require("ace/mode/yql"); var entityMap = { "&": "&", "<": "<", ">": ">", '"': '"', "'": ''', "/": '/' }; String.prototype.capitalize = function() { return this.charAt(0).toUpperCase() + this.slice(1); } String.prototype.escapeHtml = function() { return String(this).replace(/[&<>"'\/]/g, function (s) { return entityMap[s]; }); } var printAst = false; var printExpr = false; var traceOpt = false; var outputTable = (YQL_TYPE == "file") ? "Output" : "YqlOutput_" + Math.random().toString(36).substring(2, 7); var yqlEditor = ace.edit("yql-editor"); yqlEditor.getSession().setMode("ace/mode/yql"); yqlEditor.setTheme("ace/theme/tomorrow"); yqlEditor.setValue("(\n" + "# read data from Input table\n" + "(let mr_source (DataSource 'yt 'plato))\n" + "(let x (Read! world mr_source\n" + " (Key '('table (String 'Input)))\n" + " '('key 'subkey 'value) '()))\n" + "(let world (Left! x))\n" + "(let table1 (Right! x))\n" + "\n" + "# filter keys less than 100\n" + "(let tresh (Int32 '100))\n" + "(let table1low (FlatMap table1 (lambda '(item) (block '(\n" + " (let intValueOpt (FromString (Member item 'key) 'Int32))\n" + " (let ret (FlatMap intValueOpt (lambda '(item2) (block '(\n" + " (return (ListIf (< item2 tresh) item))\n" + " )))))\n" + " (return ret)\n" + ")))))\n" + "\n" + "# write table1low to " + outputTable + " table\n" + "(let mr_sink (DataSink 'yt 'plato))\n" + "(let world (Write! world mr_sink\n" + " (Key '('table (String '" + outputTable + ")))\n" + " table1low '('('mode 'append))))\n" + "\n" + "# write table1low to result sink\n" + "(let res_sink (DataSink 'result))\n" + "(let world (Write! world res_sink\n" + " (Key)\n" + " table1low '()))\n" + "\n" + "# finish\n" + "(let world (Commit! world mr_sink))\n" + "(let world (Commit! world res_sink))\n" + "(return world)\n" + ")" ); yqlEditor.gotoLine(1); var sqlEditor = ace.edit("sql-editor"); sqlEditor.getSession().setMode("ace/mode/sql"); sqlEditor.setTheme("ace/theme/tomorrow"); sqlEditor.setValue("USE plato;\n" + "\n" + "INSERT INTO " + outputTable + "\n" + "SELECT\n" + " key as key,\n" + " \"\" as subkey,\n" + " \"value:\" || value as value\n" + "FROM Input\n" + "WHERE key < \"100\"\n" + "ORDER BY key;"); sqlEditor.gotoLine(1); var tableInputEditor = ace.edit("table-input-editor"); tableInputEditor.getSession().setMode("ace/mode/sql"); tableInputEditor.setTheme("ace/theme/tomorrow"); tableInputEditor.setValue("" + "{\"key\"=\"023\";\"subkey\"=\"3\";\"value\"=\"aaa\"};\n" + "{\"key\"=\"037\";\"subkey\"=\"5\";\"value\"=\"ddd\"};\n" + "{\"key\"=\"075\";\"subkey\"=\"1\";\"value\"=\"abc\"};\n" + "{\"key\"=\"150\";\"subkey\"=\"1\";\"value\"=\"aaa\"};\n" + "{\"key\"=\"150\";\"subkey\"=\"3\";\"value\"=\"iii\"};\n" + "{\"key\"=\"150\";\"subkey\"=\"8\";\"value\"=\"zzz\"};\n" + "{\"key\"=\"200\";\"subkey\"=\"7\";\"value\"=\"qqq\"};\n" + "{\"key\"=\"527\";\"subkey\"=\"4\";\"value\"=\"bbb\"};\n" + "{\"key\"=\"761\";\"subkey\"=\"6\";\"value\"=\"ccc\"};\n" + "{\"key\"=\"911\";\"subkey\"=\"2\";\"value\"=\"kkk\"};\n" ); tableInputEditor.gotoLine(1); var tableAttrEditor = ace.edit("table-attr-editor"); tableAttrEditor.setTheme("ace/theme/tomorrow"); tableAttrEditor.setValue("{\"_yql_row_spec\"={\n" + "\t\"Type\"=[\"StructType\";[\n" + "\t\t[\"key\";[\"DataType\";\"String\"]];\n" + "\t\t[\"subkey\";[\"DataType\";\"String\"]];\n" + "\t\t[\"value\";[\"DataType\";\"String\"]]\n" + "\t]];\n" + "\t\"SortDirections\"=[1;1;];\n" + "\t\"SortedBy\"=[\"key\";\"subkey\";];\n" + "\t\"SortedByTypes\"=[[\"DataType\";\"String\";];[\"DataType\";\"String\";];];\n" + "\t\"SortMembers\"=[\"key\";\"subkey\";];\n" + "}}\n" ); tableAttrEditor.gotoLine(1); var paramsEditor = ace.edit("params-editor"); paramsEditor.setTheme("ace/theme/tomorrow"); paramsEditor.setValue("{\"$foo\"={Data=\"bar\"}}\n"); paramsEditor.gotoLine(1); var exprEditor = ace.edit("expr-editor"); exprEditor.getSession().setMode("ace/mode/yql"); exprEditor.setTheme("ace/theme/tomorrow"); exprEditor.setOptions({ readOnly: true, highlightActiveLine: false, highlightGutterLine: false }) function showOutput(output) { var headers = "" + $.map(output.headers, function(header) { return "" + header + ""; }).join("") + ""; var rows = $.map(output.rows, function(row) { var cells = $.map(row, function(cell) { return "" + cell + ""; }).join(""); return "" + cells + ""; }).join(""); var table = "" + "" + headers + "" + "" + rows + "" + "
"; $("#output").html(table); } function showResults(results) { $("#results").html("
" + results.escapeHtml() + "
"); } function showOptTrace(optTrace) { $("#opt-trace") .html("
" + optTrace.escapeHtml() + "
") .show(); } function showExpr(expr) { exprEditor.setValue(expr); exprEditor.gotoLine(1); $("#expr-editor").show(); } function showLocation(location) { var link = "" + location + ""; var $success = $("#status-success"); $success.find(".message").html(link); $success.show(); } function showStatus(success, text) { var $status = success ? $("#status-success") : $("#status-fail"); $status.find(".message").html(text + (success ? " was successful" : " failed")); $status.show(); if (window.statusTimeout !== undefined) { clearTimeout(window.statusTimeout); } window.statusTimeout = setTimeout(function() { $status.hide(); }, 3000); } function showIssues(issueHint, issues, lang) { if (issues.length == 0) return; var $issues = $(issueHint); var issuesHtml = ""; $issues.find(".message").html(issuesHtml); $issues.show(); if (lang !== undefined) { var shownIssues = []; for (var i in issues) { if (!issues[i]) continue; var s = issues[i]; while (s[0] == ">") { s = s.substring(1); } var issue = s.split(':'); shownIssues.push({ row: (parseInt(issue[0]) - 1), column: parseInt(issue[1]), type: "issue", text: issue.slice(2).join(':').trim() }); } var editor = (lang === "yql") ? yqlEditor : sqlEditor; editor.getSession().setAnnotations(shownIssues); } } function showSql(sql) { sqlEditor.setValue(sql); sqlEditor.gotoLine(1); sqlEditor.show(); } function showAst(root) { var id = 0; function addNode(g, p, n) { n.id = id++; var options = { label: n.content }; if (n.type == "list") options["class"] = "list"; g.setNode(n.id, options); if (p != null) { g.setEdge(p.id, n.id, { label: "" }); } if (n.type == "list") { for (var c in n.children) { addNode(g, n, n.children[c]); } } } $("#graph").show(); // Create a new directed graph var g = new dagreD3.graphlib.Graph().setGraph({}); addNode(g, null, root); // Set some general styles g.nodes().forEach(function(v) { var node = g.node(v); node.rx = node.ry = 5; }); var svg = d3.select("svg"), inner = svg.select("g"); // Set up zoom support var zoom = d3.behavior.zoom().on("zoom", function() { inner.attr("transform", "translate(" + d3.event.translate + ")" + "scale(" + d3.event.scale + ")"); }); svg.call(zoom); // Create the renderer var render = new dagreD3.render(); // Run the renderer. This is what draws the final graph. render(inner, g); // Center the graph var initialScale = 0.75; zoom .translate([(svg.attr("width") - g.graph().width * initialScale) / 2, 20]) .scale(initialScale) .event(svg); svg.attr('height', 400); svg.attr('width', screen.width); } function clearView() { yqlEditor.getSession().clearAnnotations(); sqlEditor.getSession().clearAnnotations(); tableInputEditor.getSession().clearAnnotations(); tableAttrEditor.getSession().clearAnnotations(); exprEditor.setValue(""); $("#expr-editor").hide(); $("#opt-trace").html("").hide(); $("#graph").hide(); $("#errors").hide(); $("#warnings").hide(); $("#infos").hide(); $("#status-success").hide(); $("#status-fail").hide(); $("#output").html(""); $("#results").html(""); } function sendProgram(e) { e.preventDefault(); clearView(); var action = $(this).attr('id'); var url = "/api/yql/" + action; var params = []; if (printAst) params.push("printAst=true"); if (printExpr) params.push("printExpr=true"); if (traceOpt) params.push("traceOpt=true"); if (params.length > 0) { url += "?" + params.join("&"); } var program; var lang = $("#editor-tabs li.active a").html().toLowerCase(); if (lang == "yql") { program = yqlEditor.getValue(); } else if (lang == "sql") { program = sqlEditor.getSelectedText(); if (!program) { program = sqlEditor.getValue(); } } else { showIssues("#errors", "Unknow program language: " + lang); } var tableInput = tableInputEditor.getValue(); var tableAttr = tableAttrEditor.getValue(); var parameters = paramsEditor.getValue(); $.ajax({ url: url, timeout: 60 * 60 * 1000, // 1 hour dataType: "json", type: "POST", jsonp: false, data: JSON.stringify({ program: program, tableInput: tableInput, tableAttr: tableAttr, lang: lang, parameters: parameters }) }) .always(function(response) { if (response.status >= 400) { var r = JSON.parse(response.responseText); showIssues("#errors", r.errors, lang); } else { if ("responseJSON" in response) response = response.responseJSON; if ("sql" in response) showSql(response.sql); if ("ast" in response) showAst(response.ast); if ("expr" in response) showExpr(response.expr); if ("output" in response && "headers" in response.output && "rows" in response.output) { showOutput(response.output); } if ("results" in response) showResults(response.results); if ("opttrace" in response) showOptTrace(response.opttrace); if ("location" in response) { showLocation(response.location); return; } if ("errors" in response) { showIssues("#errors", response.errors, lang); } if ("warnings" in response) { showIssues("#warnings", response.warnings, lang); } if ("infos" in response) { showIssues("#infos", response.infos, lang); } showStatus(response.succeeded, action.capitalize()); } }); } $(function() { $('#paste').click(sendProgram); $('#parse').click(sendProgram); $('#compile').click(sendProgram); $('#optimize').click(sendProgram); $('#validate').click(sendProgram); $('#peephole').click(sendProgram); $('#lineage').click(sendProgram); $('#run').click(sendProgram); $('#format').click(sendProgram); $("#alerts .close").click(function() { $(this).parent().hide(); }); $("#show-ast").click(function(e) { e.preventDefault(); var $li = $(this).parent(); $li.toggleClass("active"); printAst = $li.hasClass("active"); }); $("#show-expr").click(function(e) { e.preventDefault(); var $li = $(this).parent(); $li.toggleClass("active"); printExpr = $li.hasClass("active"); }); $("#trace-opt").click(function(e) { e.preventDefault(); var $li = $(this).parent(); $li.toggleClass("active"); traceOpt = $li.hasClass("active"); }); });