app.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. require("ace/mode/yql");
  2. var entityMap = {
  3. "&": "&",
  4. "<": "&lt;",
  5. ">": "&gt;",
  6. '"': '&quot;',
  7. "'": '&#39;',
  8. "/": '&#x2F;'
  9. };
  10. String.prototype.capitalize = function() {
  11. return this.charAt(0).toUpperCase() + this.slice(1);
  12. }
  13. String.prototype.escapeHtml = function() {
  14. return String(this).replace(/[&<>"'\/]/g, function (s) {
  15. return entityMap[s];
  16. });
  17. }
  18. var printAst = false;
  19. var printExpr = false;
  20. var traceOpt = false;
  21. var outputTable = (YQL_TYPE == "file")
  22. ? "Output"
  23. : "YqlOutput_" + Math.random().toString(36).substring(2, 7);
  24. var yqlEditor = ace.edit("yql-editor");
  25. yqlEditor.getSession().setMode("ace/mode/yql");
  26. yqlEditor.setTheme("ace/theme/tomorrow");
  27. yqlEditor.setValue("(\n"
  28. + "# read data from Input table\n"
  29. + "(let mr_source (DataSource 'yt 'plato))\n"
  30. + "(let x (Read! world mr_source\n"
  31. + " (Key '('table (String 'Input)))\n"
  32. + " '('key 'subkey 'value) '()))\n"
  33. + "(let world (Left! x))\n"
  34. + "(let table1 (Right! x))\n"
  35. + "\n"
  36. + "# filter keys less than 100\n"
  37. + "(let tresh (Int32 '100))\n"
  38. + "(let table1low (FlatMap table1 (lambda '(item) (block '(\n"
  39. + " (let intValueOpt (FromString (Member item 'key) 'Int32))\n"
  40. + " (let ret (FlatMap intValueOpt (lambda '(item2) (block '(\n"
  41. + " (return (ListIf (< item2 tresh) item))\n"
  42. + " )))))\n"
  43. + " (return ret)\n"
  44. + ")))))\n"
  45. + "\n"
  46. + "# write table1low to " + outputTable + " table\n"
  47. + "(let mr_sink (DataSink 'yt 'plato))\n"
  48. + "(let world (Write! world mr_sink\n"
  49. + " (Key '('table (String '" + outputTable + ")))\n"
  50. + " table1low '('('mode 'append))))\n"
  51. + "\n"
  52. + "# write table1low to result sink\n"
  53. + "(let res_sink (DataSink 'result))\n"
  54. + "(let world (Write! world res_sink\n"
  55. + " (Key)\n"
  56. + " table1low '()))\n"
  57. + "\n"
  58. + "# finish\n"
  59. + "(let world (Commit! world mr_sink))\n"
  60. + "(let world (Commit! world res_sink))\n"
  61. + "(return world)\n"
  62. + ")"
  63. );
  64. yqlEditor.gotoLine(1);
  65. var sqlEditor = ace.edit("sql-editor");
  66. sqlEditor.getSession().setMode("ace/mode/sql");
  67. sqlEditor.setTheme("ace/theme/tomorrow");
  68. sqlEditor.setValue("USE plato;\n"
  69. + "\n"
  70. + "INSERT INTO " + outputTable + "\n"
  71. + "SELECT\n"
  72. + " key as key,\n"
  73. + " \"\" as subkey,\n"
  74. + " \"value:\" || value as value\n"
  75. + "FROM Input\n"
  76. + "WHERE key < \"100\"\n"
  77. + "ORDER BY key;");
  78. sqlEditor.gotoLine(1);
  79. var tableInputEditor = ace.edit("table-input-editor");
  80. tableInputEditor.getSession().setMode("ace/mode/sql");
  81. tableInputEditor.setTheme("ace/theme/tomorrow");
  82. tableInputEditor.setValue(""
  83. + "{\"key\"=\"023\";\"subkey\"=\"3\";\"value\"=\"aaa\"};\n"
  84. + "{\"key\"=\"037\";\"subkey\"=\"5\";\"value\"=\"ddd\"};\n"
  85. + "{\"key\"=\"075\";\"subkey\"=\"1\";\"value\"=\"abc\"};\n"
  86. + "{\"key\"=\"150\";\"subkey\"=\"1\";\"value\"=\"aaa\"};\n"
  87. + "{\"key\"=\"150\";\"subkey\"=\"3\";\"value\"=\"iii\"};\n"
  88. + "{\"key\"=\"150\";\"subkey\"=\"8\";\"value\"=\"zzz\"};\n"
  89. + "{\"key\"=\"200\";\"subkey\"=\"7\";\"value\"=\"qqq\"};\n"
  90. + "{\"key\"=\"527\";\"subkey\"=\"4\";\"value\"=\"bbb\"};\n"
  91. + "{\"key\"=\"761\";\"subkey\"=\"6\";\"value\"=\"ccc\"};\n"
  92. + "{\"key\"=\"911\";\"subkey\"=\"2\";\"value\"=\"kkk\"};\n"
  93. );
  94. tableInputEditor.gotoLine(1);
  95. var tableAttrEditor = ace.edit("table-attr-editor");
  96. tableAttrEditor.setTheme("ace/theme/tomorrow");
  97. tableAttrEditor.setValue("{\"_yql_row_spec\"={\n"
  98. + "\t\"Type\"=[\"StructType\";[\n"
  99. + "\t\t[\"key\";[\"DataType\";\"String\"]];\n"
  100. + "\t\t[\"subkey\";[\"DataType\";\"String\"]];\n"
  101. + "\t\t[\"value\";[\"DataType\";\"String\"]]\n"
  102. + "\t]];\n"
  103. + "\t\"SortDirections\"=[1;1;];\n"
  104. + "\t\"SortedBy\"=[\"key\";\"subkey\";];\n"
  105. + "\t\"SortedByTypes\"=[[\"DataType\";\"String\";];[\"DataType\";\"String\";];];\n"
  106. + "\t\"SortMembers\"=[\"key\";\"subkey\";];\n"
  107. + "}}\n"
  108. );
  109. tableAttrEditor.gotoLine(1);
  110. var paramsEditor = ace.edit("params-editor");
  111. paramsEditor.setTheme("ace/theme/tomorrow");
  112. paramsEditor.setValue("{\"$foo\"={Data=\"bar\"}}\n");
  113. paramsEditor.gotoLine(1);
  114. var exprEditor = ace.edit("expr-editor");
  115. exprEditor.getSession().setMode("ace/mode/yql");
  116. exprEditor.setTheme("ace/theme/tomorrow");
  117. exprEditor.setOptions({
  118. readOnly: true,
  119. highlightActiveLine: false,
  120. highlightGutterLine: false
  121. })
  122. function showOutput(output) {
  123. var headers = "<tr>" + $.map(output.headers, function(header) {
  124. return "<th>" + header + "</th>";
  125. }).join("") + "</tr>";
  126. var rows = $.map(output.rows, function(row) {
  127. var cells = $.map(row, function(cell) {
  128. return "<td>" + cell + "</td>";
  129. }).join("");
  130. return "<tr>" + cells + "</tr>";
  131. }).join("");
  132. var table =
  133. "<table class='table table-condensed'>" +
  134. "<thead>" + headers + "</thead>" +
  135. "<tbody>" + rows + "<tbody>" +
  136. "</table>";
  137. $("#output").html(table);
  138. }
  139. function showResults(results) {
  140. $("#results").html("<pre>" + results.escapeHtml() + "</pre>");
  141. }
  142. function showOptTrace(optTrace) {
  143. $("#opt-trace")
  144. .html("<pre>" + optTrace.escapeHtml() + "</pre>")
  145. .show();
  146. }
  147. function showExpr(expr) {
  148. exprEditor.setValue(expr);
  149. exprEditor.gotoLine(1);
  150. $("#expr-editor").show();
  151. }
  152. function showLocation(location) {
  153. var link = "<a href='" + location + "' target='_blank'>" + location + "</a>";
  154. var $success = $("#status-success");
  155. $success.find(".message").html(link);
  156. $success.show();
  157. }
  158. function showStatus(success, text) {
  159. var $status = success ? $("#status-success") : $("#status-fail");
  160. $status.find(".message").html(text + (success ? " was successful" : " failed"));
  161. $status.show();
  162. if (window.statusTimeout !== undefined) {
  163. clearTimeout(window.statusTimeout);
  164. }
  165. window.statusTimeout = setTimeout(function() {
  166. $status.hide();
  167. }, 3000);
  168. }
  169. function showIssues(issueHint, issues, lang) {
  170. if (issues.length == 0) return;
  171. var $issues = $(issueHint);
  172. var issuesHtml = "<ul>" + $.map(issues, function(e) {
  173. return "<li><pre>" + e.escapeHtml() + "</pre></li>";
  174. }).join('') + "</ul>";
  175. $issues.find(".message").html(issuesHtml);
  176. $issues.show();
  177. if (lang !== undefined) {
  178. var shownIssues = [];
  179. for (var i in issues) {
  180. if (!issues[i]) continue;
  181. var s = issues[i];
  182. while (s[0] == ">") {
  183. s = s.substring(1);
  184. }
  185. var issue = s.split(':');
  186. shownIssues.push({
  187. row: (parseInt(issue[0]) - 1),
  188. column: parseInt(issue[1]),
  189. type: "issue",
  190. text: issue.slice(2).join(':').trim()
  191. });
  192. }
  193. var editor = (lang === "yql") ? yqlEditor : sqlEditor;
  194. editor.getSession().setAnnotations(shownIssues);
  195. }
  196. }
  197. function showSql(sql) {
  198. sqlEditor.setValue(sql);
  199. sqlEditor.gotoLine(1);
  200. sqlEditor.show();
  201. }
  202. function showAst(root) {
  203. var id = 0;
  204. function addNode(g, p, n) {
  205. n.id = id++;
  206. var options = { label: n.content };
  207. if (n.type == "list") options["class"] = "list";
  208. g.setNode(n.id, options);
  209. if (p != null) {
  210. g.setEdge(p.id, n.id, { label: "" });
  211. }
  212. if (n.type == "list") {
  213. for (var c in n.children) {
  214. addNode(g, n, n.children[c]);
  215. }
  216. }
  217. }
  218. $("#graph").show();
  219. // Create a new directed graph
  220. var g = new dagreD3.graphlib.Graph().setGraph({});
  221. addNode(g, null, root);
  222. // Set some general styles
  223. g.nodes().forEach(function(v) {
  224. var node = g.node(v);
  225. node.rx = node.ry = 5;
  226. });
  227. var svg = d3.select("svg"),
  228. inner = svg.select("g");
  229. // Set up zoom support
  230. var zoom = d3.behavior.zoom().on("zoom", function() {
  231. inner.attr("transform", "translate(" + d3.event.translate + ")" +
  232. "scale(" + d3.event.scale + ")");
  233. });
  234. svg.call(zoom);
  235. // Create the renderer
  236. var render = new dagreD3.render();
  237. // Run the renderer. This is what draws the final graph.
  238. render(inner, g);
  239. // Center the graph
  240. var initialScale = 0.75;
  241. zoom
  242. .translate([(svg.attr("width") - g.graph().width * initialScale) / 2, 20])
  243. .scale(initialScale)
  244. .event(svg);
  245. svg.attr('height', 400);
  246. svg.attr('width', screen.width);
  247. }
  248. function clearView() {
  249. yqlEditor.getSession().clearAnnotations();
  250. sqlEditor.getSession().clearAnnotations();
  251. tableInputEditor.getSession().clearAnnotations();
  252. tableAttrEditor.getSession().clearAnnotations();
  253. exprEditor.setValue("");
  254. $("#expr-editor").hide();
  255. $("#opt-trace").html("").hide();
  256. $("#graph").hide();
  257. $("#errors").hide();
  258. $("#warnings").hide();
  259. $("#infos").hide();
  260. $("#status-success").hide();
  261. $("#status-fail").hide();
  262. $("#output").html("");
  263. $("#results").html("");
  264. }
  265. function sendProgram(e) {
  266. e.preventDefault();
  267. clearView();
  268. var action = $(this).attr('id');
  269. var url = "/api/yql/" + action;
  270. var params = [];
  271. if (printAst) params.push("printAst=true");
  272. if (printExpr) params.push("printExpr=true");
  273. if (traceOpt) params.push("traceOpt=true");
  274. if (params.length > 0) {
  275. url += "?" + params.join("&");
  276. }
  277. var program;
  278. var lang = $("#editor-tabs li.active a").html().toLowerCase();
  279. if (lang == "yql") {
  280. program = yqlEditor.getValue();
  281. } else if (lang == "sql") {
  282. program = sqlEditor.getSelectedText();
  283. if (!program) {
  284. program = sqlEditor.getValue();
  285. }
  286. } else {
  287. showIssues("#errors", "Unknow program language: " + lang);
  288. }
  289. var tableInput = tableInputEditor.getValue();
  290. var tableAttr = tableAttrEditor.getValue();
  291. var parameters = paramsEditor.getValue();
  292. $.ajax({
  293. url: url,
  294. timeout: 60 * 60 * 1000, // 1 hour
  295. dataType: "json",
  296. type: "POST",
  297. jsonp: false,
  298. data: JSON.stringify({
  299. program: program,
  300. tableInput: tableInput,
  301. tableAttr: tableAttr,
  302. lang: lang,
  303. parameters: parameters
  304. })
  305. })
  306. .always(function(response) {
  307. if (response.status >= 400) {
  308. var r = JSON.parse(response.responseText);
  309. showIssues("#errors", r.errors, lang);
  310. } else {
  311. if ("responseJSON" in response) response = response.responseJSON;
  312. if ("sql" in response) showSql(response.sql);
  313. if ("ast" in response) showAst(response.ast);
  314. if ("expr" in response) showExpr(response.expr);
  315. if ("output" in response && "headers" in response.output && "rows" in response.output) {
  316. showOutput(response.output);
  317. }
  318. if ("results" in response) showResults(response.results);
  319. if ("opttrace" in response) showOptTrace(response.opttrace);
  320. if ("location" in response) {
  321. showLocation(response.location);
  322. return;
  323. }
  324. if ("errors" in response) {
  325. showIssues("#errors", response.errors, lang);
  326. }
  327. if ("warnings" in response) {
  328. showIssues("#warnings", response.warnings, lang);
  329. }
  330. if ("infos" in response) {
  331. showIssues("#infos", response.infos, lang);
  332. }
  333. showStatus(response.succeeded, action.capitalize());
  334. }
  335. });
  336. }
  337. $(function() {
  338. $('#paste').click(sendProgram);
  339. $('#parse').click(sendProgram);
  340. $('#compile').click(sendProgram);
  341. $('#optimize').click(sendProgram);
  342. $('#validate').click(sendProgram);
  343. $('#peephole').click(sendProgram);
  344. $('#lineage').click(sendProgram);
  345. $('#run').click(sendProgram);
  346. $('#format').click(sendProgram);
  347. $("#alerts .close").click(function() {
  348. $(this).parent().hide();
  349. });
  350. $("#show-ast").click(function(e) {
  351. e.preventDefault();
  352. var $li = $(this).parent();
  353. $li.toggleClass("active");
  354. printAst = $li.hasClass("active");
  355. });
  356. $("#show-expr").click(function(e) {
  357. e.preventDefault();
  358. var $li = $(this).parent();
  359. $li.toggleClass("active");
  360. printExpr = $li.hasClass("active");
  361. });
  362. $("#trace-opt").click(function(e) {
  363. e.preventDefault();
  364. var $li = $(this).parent();
  365. $li.toggleClass("active");
  366. traceOpt = $li.hasClass("active");
  367. });
  368. });