@graphenedata/cli 0.0.6 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/cli.js CHANGED
@@ -150,15 +150,17 @@ function setConfig(cfg) {
150
150
  else if (cfg.snowflake) dialect = "snowflake";
151
151
  else if (cfg.duckdb) dialect = "duckdb";
152
152
  Object.keys(config).forEach((key) => delete config[key]);
153
- Object.assign(config, cfg, { dialect });
153
+ Object.assign(config, cfg);
154
+ config.dialect = dialect;
155
+ config.root ||= process.cwd();
156
+ config.ignoredFiles ||= ["agents.md", "claude.md"];
154
157
  }
155
158
  function loadConfig(dir) {
156
159
  if (config.root) return;
157
160
  let packageJsonObject = {};
158
161
  try {
159
162
  let txt2 = fs.readFileSync(path.join(dir, "package.json"), "utf8");
160
- let all = JSON.parse(txt2);
161
- packageJsonObject = all.graphene || {};
163
+ packageJsonObject = JSON.parse(txt2).graphene || {};
162
164
  } catch {
163
165
  console.warn("No package.json found in current directory");
164
166
  }
@@ -172,7 +174,7 @@ var init_config = __esm({
172
174
  }
173
175
  });
174
176
 
175
- // ../lang/functions.ts
177
+ // ../lang/functionDefs.ts
176
178
  import { DUCKDB_DIALECT_FUNCTIONS, GlobalNameSpace, DialectNameSpace, getDialect } from "@graphenedata/malloy";
177
179
  function findOverloads(name, dialect) {
178
180
  if (!dialectNamespaces.has(dialect)) {
@@ -183,8 +185,8 @@ function findOverloads(name, dialect) {
183
185
  return res?.entry ? res.entry.overloads : [];
184
186
  }
185
187
  var globalNamespace, dialectNamespaces, BIGQUERY_DIALECT_FUNCTIONS;
186
- var init_functions = __esm({
187
- "../lang/functions.ts"() {
188
+ var init_functionDefs = __esm({
189
+ "../lang/functionDefs.ts"() {
188
190
  "use strict";
189
191
  globalNamespace = new GlobalNameSpace();
190
192
  dialectNamespaces = /* @__PURE__ */ new Map();
@@ -254,8 +256,9 @@ var init_functions = __esm({
254
256
  impl: { function: "TIMESTAMP_DIFF" }
255
257
  },
256
258
  "date_trunc": {
257
- takes: { "date": "timestamp", "unit": { sql_native: "kw" } },
258
- returns: "timestamp",
259
+ generic: { "T": ["date", "timestamp"] },
260
+ takes: { "date": { generic: "T" }, "unit": { sql_native: "kw" } },
261
+ returns: { generic: "T" },
259
262
  impl: { sql: "DATE_TRUNC(${date}, ${unit})" }
260
263
  },
261
264
  "current_date": {
@@ -315,6 +318,112 @@ var init_functions = __esm({
315
318
  }
316
319
  });
317
320
 
321
+ // ../lang/functions.ts
322
+ function analyzeFunctionCall(expr, scope) {
323
+ let rawName = txt(expr.getChild("Identifier")).toLowerCase();
324
+ let argNodes = expr.getChildren("Expression");
325
+ let name = rawName;
326
+ let overload = findOverloads(name, config.dialect).find((o) => {
327
+ return o.params.length == argNodes.length || !!o.params.find((p) => p.isVariadic);
328
+ });
329
+ let args = argNodes.map((node, idx) => {
330
+ let firstType = overload?.params[idx]?.allowedTypes[0];
331
+ if (firstType?.type === "sql native" && firstType?.rawType === "kw") {
332
+ return { node: "genericSQLExpr", kids: { args: [] }, type: "sql native", src: [txt(node)], isAgg: false };
333
+ } else {
334
+ let argExpr = analyzeExpression(node, scope);
335
+ let allowed = overload?.params[idx]?.allowedTypes.map((at) => at.type);
336
+ if (allowed) checkTypes(argExpr, allowed, node);
337
+ return argExpr;
338
+ }
339
+ });
340
+ let type = overload?.returnType.type;
341
+ if (type == "generic") type = args[0]?.type || "string";
342
+ if (type && !isSupportedType(type)) {
343
+ return diag(expr, `Unsupported function return type ${type} from function ${name}`, errExpr);
344
+ }
345
+ let structPaths = /* @__PURE__ */ new Set();
346
+ args.forEach((a) => walkExpression(a, (e) => {
347
+ if (e.node != "field") return;
348
+ structPaths.add(e.path.slice(0, -1).join(".") || scope.table.name);
349
+ }));
350
+ let ret;
351
+ let percentileMatch = /^p(\d+)$/.exec(rawName);
352
+ if (["count", "min", "max", "avg", "sum"].includes(name.toLowerCase())) {
353
+ let type2 = "number", typeDef;
354
+ if (["min", "max", "avg"].includes(name.toLowerCase())) {
355
+ type2 = args[0].type;
356
+ typeDef = args[0].typeDef;
357
+ }
358
+ ret = { node: "aggregate", function: name, e: args[0], type: type2, typeDef, isAgg: true };
359
+ } else if (percentileMatch) {
360
+ ret = analyzePercentile(expr, scope, percentileMatch[1], argNodes);
361
+ } else if (overload && type) {
362
+ ret = {
363
+ node: "function_call",
364
+ type,
365
+ name,
366
+ overload,
367
+ expressionType: overload.returnType.expressionType || "scalar",
368
+ kids: { args },
369
+ isAgg: overload.returnType.expressionType == "aggregate" || args.some((a) => a.isAgg)
370
+ };
371
+ } else {
372
+ return diag(expr, `Unknown function: ${name}`, errExpr);
373
+ }
374
+ if (structPaths.size > 1 && (ret.node == "aggregate" || ret.expressionType == "aggregate")) {
375
+ return diag(expr, "Graphene only supports a single table within aggregates. This one has: " + Array.from(structPaths).join(", "), errExpr);
376
+ }
377
+ let foriegnPaths = Array.from(structPaths).filter((p) => p != scope.table.name);
378
+ if (foriegnPaths.length > 0) ret.structPath = foriegnPaths[0].split(".");
379
+ return ret;
380
+ }
381
+ function isSupportedType(value) {
382
+ let supported = ["string", "number", "boolean", "date", "timestamp", "json", "sql native", "error", "array", "record", "null", "generic", "interval"];
383
+ return supported.includes(value);
384
+ }
385
+ function analyzePercentile(callNode, scope, digits, argNodes) {
386
+ let frac = Number(`0.${digits}`);
387
+ if (Number(digits) == 100) return diag(callNode, "p100 is not allowed", errExpr);
388
+ if (Number(digits) == 0) return diag(callNode, "p0 is not allowed", errExpr);
389
+ if (config.dialect == "bigquery" && frac > 0.99) return diag(callNode, "BigQuery only supports up to p99", errExpr);
390
+ let valueExpr = analyzeExpression(argNodes[0], scope);
391
+ checkTypes(valueExpr, ["number"], argNodes[0]);
392
+ let src;
393
+ switch (config.dialect) {
394
+ case "duckdb":
395
+ src = ["quantile_cont(", `, ${frac})`];
396
+ break;
397
+ case "bigquery": {
398
+ src = ["approx_quantiles(", `, 100)[OFFSET(${Math.round(frac * 10)})]`];
399
+ break;
400
+ }
401
+ case "snowflake":
402
+ src = [`PERCENTILE_CONT(${frac}) WITHIN GROUP (ORDER BY `, ")"];
403
+ break;
404
+ default:
405
+ return diag(callNode, `Percentile functions are not supported for dialect ${config.dialect}`, errExpr);
406
+ }
407
+ return {
408
+ node: "genericSQLExpr",
409
+ kids: { args: [valueExpr] },
410
+ src,
411
+ type: "number",
412
+ isAgg: true
413
+ };
414
+ }
415
+ var errExpr;
416
+ var init_functions = __esm({
417
+ "../lang/functions.ts"() {
418
+ "use strict";
419
+ init_config();
420
+ init_functionDefs();
421
+ init_util();
422
+ init_analyze();
423
+ errExpr = { node: "error", type: "error" };
424
+ }
425
+ });
426
+
318
427
  // ../lang/temporalLiterals.ts
319
428
  function parseTemporalLiteral(value, expected) {
320
429
  let raw = (value ?? "").trim();
@@ -598,9 +707,9 @@ function findTables(fi) {
598
707
  fi.tables = [];
599
708
  let nodes = tn.getChildren("TableStatement").concat(tn.getChildren("ViewStatement"));
600
709
  for (let syntaxNode of nodes) {
601
- let name = txt(syntaxNode.getChild("Identifier"));
710
+ let name = txt(syntaxNode.getChild("Ref"));
602
711
  if (Object.values(FILE_MAP).find((f) => f.tables.find((t) => t.name == name))) {
603
- diag(syntaxNode.getChild("Identifier"), `Table "${name}" is already defined`);
712
+ diag(syntaxNode.getChild("Ref"), `Table "${name}" is already defined`);
604
713
  }
605
714
  let table2 = makeTable(name, syntaxNode.getChild("QueryStatement") ? "query_source" : "table");
606
715
  table2.metadata = extractLeadingMetadata(syntaxNode);
@@ -622,12 +731,11 @@ function addColumnField(table2, node) {
622
731
  table2.primaryKey = name;
623
732
  }
624
733
  let type = convertDataType(txt(node.getChild("DataType")));
625
- if (!type) diag(node, `Unsupported data type: ${txt(node.getChild("DataType"))}`);
626
- let field = { name, type, metadata: extractLeadingMetadata(node) };
627
- return addFieldToTable(table2, field, node);
734
+ if (!type) return diag(node, `Unsupported data type: ${txt(node.getChild("DataType"))}`);
735
+ addFieldToTable(table2, { name, type, metadata: extractLeadingMetadata(node) }, node);
628
736
  }
629
737
  function addJoinField(table2, node) {
630
- let nameNode = node.getChild("Alias") || node.getChild("Identifier");
738
+ let nameNode = node.getChild("Alias") || node.getChild("Ref").getChildren("Identifier").pop();
631
739
  return addFieldToTable(table2, { name: txt(nameNode) }, node);
632
740
  }
633
741
  function addComputedField(table2, node) {
@@ -636,19 +744,17 @@ function addComputedField(table2, node) {
636
744
  }
637
745
  function addFieldToTable(table2, field, node) {
638
746
  if (table2.fields.find((f) => f.name == field.name)) {
639
- diag(node, `Table already has a field called "${field.name}"`);
640
- return null;
747
+ return diag(node, `Table already has a field called "${field.name}"`);
641
748
  }
642
749
  table2.fields.push(field);
643
750
  FIELD_NODE_MAP.set(field, node);
644
- return field;
645
751
  }
646
752
  function applyExtends(fi) {
647
753
  fi.tree.topNode.getChildren("ExtendStatement").forEach((node) => {
648
- let tableName = txt(node.getChild("Identifier"));
754
+ let tableName = txt(node.getChild("Ref"));
649
755
  let target = lookupTable(tableName, node);
650
756
  if (!target) {
651
- return diag(node.getChild("Identifier") || node, `Cannot extend unknown table "${tableName}"`);
757
+ return diag(node.getChild("Ref") || node, `Cannot extend unknown table "${tableName}"`);
652
758
  }
653
759
  node.getChildren("JoinDef").forEach((jn) => addJoinField(target, jn));
654
760
  node.getChildren("ComputedDef").forEach((cn) => addComputedField(target, cn));
@@ -675,14 +781,14 @@ function analyzeField(field, table2) {
675
781
  analysisQueue.add(field);
676
782
  if (node.name == "JoinDef") {
677
783
  field = field;
678
- let target = lookupTable(txt(node.getChild("Identifier")), node);
784
+ let target = lookupTable(txt(node.getChild("Ref")), node);
679
785
  if (!target) return diag(node, "Unknown table to join");
680
786
  if (target.type == "query_source") analyzeTable(target);
681
787
  let joinTypeStr = txt(node.getChild("JoinType")).replace(/\s+/g, " ");
682
788
  let jt = { "join many": "many", "join one": "one" }[joinTypeStr];
683
789
  if (!jt) return diag(node, "Unknown join type");
684
790
  Object.assign(field, target, { name: field.name, join: jt });
685
- field.onExpression = analyzeExpression(node.getChild("Expression"), { table: table2, outputFields: [] });
791
+ field.onExpression = analyzeExpression(node.getChild("BinaryExpression"), { table: table2, outputFields: [] });
686
792
  }
687
793
  if (node.name == "ComputedDef") {
688
794
  let e = analyzeExpression(node.getChild("Expression"), { table: table2, outputFields: [] });
@@ -711,7 +817,7 @@ function analyzeQuery(queryNode) {
711
817
  TABLE_NODE_MAP.set(scope.table, froms[0].getChild("SubqueryExpression"));
712
818
  analyzeTable(scope.table);
713
819
  } else {
714
- baseTableName = txt(froms[0].getChild("Identifier"));
820
+ baseTableName = txt(froms[0].getChild("Ref"));
715
821
  scope.table = lookupTable(baseTableName, froms[0]);
716
822
  if (!scope.table) return diag(froms[0], `could not find table "${baseTableName}"`);
717
823
  NODE_ENTITY_MAP.set(froms[0], { entityType: "table", table: scope.table });
@@ -799,7 +905,7 @@ function analyzeQuery(queryNode) {
799
905
  }
800
906
  function analyzeExpression(expr, scope) {
801
907
  if (expr.type.isError) {
802
- return diag(expr, "Invalid expression", errExpr);
908
+ return diag(expr, "Invalid expression", errExpr2);
803
909
  }
804
910
  switch (expr.name) {
805
911
  case "Number":
@@ -814,7 +920,7 @@ function analyzeExpression(expr, scope) {
814
920
  return { node: "parameter", path: [txt(expr).slice(1)], type: "string" };
815
921
  case "Ref": {
816
922
  let field = lookupField(expr, scope);
817
- if (!field) return errExpr;
923
+ if (!field) return errExpr2;
818
924
  let type = field.type || "unknown";
819
925
  let typeInfo = { type };
820
926
  if (type === "date" || type === "timestamp") typeInfo.typeDef = { type };
@@ -828,9 +934,9 @@ function analyzeExpression(expr, scope) {
828
934
  let extractExprNode = expr.getChild("Expression");
829
935
  let e = analyzeExpression(extractExprNode, scope);
830
936
  checkTypes(e, ["date", "timestamp"], extractExprNode);
831
- if (!isTemporalType(e.type) || !e.typeDef) return diag(expr, "Expression must be a date or timestamp", errExpr);
937
+ if (!isTemporalType(e.type) || !e.typeDef) return diag(expr, "Expression must be a date or timestamp", errExpr2);
832
938
  let units = txt(expr.getChild("ExtractUnit")).replace(/^['"]|['"]$/g, "").toLowerCase();
833
- if (!isExtractUnit(units)) return diag(expr, "Not a valid unit to extract", errExpr);
939
+ if (!isExtractUnit(units)) return diag(expr, "Not a valid unit to extract", errExpr2);
834
940
  return { node: "extract", type: "number", units, e, isAgg: false };
835
941
  }
836
942
  case "FunctionCall":
@@ -863,6 +969,7 @@ function analyzeExpression(expr, scope) {
863
969
  checkTypes(right2, ["number"], expr.lastChild);
864
970
  }
865
971
  if (op == "<" || op == "<=" || op == ">" || op == ">=" || op == "=" || op == "!=" || op == "<>") {
972
+ if (op == "<>") op = "!=";
866
973
  ensureSameType(left2, expr.firstChild, right2, expr.lastChild);
867
974
  type = "boolean";
868
975
  }
@@ -884,7 +991,7 @@ function analyzeExpression(expr, scope) {
884
991
  if (opTxt === "not") return { node: "not", e: child, type: "boolean", isAgg: child.isAgg };
885
992
  if (opTxt === "-") return { node: "unary-", e: child, type: child.type, isAgg: child.isAgg };
886
993
  if (opTxt === "+") return { node: "()", e: child, type: child.type, isAgg: child.isAgg };
887
- return diag(expr, `Unknown unary operator: ${opTxt}`, errExpr);
994
+ return diag(expr, `Unknown unary operator: ${opTxt}`, errExpr2);
888
995
  }
889
996
  case "CaseExpression": {
890
997
  let caseValue = expr.getChild("Expression");
@@ -919,83 +1026,28 @@ function analyzeExpression(expr, scope) {
919
1026
  }
920
1027
  case "SubqueryExpression":
921
1028
  default:
922
- return diag(expr, `Unsupported expression "${expr.name}": ${txt(expr)}`, errExpr);
923
- }
924
- }
925
- function analyzeFunctionCall(expr, scope) {
926
- let name = txt(expr.getChild("Identifier")).toLowerCase();
927
- let argNodes = expr.getChildren("Expression");
928
- let overload = findOverloads(name, config.dialect).find((o) => {
929
- return o.params.length == argNodes.length || !!o.params.find((p) => p.isVariadic);
930
- });
931
- let args = argNodes.map((node, idx) => {
932
- let firstType = overload?.params[idx]?.allowedTypes[0];
933
- if (firstType?.type === "sql native" && firstType?.rawType === "kw") {
934
- return { node: "genericSQLExpr", kids: { args: [] }, type: "sql native", src: [txt(node)], isAgg: false };
935
- } else {
936
- let argExpr = analyzeExpression(node, scope);
937
- let allowed = overload?.params[idx]?.allowedTypes.map((at) => at.type);
938
- if (allowed) checkTypes(argExpr, allowed, node);
939
- return argExpr;
940
- }
941
- });
942
- let type = overload?.returnType.type;
943
- if (type == "generic") type = args[0]?.type || "string";
944
- if (type && !isSupportedType(type)) {
945
- return diag(expr, `Unsupported function return type ${type} from function ${name}`, errExpr);
946
- }
947
- let structPaths = /* @__PURE__ */ new Set();
948
- args.forEach((a) => walkExpression(a, (e) => {
949
- if (e.node != "field") return;
950
- structPaths.add(e.path.slice(0, -1).join(".") || scope.table.name);
951
- }));
952
- let ret;
953
- if (["count", "min", "max", "avg", "sum"].includes(name.toLowerCase())) {
954
- let type2 = "number", typeDef;
955
- if (["min", "max", "avg"].includes(name.toLowerCase())) {
956
- type2 = args[0].type;
957
- typeDef = args[0].typeDef;
958
- }
959
- ret = { node: "aggregate", function: name, e: args[0], type: type2, typeDef, isAgg: true };
960
- } else if (overload && type) {
961
- ret = {
962
- node: "function_call",
963
- type,
964
- name,
965
- overload,
966
- expressionType: overload.returnType.expressionType || "scalar",
967
- kids: { args },
968
- isAgg: overload.returnType.expressionType == "aggregate" || args.some((a) => a.isAgg)
969
- };
970
- } else {
971
- return diag(expr, `Unknown function: ${name}`, errExpr);
972
- }
973
- if (structPaths.size > 1 && (ret.node == "aggregate" || ret.expressionType == "aggregate")) {
974
- return diag(expr, "Graphene only supports a single table within aggregates. This one has: " + Array.from(structPaths).join(", "), errExpr);
1029
+ return diag(expr, `Unsupported expression "${expr.name}": ${txt(expr)}`, errExpr2);
975
1030
  }
976
- let foriegnPaths = Array.from(structPaths).filter((p) => p != scope.table.name);
977
- if (foriegnPaths.length > 0) ret.structPath = foriegnPaths[0].split(".");
978
- return ret;
979
1031
  }
980
1032
  function analyzeTimeExpression(op, left2, right2, node) {
981
- if (left2.type !== "date" && left2.type !== "timestamp") return diag(node, "Expected left side to be a date or timestamp", errExpr);
1033
+ if (left2.type !== "date" && left2.type !== "timestamp") return diag(node, "Expected left side to be a date or timestamp", errExpr2);
982
1034
  let units = left2.type === "timestamp" ? "second" : "day";
983
1035
  if (right2.node == "stringLiteral") {
984
1036
  units = parseTemporal(right2);
985
1037
  if (right2.node == "stringLiteral") {
986
- return diag(node, "Could not parse interval", errExpr);
1038
+ return diag(node, "Could not parse interval", errExpr2);
987
1039
  }
988
1040
  }
989
1041
  if (right2.type == "date" || right2.type == "timestamp") {
990
- if (op !== "-") return diag(node, "Only subtraction between dates is supported", errExpr);
991
- if (right2.type !== left2.type) return diag(node, `Expected right side to be a ${left2.type}`, errExpr);
1042
+ if (op !== "-") return diag(node, "Only subtraction between dates is supported", errExpr2);
1043
+ if (right2.type !== left2.type) return diag(node, `Expected right side to be a ${left2.type}`, errExpr2);
992
1044
  return { node: "timeDiff", kids: { left: left2, right: right2 }, units, type: "interval", isAgg: false };
993
1045
  }
994
1046
  if (right2.type == "interval") {
995
1047
  let typeDef = { type: left2.type };
996
1048
  return { node: "delta", kids: { base: left2, delta: right2 }, op, units, type: left2.type, typeDef, isAgg: false };
997
1049
  }
998
- return diag(node, "Expected right side to be a date or interval", errExpr);
1050
+ return diag(node, "Expected right side to be a date or interval", errExpr2);
999
1051
  }
1000
1052
  function ensureSameType(left2, leftNode, right2, rightNode) {
1001
1053
  if (left2.type === "error" || right2.type === "error") return;
@@ -1021,10 +1073,6 @@ function checkTypes(expr, expected, node) {
1021
1073
  return Object.assign(expr, { node: "numberLiteral", literal: parsed.quantity.toString(), type: "interval", intervalUnit: parsed.unit });
1022
1074
  } else diag(node, `Expected types: ${expected.join(", ")}`);
1023
1075
  }
1024
- function isSupportedType(value) {
1025
- let supported = ["string", "number", "boolean", "date", "timestamp", "json", "sql native", "error", "array", "record", "null", "generic", "interval"];
1026
- return supported.includes(value);
1027
- }
1028
1076
  function lookupField(expr, scope) {
1029
1077
  let pathNodes = expr.getChildren("Identifier");
1030
1078
  let fieldNode = pathNodes.pop();
@@ -1069,7 +1117,7 @@ function lookupTable(name, node) {
1069
1117
  }
1070
1118
  }
1071
1119
  function clearWorkspace() {
1072
- FILE_MAP = {};
1120
+ Object.keys(FILE_MAP).forEach((k) => delete FILE_MAP[k]);
1073
1121
  TABLE_NODE_MAP = /* @__PURE__ */ new WeakMap();
1074
1122
  diagnostics = [];
1075
1123
  }
@@ -1124,6 +1172,8 @@ function convertDataType(dataType) {
1124
1172
  return "number";
1125
1173
  case "FLOAT64":
1126
1174
  return "number";
1175
+ case "BOOL":
1176
+ return "boolean";
1127
1177
  case "BOOLEAN":
1128
1178
  return "boolean";
1129
1179
  case "DATE":
@@ -1156,7 +1206,7 @@ function convertDataType(dataType) {
1156
1206
  return null;
1157
1207
  }
1158
1208
  }
1159
- var FILE_MAP, diagnostics, TABLE_NODE_MAP, FIELD_NODE_MAP, NODE_ENTITY_MAP, analysisQueue, errExpr;
1209
+ var FILE_MAP, diagnostics, TABLE_NODE_MAP, FIELD_NODE_MAP, NODE_ENTITY_MAP, analysisQueue, errExpr2;
1160
1210
  var init_analyze = __esm({
1161
1211
  "../lang/analyze.ts"() {
1162
1212
  "use strict";
@@ -1172,7 +1222,7 @@ var init_analyze = __esm({
1172
1222
  FIELD_NODE_MAP = /* @__PURE__ */ new WeakMap();
1173
1223
  NODE_ENTITY_MAP = new NodeWeakMap();
1174
1224
  analysisQueue = /* @__PURE__ */ new Set();
1175
- errExpr = { node: "error", type: "error" };
1225
+ errExpr2 = { node: "error", type: "error" };
1176
1226
  }
1177
1227
  });
1178
1228
 
@@ -1182,10 +1232,10 @@ var init_parser_terms = __esm({
1182
1232
  "../lang/parser.terms.js"() {
1183
1233
  "use strict";
1184
1234
  table = 6;
1185
- primary_key = 11;
1186
- join = 15;
1187
- as = 21;
1188
- on = 24;
1235
+ primary_key = 12;
1236
+ join = 16;
1237
+ as = 22;
1238
+ on = 25;
1189
1239
  or = 31;
1190
1240
  and = 34;
1191
1241
  like = 43;
@@ -1266,24 +1316,24 @@ var init_parser = __esm({
1266
1316
  "../lang/parser.js"() {
1267
1317
  "use strict";
1268
1318
  init_tokens();
1269
- spec_Identifier = { __proto__: null, table: 12, primary_key: 22, join: 30, one: 34, many: 38, as: 42, on: 48, or: 62, and: 68, like: 86, not: 90, in: 110, from: 120, inner: 132, left: 136, right: 140, full: 144, cross: 148, select: 154, distinct: 158, where: 168, group: 174, by: 178, having: 184, order: 190, asc: 198, desc: 202, limit: 208, offset: 212, is: 218, null: 222, case: 232, when: 238, then: 242, else: 248, end: 252, exists: 258, true: 266, false: 270, count: 280, extract: 286, extend: 306 };
1319
+ spec_Identifier = { __proto__: null, table: 12, primary_key: 24, join: 32, one: 36, many: 40, as: 44, on: 50, or: 62, and: 68, like: 86, not: 90, in: 110, from: 120, inner: 132, left: 136, right: 140, full: 144, cross: 148, select: 154, distinct: 158, where: 168, group: 174, by: 178, having: 184, order: 190, asc: 198, desc: 202, limit: 208, offset: 212, is: 218, null: 222, case: 232, when: 238, then: 242, else: 248, end: 252, exists: 258, true: 266, false: 270, count: 280, extract: 286, extend: 306 };
1270
1320
  parser = LRParser.deserialize({
1271
1321
  version: 14,
1272
- states: "G`QYQPOOOOQO'#C`'#C`OOQO'#Di'#DiOwQPO'#DhOOQO'#Dz'#DzO#TQPO'#DyOOQO'#ER'#EROOQO'#EU'#EUO#[QPO'#ETOOQO'#EZ'#EZOOQO'#E^'#E^O#[QPO'#E]OOQO'#Eg'#EgO#aQPO'#EfOOQO'#Fp'#FpO#}QPO'#DgO$[QPO'#C_OOQO'#Fj'#FjO$aQPO'#FiO$fQPO'#FlQYQPOOQ%ZQPO'#FlO%`QPO'#EQO%`QPO'#EYO&aQPO'#DkO#fQPO'#DmO'nQPO'#DlOOQO'#GP'#GPO)aQPO,5:SO+hQPO'#CvO-pQPO'#CvOOQO'#DY'#DYO-xQPO'#DmOOQO'#D|'#D|OOQO'#EP'#EPOOQO'#EO'#EOO.cQPO,5:eO!PQPO,5:eO0eQPO'#EOOOQO'#En'#EnOOQO'#Eq'#EqOOQO'#Es'#EsO1_QPO'#ErOOQO'#FQ'#FQO1fQPO'#FPOOQO'#FU'#FUOOQO'#FW'#FWOOQO'#FT'#FTOOQO'#FY'#FYOOQO'#GT'#GTOOQO'#F]'#F]O1kQPO'#F[OOQO'#GS'#GSOOQO'#F`'#F`OOQO'#GR'#GROOQO'#GU'#GUOOQO'#F}'#F}O%`QPO'#EpO1pQPO'#F_OOQO'#EW'#EWO!PQPO,5:oO1uQPO,5:wO1}QPO,5;QOOQO-E9n-E9nO2rQPO,58yO2zQPO,5<TOOQO,5<W,5<WOOQO-E9j-E9jO3PQPO'#CvO3UQPO,5:lO3xQPO,5:tOOQO'#Cp'#CpOOQO'#Cr'#CrOOQO,5:V,5:VO4lQPO,5:VO4qQPO,5:XOOQO,5:W,5:WO4lQPO,5:WOOQO'#Cj'#CjOOQO'#Do'#DoOOQO'#Dq'#DqOOQO'#Ds'#DsOOQO'#Du'#DuOOQO'#Dw'#DwOwQPO'#DnO4vQPO'#DnOOQO'#Fq'#FqO4{QPO1G/nOOQO,5<Y,5<YO5oQPO,5;uO5vQPO,59bOOQO-E9l-E9lOOQO,5:k,5:kO9[QPO,5<OO9cQPO1G0PO:VQPO1G0PO:VQPO1G0POOQO'#Cz'#CzOOQO'#C}'#C}OOQO'#DW'#DWOOQO'#DP'#DPO:zQPO,59}OOQO'#D['#D[OOQO'#D_'#D_OOQO'#Dd'#DdO;SQPO,59}OOQO'#El'#ElO;XQPO,5;VO%`QPO,59hO%`QPO,59hO%`QPO,59hO%`QPO,59hO%`QPO,59hOOQO,5:j,5:jO4lQPO,5:jO;aQPO,5;^OOQO'#Ev'#EvOOQO'#Ft'#FtO;hQPO,5;^O%`QPO'#EuO#fQPO,5;kO;sQPO,5;vOOQO,5;[,5;[O<QQPO,5;yO<YQPO1G0ZO<}QPO'#E`O=xQPO1G0cOOQO'#Ei'#EiO>mQPO1G0lO>rQPO1G.eO?sQPO1G1nO?xQPO1G1oOOQO1G/q1G/qOOQO1G/s1G/sOOQO1G/r1G/rO@yQPO,5:YOwQPO,5:YOOQO-E9o-E9oOBQQPO1G1aOOQO1G1a1G1aPB[QPO'#FnOOQO1G1j1G1jOOQO,5<^,5<^OBaQPO7+%kOOQO-E9p-E9pOCTQPO7+%kOOQO,59k,59kOCxQPO1G/iO-xQPO1G/iOOQO1G0q1G0qO;[QPO1G0qOG]QPO1G/SOGdQPO1G/SOJvQPO1G/SOKQQPO1G/SOOQO1G/S1G/SOOQO1G0U1G0UO;hQPO1G0xOOQO-E9r-E9rOOQO'#E{'#E{OOQO'#E}'#E}OOQO1G0x1G0xO;nQPO1G0xO%`QPO'#EzOK[QPO,5;aOKcQPO1G1VOKhQPO1G1bOOQO1G1b1G1bOKoQPO1G1bO%`QPO1G1bOOQO'#Fb'#FbOKtQPO1G1eOKyQPO7+%uOLmQPO7+%uOOQO'#Eb'#EbOOQO'#Ed'#EdOOQO,5:z,5:zONSQPO7+%}ON^QPO7+%}OOQO7+&W7+&WONeQPO'#CrONoQPO'#CiONwQPO'#ChO/WQPO'#CxOOQO'#F|'#F|OOQO'#Fz'#FzON|QPO'#FmO!!TQPO7+$PO!![QPO'#CxO#fQPO7+'YONhQPO'#CrOOQO'#GW'#GWO!!aQPO'#FuO!#hQPO7+'ZOOQO'#Cs'#CsO%`QPO1G/tO!#oQPO1G/tO!$vQPO7+&{O!%OQPO7+&{OOQO7+&{7+&{P!PQPO'#FrO!%VQPO<<IVO-xQPO7+%TO!%yQPO'#DfO!&TQPO7+%TOOQO7+&]7+&]OOQO7+&d7+&dO;nQPO7+&dO!&YQPO,5;fOOQO'#Ex'#ExO%`QPO1G0{OOQO7+&q7+&qOOQO7+&|7+&|O!&aQPO7+&|O%`QPO7+'PO!&hQPO<<IaOOQO,5<_,5<_O!'[QPO<<IiOOQO-E9q-E9qOOQO'#Cd'#CdO!(SQPO,58}OOQO'#Cl'#ClOOQO'#Cn'#CnOOQO,59T,59TO!)^QPO,59SO:zQPO,5<PO!)fQPO,5<PO;XQPO,5<QO%`QPO,59eO%`QPO,59eO%`QPO,59eO%`QPO,59eO%`QPO,59eO4lQPO,59dOOQO,5<X,5<XOOQO-E9k-E9kOOQO<<Gk<<GkO%`QPO,59dO!)kQPO<<JtOOQO,5<a,5<aOOQO-E9s-E9sOOQO<<Ju<<JuO!)pQPO7+%`O%`QPO7+%`OOQO-E9m-E9mO!*vQPO<<JgOOQO<<Jg<<JgO!*}QPO,5<ZO!+XQPO<<HoO!+^QPO,5:QO!+fQPO,5:QOOQO<<Ho<<HoOOQO<<JO<<JOO!+mQPO7+&gOOQO<<Jh<<JhO!+zQPO<<JkP1uQPO'#FsOOQO'#Cf'#CfOOQO'#Ce'#CeOOQO1G.i1G.iO!,RQPO1G.nO4lQPO1G.nO!,WQPO1G1kO-xQPO1G1kOOQO1G1l1G1lO;[QPO1G1lO!-gQPO1G/PO!-nQPO1G/PO!.|QPO1G/PO!/WQPO1G/POOQO1G/P1G/POOQO1G/O1G/OO!/bQPO1G/OOOQOAN@`AN@`O!0bQPO<<HzP%`QPO'#FoOOQOAN@RAN@ROOQOAN>ZAN>ZO!1hQPO1G/lOOQOAN@VAN@VO!1oQPO'#CvO!2|QPO'#CuOOQO7+$Y7+$YO!)aQPO7+$YO-xQPO7+'VO!3RQPO7+'VOOQO7+'W7+'WO!,RQPO,59aO!,RQPO<<GtO!3WQPO<<JqOOQO<<Jq<<JqOOQO1G.{1G.{OOQOAN=`AN=`OOQOAN@]AN@]",
1273
- stateData: "!3b~O$lOSPOS~OUPO!^QO!oSO!vUO!yVO#OXO#RYO#[[O$_aO~OThO$miO~OTmO}oO!PxO!QxO!SrO#T!RO#cwO#hyO#u{O#v!RO#y}O#{!OO$Q!SO$T!VO$V!WO$mpO~O!qqO~P!PO!{!]O~O#T!`O~O!^QO!oSO!vUO!yVO#OXO#RYO#[[O~O$j!ZX$y!ZX$t!ZX~P#fOT!bO~OT!cO~O$y!dOU$`X!^$`X!o$`X!v$`X!y$`X#O$`X#R$`X#[$`X$_$`X$j$`X~O$y!dO~OTmO}oO!PxO!QxO#T!RO#cwO#hyO#u{O#v!RO#y}O#{!OO$Q!SO$T!VO$V!WO$mpO~OT!jOe!iO_!_X!^!_X!d!_X!f!_X!h!_X!j!_X!l!_X!o!_X!v!_X!y!_X#O!_X#R!_X#[!_X$j!_X$y!_X$t!_Xh!_X~OT!jOe!iO_!`X!^!`X!d!`X!f!`X!h!`X!j!`X!l!`X!o!`X!v!`X!y!`X#O!`X#R!`X#[!`X$j!`X$y!`X$t!`Xh!`X~O_!pO!d!qO!f!rO!h!sO!j!tO!l!uO~O!^![a!o![a!v![a!y![a#O![a#R![a#[![a$j![a$y![a$t![a~P({O$m!{O$o!zOejXkjXojXrjXtjXujXvjXwjXxjXyjX{jX}jX!PjX!QjX!SjX!TjX!UjX!XjX#ajX~OTjX!^jX!ojX!vjX!yjX#OjX#RjX#[jX$jjX$rjX$yjX$tjX#kjX#mjX#rjX_jX!djX!fjX!hjX!jjX!ljX#pjX#TjX#cjX#hjX#ujX#vjX#yjX#{jX$QjX$TjX$VjX~P*TOT!|O!S#OO~O!^QO!oSO!vUO!yVO#OXO#RYO#[[O~P%`O$r#QO!^!ma!o!ma!v!ma!y!ma#O!ma#R!ma#[!ma$j!ma$y!ma$t!ma~Oe!iOk#WOo#TOr#UOt#WOu#WOv#WOw#WOx#WOy#WO{#VO}oO!P#YO!Q#YO!S#ZO!T#ZO!U#ZO!X#[O#a#^O~OT!jO!^!rX!o!rX!v!rX!y!rX#O!rX#R!rX#[!rX$j!rX$r!rX$y!rX$t!rX~P/WO#k#hO~P%`O$m#lO~O$m#mO~O$m#oO~OT#qO#T#qO~O#^#sO!^#Ya!o#Ya!v#Ya!y#Ya#O#Ya#R#Ya#[#Ya$j#Ya$y#Ya$t#Ya~Oe!iO$m#uO~O$m#wO~OT!|O~O!^!ta!o!ta!v!ta!y!ta#O!ta#R!ta#[!ta$j!ta$y!ta$t!ta~P/ZO!^!|a!o!|a!v!|a!y!|a#O!|a#R!|a#[!|a$j!|a$y!|a$t!|a~P/ZOT!jO~O$t#yO~O_!pO~O!^![i!o![i!v![i!y![i#O![i#R![i#[![i$j![i$y![i$t![i~P({O$t$PO~P%`O$o!zOTjaejakjaojarjatjaujavjawjaxjayja{ja}ja!Pja!Qja!Sja!Tja!Uja!Xja!^ja!oja!vja!yja#Oja#Rja#[ja#aja$jja$rja$yja$tja#kja#mja#rja_ja!dja!fja!hja!jja!lja#pja#Tja#cja#hja#uja#vja#yja#{ja$Qja$Tja$Vja~O$t$RO~P/ZO!^!mi!o!mi!v!mi!y!mi#O!mi#R!mi#[!mi$j!mi$y!mi$t!mi~P!PO$r$TO!^!mi!o!mi!v!mi!y!mi#O!mi#R!mi#[!mi$j!mi$y!mi$t!mi~O{#VO!X#[O~O$m$YO~O}oO#cwO~O#k#hO~P/ZO#k#hO#p$eO#r$fO~O!S$nO!qqO$t$mO~P%`OT$pO#v$pO~O$r$rO!^!wi!o!wi!v!wi!y!wi#O!wi#R!wi#[!wi$j!wi$y!wi$t!wi~O#V$tO#X$uO!^#SX!o#SX!v#SX!y#SX#O#SX#R#SX#[#SX$j#SX$r#SX$y#SX$t#SX~O$r$wO!^#Pi!o#Pi!v#Pi!y#Pi#O#Pi#R#Pi#[#Pi$j#Pi$y#Pi$t#Pi~O#T$yO~OT$zO_!pO}oO!PxO!QxO#T!RO#cwO#hyO#u{O#v!RO#y}O#{!OO$Q!SO$T!VO$V!WO~O$m%TO~OT%UO_!pO}oO!PxO!QxO#T!RO#cwO#hyO#u{O#v!RO#y}O#{!OO$Q!SO$T!VO$V!WO~Oh%YO_!ba!^!ba!d!ba!f!ba!h!ba!j!ba!l!ba!o!ba!v!ba!y!ba#O!ba#R!ba#[!ba$j!ba$y!ba$t!ba~O$r%^O$t%_O~P/ZO$o!zO~O!^!mq!o!mq!v!mq!y!mq#O!mq#R!mq#[!mq$j!mq$y!mq$t!mq~P!PO$r%aO!^!mq!o!mq!v!mq!y!mq#O!mq#R!mq#[!mq$j!mq$y!mq$t!mq~O$m%bO~Ok#WOt#WOu#WOv#WOw#WOx#WOy#WO{#VO}oO!P#YO!Q#YO!S#ZO!T#ZO!U#ZO!X#[O#a#^OTpiepiopi!^pi!opi!vpi!ypi#Opi#Rpi#[pi$jpi$rpi$ypi$tpi#kpi#mpi#rpi_pi!dpi!fpi!hpi!jpi!lpi#ppi#Tpi#cpi#hpi#upi#vpi#ypi#{pi$Qpi$Tpi$Vpi~Or#UO~PC}Orpi~PC}O!S#ZO!T#ZO!U#ZOTpiepikpiopirpitpiupivpiwpixpiypi{pi}pi!Xpi!^pi!opi!vpi!ypi#Opi#Rpi#[pi#api$jpi$rpi$ypi$tpi#kpi#mpi#rpi_pi!dpi!fpi!hpi!jpi!lpi#ppi#Tpi#cpi#hpi#upi#vpi#ypi#{pi$Qpi$Tpi$Vpi~O!P#YO!Q#YO~PGkO!Ppi!Qpi~PGkO#m%iO~P/ZO$t%kO~O$t%lO~P/ZO$t%lO~O!^QO~O!^!wq!o!wq!v!wq!y!wq#O!wq#R!wq#[!wq$j!wq$y!wq$t!wq~P!PO$r%oO!^!wq!o!wq!v!wq!y!wq#O!wq#R!wq#[!wq$j!wq$y!wq$t!wq~O!^#Pq!o#Pq!v#Pq!y#Pq#O#Pq#R#Pq#[#Pq$j#Pq$y#Pq$t#Pq~OT#qO#T#qO~PMbO$r%qO~PMbOT%sO$ZfX~P*TOa%uOc%vO~OT%xO~O$r&SOT$aX_$aX}$aX!P$aX!Q$aX#T$aX#c$aX#h$aX#u$aX#v$aX#y$aX#{$aX$Q$aX$T$aX$V$aX$t$aX~O$t&UO~P>rO$Z&VO~O$r&XOT$iX_$iX}$iX!P$iX!Q$iX#T$iX#c$iX#h$iX#u$iX#v$iX#y$iX#{$iX$Q$iX$T$iX$V$iX$t$iX~O$t&ZO~P?xOh%YO_!bi!^!bi!d!bi!f!bi!h!bi!j!bi!l!bi!o!bi!v!bi!y!bi#O!bi#R!bi#[!bi$j!bi$y!bi$t!bi~O$r&_O$t&`O~O$t&`O~P%`O!^!my!o!my!v!my!y!my#O!my#R!my#[!my$j!my$y!my$t!my~P!PO$r&dO$t!YX~P/ZO$t&eO~O#r#na~P/ZO$t&hO~P/ZO!^!wy!o!wy!v!wy!y!wy#O!wy#R!wy#[!wy$j!wy$y!wy$t!wy~P!POT#qO#T#qO!^#Py!o#Py!v#Py!y#Py#O#Py#R#Py#[#Py$j#Py$y#Py$t#Py~OZ&kOTVa_Va}Va!PVa!QVa#TVa#cVa#hVa#uVa#vVa#yVa#{Va$QVa$TVa$VVa$rVa$tVa~Oe!iOh%YO~O$m&qO~O$t&{O~O_!bq!^!bq!d!bq!f!bq!h!bq!j!bq!l!bq!o!bq!v!bq!y!bq#O!bq#R!bq#[!bq$j!bq$y!bq$t!bq~P/ZO$t'OO~P%`O$r$ca$t$ca~P/ZO$t'PO~O$r'QO$t!Ya~O$t!Ya~P%`O#k#iq#p#iq#r#iq~P/ZO$t'RO~P/ZOT'SO~O$m'WO~Ok#WOt#WOu#WOv#WOw#WOx#WOy#WO{#VO}oO!P#YO!Q#YO!S#ZO!T#ZO!U#ZO!X#[O#a#^Oemiomi~Or#UO~P!,]Ormi~P!,]O!S#ZO!T#ZO!U#ZOemikmiomirmitmiumivmiwmixmiymi{mi}mi!Xmi#ami~O!P#YO!Q#YO~P!-uO!Pmi!Qmi~P!-uOTli_li#Tli#cli#hli#uli#vli#yli#{li$Qli$Tli$Vli$rli$tli~P/ZO_!by!^!by!d!by!f!by!h!by!j!by!l!by!o!by!v!by!y!by#O!by#R!by#[!by$j!by$y!by$t!by~P/ZO$t!Yi~P%`O$o!zOkjXTjX_jX}jX!PjX!QjX#TjX#cjX#hjX#ujX#vjX#yjX#{jX$QjX$TjX$VjX$rjX$tjX~Ok'ZO~O$t'^O~O$t'aO~OP!T!S!Q~",
1274
- goto: "Hi${PPP$|%QPP%U%Y%]%`P%c%k%qP&OP&OP&RP&e'TP'a'gP%c(q(wP)_*^P*vPPPPPP+bP,OP-sPP.aPPP)_/PP/q/}0i0vP1W1W1]2a2eP2eP2eP2eP2eP0i2iP2vP2|3_0i3jP0i3wP4UP0i4[P0i4iP4vP5OP5OP0i5RP5`P)_5cP5}P7^8a7^9dP:g:mP:sP:v:|P;QP7^;[PP<_=bP=bP<_>e>e?hP7^@kPAnP1b(q(qP$|$|AqPAuA{BRC_CiCxDOD^DdDnPPPPDtPDxEOPGVPG`7^>e)_PHeTcOdT`OdT%P#u%RR%t$zR&m%tR&l%tS%P#u%RT%V#w%XX$|#u#w%R%XS!vl!yQ#|!wX${#u#w%R%XR%w${Q!lhQ!ojQ#fvQ#v!bQ&R$}R&o%xQ!khQ!njQ#evQ#x!lQ#z!oQ$b#fW%S#u#w%R%XQ&y&RR'V&oQ%Z#{Q&]%[Q&n%xR'['VQ'U&nR'`'[#Q!UTfgpuz!Z!^!{#Q#`#a#b#c#d#k#m#u#w$T$Y$i$o$r%R%X%Z%^%`%a%b%j%n%o%|%}&O&P&Q&V&]&_&d&q&}'Q'WS'T&n'[R'_'ZX%O#u#w%R%Xr#`v!g!h#P#g$O$j$l%c%h%m&[&a&g&i&z&|R%|$}!y!YTfgpuz!Z!^!{#Q#`#a#b#c#d#k#m$T$Y$i$o$r%Z%^%`%a%b%j%n%o%|%}&O&P&Q&V&]&_&d&q&}'Q'Wv#av!g!h#P#g$O$]$j$l%c%h%m&[&a&g&i&t&z&|R%}$}z#bv!g!h#P#g$O$]$^$j$l%c%h%m&[&a&g&i&t&u&z&|R&O$}|#Wv!g!h#P#g$O$]$^$j$l$}%c%h%m&[&a&g&i&t&u&z&|T$W#X%y#QxTfgpuz!Z!^!{#Q#`#a#b#c#d#k#m#u#w$T$Y$i$o$r%R%X%Z%^%`%a%b%j%n%o%|%}&O&P&Q&V&]&_&d&q&}'Q'Wz#Xv!g!h#P#g$O$]$^$j$l%c%h%m&[&a&g&i&t&u&z&|Q$[#_Q%y$}R&s%{!O#cv!g!h#P#g$O$]$^$_$j$l%c%h%m&[&a&g&i&t&u&v&z&|R&P$}!S#dv!g!h#P#g$O$]$^$_$`$j$l%c%h%m&[&a&g&i&t&u&v&w&z&|R&Q$}z#]v!g!h#P#g$O$]$^$j$l%c%h%m&[&a&g&i&t&u&z&|Q$X#XQ%z$}R&p%yQ%d$YQ&b%bQ'X&qR']'WSeOdS!mipQ$k#lQ%d$YQ&W%TQ&b%bQ'X&qR']'Wg^O_dip#l$Y%T%b&q'WfRO_dip#l$Y%T%b&q'WR%n$qVkR!v#|UjR!v#|!y!XTfgpuz!Z!^!{#Q#`#a#b#c#d#k#m$T$Y$i$o$r%Z%^%`%a%b%j%n%o%|%}&O&P&Q&V&]&_&d&q&}'Q'WT!xl!yT!wl!ygTO_dip#l$Y%T%b&q'WQuTR$o#mQtTQ#SuQ#p!^]$S#Q$T$r%`%a%ocsTu!^#Q$T$r%`%a%ogfO_dip#l$Y%T%b&q'WgWO_dip#l$Y%T%b&q'WQ!^WR!_ZggO_dip#l$Y%T%b&q'WgZO_dip#l$Y%T%b&q'WQ#r!_V%p$w%q&jR$v#qg]O_dip#l$Y%T%b&q'WR#t!`z#_v!g!h#P#g$O$]$^$j$l%c%h%m&[&a&g&i&t&u&z&|R%{$}#Q!QTfgpuz!Z!^!{#Q#`#a#b#c#d#k#m#u#w$T$Y$i$o$r%R%X%Z%^%`%a%b%j%n%o%|%}&O&P&Q&V&]&_&d&q&}'Q'WQ$Z#_Q%e$[Q&r%{R'Y&s#R!WTfgpuz!Z!^!{#Q#`#a#b#c#d#k#m#u#w$T$Y$i$o$r%R%X%Z%^%`%a%b%j%n%o%|%}&O&P&Q&V&]&_&d&q&}'Q'W#R!ZTfgpuz!Z!^!{#Q#`#a#b#c#d#k#m#u#w$T$Y$i$o$r%R%X%Z%^%`%a%b%j%n%o%|%}&O&P&Q&V&]&_&d&q&}'Q'W#RzTfgpuz!Z!^!{#Q#`#a#b#c#d#k#m#u#w$T$Y$i$o$r%R%X%Z%^%`%a%b%j%n%o%|%}&O&P&Q&V&]&_&d&q&}'Q'WX#iz#g#j$cX#kz#g#j$cR%j$jQ$h#jR%g$cT$i#j$cQ$g#jS%f$c$hR&f%g#R|Tfgpuz!Z!^!{#Q#`#a#b#c#d#k#m#u#w$T$Y$i$o$r%R%X%Z%^%`%a%b%j%n%o%|%}&O&P&Q&V&]&_&d&q&}'Q'W#R!RTfgpuz!Z!^!{#Q#`#a#b#c#d#k#m#u#w$T$Y$i$o$r%R%X%Z%^%`%a%b%j%n%o%|%}&O&P&Q&V&]&_&d&q&}'Q'W#R!PTfgpuz!Z!^!{#Q#`#a#b#c#d#k#m#u#w$T$Y$i$o$r%R%X%Z%^%`%a%b%j%n%o%|%}&O&P&Q&V&]&_&d&q&}'Q'W#R!UTfgpuz!Z!^!{#Q#`#a#b#c#d#k#m#u#w$T$Y$i$o$r%R%X%Z%^%`%a%b%j%n%o%|%}&O&P&Q&V&]&_&d&q&}'Q'W#R!TTfgpuz!Z!^!{#Q#`#a#b#c#d#k#m#u#w$T$Y$i$o$r%R%X%Z%^%`%a%b%j%n%o%|%}&O&P&Q&V&]&_&d&q&}'Q'W#R![Tfgpuz!Z!^!{#Q#`#a#b#c#d#k#m#u#w$T$Y$i$o$r%R%X%Z%^%`%a%b%j%n%o%|%}&O&P&Q&V&]&_&d&q&}'Q'WR$q#oTbOdQdOR!edQ%R#uR&T%RbnTu!^#Q$T$r%`%a%o!t!ffgpz!Z!{#`#a#b#c#d#k#m#u#w$Y$i$o%R%X%Z%^%b%j%n%|%}&O&P&Q&V&]&_&d&n&q&}'Q'W'Z'[T!}n!fQ%]$OS&^%]&cR&c%cd_Odip#l$Y%T%b&q'WR!a_Q!ylR#}!yQ#RtU$U#R$V$sQ$V#SR$s#pQ$x#rR%r$xQ#jzQ$c#gT$d#j$cQ%X#wR&Y%XT%Q#u%RX$}#u#w%R%XbvTu!^#Q$T$r%`%a%oQ!gfQ!hgQ#PpQ#gzQ#n!ZQ$O!{Q$]#`Q$^#aQ$_#bQ$`#cQ$a#dQ$j#kQ$l#mW%c$Y%b&q'WQ%h$iQ%m$oQ&[%ZY&a%^&_&d&}'QQ&g%jQ&i%nQ&t%|Q&u%}Q&v&OQ&w&PQ&x&QQ&z&VR&|&]QlRQ#{!vR%[#|!x!YTfgpuz!Z!^!{#Q#`#a#b#c#d#k#m$T$Y$i$o$r%Z%^%`%a%b%j%n%o%|%}&O&P&Q&V&]&_&d&q&}'Q'WX%O#u#w%R%XT%W#w%X",
1275
- nodeNames: "\u26A0 Comment Program TableStatement Kw Identifier table ColumnDef DataType PrimaryKey Kw primary_key JoinDef JoinType Kw join Kw one Kw many Kw as Alias Kw on BinaryExpression Ref = ComputedDef BinaryExpression Kw or BinaryExpression Kw and ComparisonOp != <> < > <= >= Kw like Kw not AddOp + - MulOp * / % InExpression Kw in InValueList QueryStatement FromClause Kw from TableName Subquery SubqueryExpression JoinClause Kw inner Kw left Kw right Kw full Kw cross SelectClause Kw select Kw distinct SelectItem Wildcard WhereClause Kw where GroupByClause Kw group Kw by HavingClause Kw having OrderByClause Kw order OrderItem Number Kw asc Kw desc LimitClause Kw limit Kw offset NullTestExpression Kw is Kw null UnaryExpression UnaryOperator CaseExpression Kw case WhenClause Kw when Kw then ElseClause Kw else Kw end ExistsExpression Kw exists String Boolean Kw true Kw false Null FunctionCall Count Kw count ExtractExpression Kw extract ExtractUnit Param Parenthetical InExpression NullTestExpression : ViewStatement ExtendStatement Kw extend",
1322
+ states: "G`QYQPOOOOQO'#C`'#C`OOQO'#Di'#DiOwQPO'#DhOOQO'#Dz'#DzO#TQPO'#DyOOQO'#ER'#EROOQO'#EU'#EUO#[QPO'#ETOOQO'#EZ'#EZOOQO'#E^'#E^O#[QPO'#E]OOQO'#Eg'#EgO#aQPO'#EfOOQO'#Fp'#FpO#}QPO'#DgO$[QPO'#C_OOQO'#Fj'#FjO$[QPO'#FiO$aQPO'#FlQYQPOOQ%UQPO'#FlO%ZQPO'#EQO%ZQPO'#EYO(hQPO'#CcO(rQPO'#CcO(wQPO'#DkO#fQPO'#DmO*UQPO'#DlOOQO'#GP'#GPO+wQPO,5:SO,kQPO'#CcO-zQPO'#CcOOQO'#DY'#DYO.SQPO'#DmOOQO'#D|'#D|OOQO'#EP'#EPOOQO'#EO'#EOO.mQPO,5:eO!PQPO,5:eO0oQPO'#EOOOQO'#En'#EnOOQO'#Eq'#EqOOQO'#Es'#EsO1iQPO'#ErOOQO'#FQ'#FQO1pQPO'#FPOOQO'#FU'#FUOOQO'#FW'#FWOOQO'#FT'#FTOOQO'#FY'#FYOOQO'#GT'#GTOOQO'#F]'#F]O1uQPO'#F[OOQO'#GS'#GSOOQO'#F`'#F`OOQO'#GR'#GROOQO'#GU'#GUOOQO'#F}'#F}O%ZQPO'#EpO1zQPO'#F_OOQO'#EW'#EWO!PQPO,5:oO2PQPO,5:wO2XQPO,5;QOOQO-E9n-E9nO2|QPO,58yO3UQPO,5<TOOQO,5<W,5<WOOQO-E9j-E9jO3ZQPO,5:lO3}QPO,5:tOOQO,5<X,5<XO4qQPO,58}OOQO-E9k-E9kOOQO'#Cq'#CqOOQO'#Cs'#CsOOQO,5:V,5:VO8]QPO,5:VO8bQPO,5:XOOQO,5:W,5:WO8]QPO,5:WOOQO'#Ck'#CkOOQO'#Do'#DoOOQO'#Dq'#DqOOQO'#Ds'#DsOOQO'#Du'#DuOOQO'#Dw'#DwOwQPO'#DnO8gQPO'#DnOOQO'#Fq'#FqO8lQPO1G/nO9`QPO,5;uOOQO,5:k,5:kO9gQPO,5<OO9nQPO1G0PO:bQPO1G0PO:bQPO1G0POOQO'#Cz'#CzOOQO'#C}'#C}OOQO'#DW'#DWOOQO'#DP'#DPO;VQPO,59}OOQO'#D['#D[OOQO'#D_'#D_OOQO'#Dd'#DdO;_QPO,59}OOQO'#El'#ElO;dQPO,5;VO%ZQPO,59hO%ZQPO,59hO%ZQPO,59hO%ZQPO,59hO%ZQPO,59hOOQO,5:j,5:jO8]QPO,5:jO;lQPO,5;^OOQO'#Ev'#EvOOQO'#Ft'#FtO;sQPO,5;^O%ZQPO'#EuO#fQPO,5;kO<OQPO,5;vOOQO,5;[,5;[O<]QPO,5;yO<eQPO1G0ZO=YQPO'#E`O>TQPO1G0cOOQO'#Ei'#EiO>xQPO1G0lO>}QPO1G.eO@OQPO1G1nO@TQPO1G1oPAUQPO'#FmOOQO1G/q1G/qOOQO1G/s1G/sOOQO1G/r1G/rOAZQPO,5:YOwQPO,5:YOOQO-E9o-E9oOBbQPO1G1aOOQO1G1a1G1aOOQO1G1j1G1jOOQO,5<^,5<^OBlQPO7+%kOOQO-E9p-E9pOC`QPO7+%kOOQO,59k,59kODTQPO1G/iO.SQPO1G/iOOQO1G0q1G0qO;gQPO1G0qOGhQPO1G/SOGoQPO1G/SOKRQPO1G/SOK]QPO1G/SOOQO1G/S1G/SOOQO1G0U1G0UO;sQPO1G0xOOQO-E9r-E9rOOQO'#E{'#E{OOQO'#E}'#E}OOQO1G0x1G0xO;yQPO1G0xO%ZQPO'#EzOKgQPO,5;aOKnQPO1G1VOKsQPO1G1bOOQO1G1b1G1bOKzQPO1G1bO%ZQPO1G1bOOQO'#Fb'#FbOLPQPO1G1eOLUQPO7+%uOLxQPO7+%uOOQO'#Eb'#EbOOQO'#Ed'#EdOOQO,5:z,5:zON_QPO7+%}ONiQPO7+%}OOQO7+&W7+&WO!!WQPO'#CcO!!_QPO'#CjO$[QPO'#CiO/bQPO'#CxOOQO'#F|'#F|OOQO'#F{'#F{O!!gQPO'#FnO!#nQPO7+$PO!#uQPO'#CxO#fQPO7+'YONpQPO'#CcOOQO'#GW'#GWO!#zQPO'#FuO!%RQPO7+'ZOOQO'#Ct'#CtO%ZQPO1G/tO!%YQPO1G/tO!&aQPO7+&{O!&iQPO7+&{OOQO7+&{7+&{P!PQPO'#FrO!&pQPO<<IVO.SQPO7+%TO!'dQPO'#DfO!'nQPO7+%TOOQO7+&]7+&]OOQO7+&d7+&dO;yQPO7+&dO!'sQPO,5;fOOQO'#Ex'#ExO%ZQPO1G0{OOQO7+&q7+&qOOQO7+&|7+&|O!'zQPO7+&|O%ZQPO7+'PO!(RQPO<<IaOOQO,5<_,5<_O!(uQPO<<IiOOQO-E9q-E9qOOQO'#Ce'#CeO!)mQPO,59OOOQO'#Cm'#CmOOQO'#Co'#CoOOQO,59U,59UO!*wQPO,59TO;VQPO,5<PO!+PQPO,5<PO;dQPO,5<QO%ZQPO,59eO%ZQPO,59eO%ZQPO,59eO%ZQPO,59eO%ZQPO,59eO8]QPO,59dOOQO,5<Y,5<YOOQO-E9l-E9lOOQO<<Gk<<GkO%ZQPO,59dO!+UQPO<<JtOOQO,5<a,5<aOOQO-E9s-E9sOOQO<<Ju<<JuO!+ZQPO7+%`O%ZQPO7+%`OOQO-E9m-E9mO!,aQPO<<JgOOQO<<Jg<<JgO!,hQPO,5<ZO!,rQPO<<HoO!,wQPO,5:QO!-PQPO,5:QOOQO<<Ho<<HoOOQO<<JO<<JOO!-WQPO7+&gOOQO<<Jh<<JhO!-eQPO<<JkP2PQPO'#FsOOQO'#Cg'#CgOOQO'#Cf'#CfOOQO1G.j1G.jO$[QPO1G.oO8]QPO1G.oO!-lQPO1G1kO.SQPO1G1kOOQO1G1l1G1lO;gQPO1G1lO!.{QPO1G/PO!/SQPO1G/PO!0bQPO1G/PO!0lQPO1G/POOQO1G/P1G/POOQO1G/O1G/OO!0vQPO1G/OOOQOAN@`AN@`O!1vQPO<<HzP%ZQPO'#FoOOQOAN@RAN@ROOQOAN>ZAN>ZO!2|QPO1G/lOOQOAN@VAN@VO!3TQPO'#CvOOQO7+$Z7+$ZO!*zQPO7+$ZO.SQPO7+'VO!3YQPO7+'VOOQO7+'W7+'WO$[QPO,59bO$[QPO<<GuO!3_QPO<<JqOOQO<<Jq<<JqOOQO1G.|1G.|OOQOAN=aAN=aOOQOAN@]AN@]",
1323
+ stateData: "!3i~O$lOSPOS~OUPO!^QO!oSO!vUO!yVO#OXO#RYO#[[O$_aO~OThO$nkO~OToO}qO!PzO!QzO!StO#T!TO#cyO#h{O#u}O#v!TO#y!PO#{!QO$Q!UO$T!XO$V!YO$nrO~O!qsO~P!PO!{!_O~O#T!bO~O!^QO!oSO!vUO!yVO#OXO#RYO#[[O~O$j!ZX$y!ZX$t!ZX~P#fOThO~O$y!fOU$`X!^$`X!o$`X!v$`X!y$`X#O$`X#R$`X#[$`X$_$`X$j$`X~O$y!fO~OToO}qO!PzO!QzO#T!TO#cyO#h{O#u}O#v!TO#y!PO#{!QO$Q!UO$T!XO$V!YO$nrO~O$m!jOTVX`VXfVX!^VX!dVX!fVX!hVX!jVX!lVX!oVX!vVX!yVX#OVX#RVX#[VX$jVX$yVX$tVXkVX}VX!PVX!QVX#TVX#cVX#hVX#uVX#vVX#yVX#{VX$QVX$TVX$VVX$rVX~O$nVXiVX~P&[OT!kO~OT!nOf!mO`!_X!^!_X!d!_X!f!_X!h!_X!j!_X!l!_X!o!_X!v!_X!y!_X#O!_X#R!_X#[!_X$j!_X$y!_X$t!_Xi!_X~OT!nOf!mO`!`X!^!`X!d!`X!f!`X!h!`X!j!`X!l!`X!o!`X!v!`X!y!`X#O!`X#R!`X#[!`X$j!`X$y!`X$t!`Xi!`X~O`!tO!d!uO!f!vO!h!wO!j!xO!l!yO~O!^![a!o![a!v![a!y![a#O![a#R![a#[![a$j![a$y![a$t![a~P+cO$n#OOoVXrVXtVXuVXvVXwVXxVXyVX{VX!SVX!TVX!UVX!XVX#aVX#kVX#mVX#rVX#pVX~P&[OT!kO!S#PO~O!^QO!oSO!vUO!yVO#OXO#RYO#[[O~P%ZO$r#RO!^!ma!o!ma!v!ma!y!ma#O!ma#R!ma#[!ma$j!ma$y!ma$t!ma~Of!mOk#XOo#UOr#VOt#XOu#XOv#XOw#XOx#XOy#XO{#WO}qO!P#ZO!Q#ZO!S#[O!T#[O!U#[O!X#]O#a#_O~OT!nO!^!rX!o!rX!v!rX!y!rX#O!rX#R!rX#[!rX$j!rX$r!rX$y!rX$t!rX~P/bO#k#iO~P%ZO$n#mO~O$n#nO~O$n#pO~OT#rO#T#rO~O#^#tO!^#Ya!o#Ya!v#Ya!y#Ya#O#Ya#R#Ya#[#Ya$j#Ya$y#Ya$t#Ya~Of!mO$n#vO~O$n#xO~O!^!ta!o!ta!v!ta!y!ta#O!ta#R!ta#[!ta$j!ta$y!ta$t!ta~P/eO!^!|a!o!|a!v!|a!y!|a#O!|a#R!|a#[!|a$j!|a$y!|a$t!|a~P/eO$m!jOTVa`VafVa!^Va!dVa!fVa!hVa!jVa!lVa!oVa!vVa!yVa#OVa#RVa#[Va$jVa$yVakVaoVarVatVauVavVawVaxVayVa{Va}Va!PVa!QVa!SVa!TVa!UVa!XVa#aVa$rVa$nVa$tVa#kVaiVa#mVa#rVa#pVa#TVa#cVa#hVa#uVa#vVa#yVa#{Va$QVa$TVa$VVa~OT!nO~O$t#{O~O`!tO~O!^![i!o![i!v![i!y![i#O![i#R![i#[![i$j![i$y![i$t![i~P+cO$t$RO~P%ZO$t$SO~P/eO!^!mi!o!mi!v!mi!y!mi#O!mi#R!mi#[!mi$j!mi$y!mi$t!mi~P!PO$r$UO!^!mi!o!mi!v!mi!y!mi#O!mi#R!mi#[!mi$j!mi$y!mi$t!mi~O{#WO!X#]O~O$n$ZO~O}qO#cyO~O#k#iO~P/eO#k#iO#p$fO#r$gO~O!S$oO!qsO$t$nO~P%ZOT$qO#v$qO~O$r$sO!^!wi!o!wi!v!wi!y!wi#O!wi#R!wi#[!wi$j!wi$y!wi$t!wi~O#V$uO#X$vO!^#SX!o#SX!v#SX!y#SX#O#SX#R#SX#[#SX$j#SX$r#SX$y#SX$t#SX~O$r$xO!^#Pi!o#Pi!v#Pi!y#Pi#O#Pi#R#Pi#[#Pi$j#Pi$y#Pi$t#Pi~O#T$zO~OT${O`!tO}qO!PzO!QzO#T!TO#cyO#h{O#u}O#v!TO#y!PO#{!QO$Q!UO$T!XO$V!YO~O$n%UO~OT%VO`!tO}qO!PzO!QzO#T!TO#cyO#h{O#u}O#v!TO#y!PO#{!QO$Q!UO$T!XO$V!YO~O$m!jO~Oi%ZO`!ba!^!ba!d!ba!f!ba!h!ba!j!ba!l!ba!o!ba!v!ba!y!ba#O!ba#R!ba#[!ba$j!ba$y!ba$t!ba~O$r%_O$t%`O~P/eO!^!mq!o!mq!v!mq!y!mq#O!mq#R!mq#[!mq$j!mq$y!mq$t!mq~P!PO$r%bO!^!mq!o!mq!v!mq!y!mq#O!mq#R!mq#[!mq$j!mq$y!mq$t!mq~O$n%cO~Ok#XOt#XOu#XOv#XOw#XOx#XOy#XO{#WO}qO!P#ZO!Q#ZO!S#[O!T#[O!U#[O!X#]O#a#_OTpifpiopi!^pi!opi!vpi!ypi#Opi#Rpi#[pi$jpi$rpi$ypi$tpi#kpi#mpi#rpi`pi!dpi!fpi!hpi!jpi!lpi#ppi#Tpi#cpi#hpi#upi#vpi#ypi#{pi$Qpi$Tpi$Vpi~Or#VO~PDYOrpi~PDYO!S#[O!T#[O!U#[OTpifpikpiopirpitpiupivpiwpixpiypi{pi}pi!Xpi!^pi!opi!vpi!ypi#Opi#Rpi#[pi#api$jpi$rpi$ypi$tpi#kpi#mpi#rpi`pi!dpi!fpi!hpi!jpi!lpi#ppi#Tpi#cpi#hpi#upi#vpi#ypi#{pi$Qpi$Tpi$Vpi~O!P#ZO!Q#ZO~PGvO!Ppi!Qpi~PGvO#m%jO~P/eO$t%lO~O$t%mO~P/eO$t%mO~O!^QO~O!^!wq!o!wq!v!wq!y!wq#O!wq#R!wq#[!wq$j!wq$y!wq$t!wq~P!PO$r%pO!^!wq!o!wq!v!wq!y!wq#O!wq#R!wq#[!wq$j!wq$y!wq$t!wq~O!^#Pq!o#Pq!v#Pq!y#Pq#O#Pq#R#Pq#[#Pq$j#Pq$y#Pq$t#Pq~OT#rO#T#rO~PMmO$r%rO~PMmO$m!jO$n#OOfVXkVXoVXrVXtVXuVXvVXwVXxVXyVX{VX}VX!PVX!QVX!SVX!TVX!UVX!XVX#aVX$ZgX~OT%tO~PNpOb%vOd%wO~O$r&TOT$bX`$bX}$bX!P$bX!Q$bX#T$bX#c$bX#h$bX#u$bX#v$bX#y$bX#{$bX$Q$bX$T$bX$V$bX$t$bX~O$t&VO~P>}O$Z&WO~O$r&YOT$iX`$iX}$iX!P$iX!Q$iX#T$iX#c$iX#h$iX#u$iX#v$iX#y$iX#{$iX$Q$iX$T$iX$V$iX$t$iX~O$t&[O~P@TOi%ZO`!bi!^!bi!d!bi!f!bi!h!bi!j!bi!l!bi!o!bi!v!bi!y!bi#O!bi#R!bi#[!bi$j!bi$y!bi$t!bi~O$r&`O$t&aO~O$t&aO~P%ZO!^!my!o!my!v!my!y!my#O!my#R!my#[!my$j!my$y!my$t!my~P!PO$r&eO$t!YX~P/eO$t&fO~O#r#na~P/eO$t&iO~P/eO!^!wy!o!wy!v!wy!y!wy#O!wy#R!wy#[!wy$j!wy$y!wy$t!wy~P!POT#rO#T#rO!^#Py!o#Py!v#Py!y#Py#O#Py#R#Py#[#Py$j#Py$y#Py$t#Py~O[&lOTWa`Wa}Wa!PWa!QWa#TWa#cWa#hWa#uWa#vWa#yWa#{Wa$QWa$TWa$VWa$rWa$tWa~Of!mOi%ZO~O$n&rO~O$t&|O~O`!bq!^!bq!d!bq!f!bq!h!bq!j!bq!l!bq!o!bq!v!bq!y!bq#O!bq#R!bq#[!bq$j!bq$y!bq$t!bq~P/eO$t'PO~P%ZO$r$ca$t$ca~P/eO$t'QO~O$r'RO$t!Ya~O$t!Ya~P%ZO#k#iq#p#iq#r#iq~P/eO$t'SO~P/eO$n'WO~Ok#XOt#XOu#XOv#XOw#XOx#XOy#XO{#WO}qO!P#ZO!Q#ZO!S#[O!T#[O!U#[O!X#]O#a#_Ofmiomi~Or#VO~P!-qOrmi~P!-qO!S#[O!T#[O!U#[Ofmikmiomirmitmiumivmiwmixmiymi{mi}mi!Xmi#ami~O!P#ZO!Q#ZO~P!/ZO!Pmi!Qmi~P!/ZOTli`li#Tli#cli#hli#uli#vli#yli#{li$Qli$Tli$Vli$rli$tli~P/eO`!by!^!by!d!by!f!by!h!by!j!by!l!by!o!by!v!by!y!by#O!by#R!by#[!by$j!by$y!by$t!by~P/eO$t!Yi~P%ZOk'ZO~O$t'^O~O$t'aO~OP!T!S!Q~",
1324
+ goto: "H}${PPP$|%QPP%U&n&r&u&xP&{'T'ZP'hP'hP'kP'}(mP(yP&{)P)VP)m*lP+UPPPPPP+pP,^P.RPP.oPPP)m/_P0P0]0w1UP1f1f1k2o2sP2sP2sP2sP2sP0w2wP3UP3[3m0w3xP0w4VP4dP0w4jP0w4wP5UP5^P5^P0w5aP5nP)m5qP6]P7l8o7l9rP:u:{P;RP;U;[P;`P7l;jPP<m=pP=pP<m>s>s?vP7l@yPA|P1p)P)PP$|$|BPPBTBZCmCsC}D^DdDrDxESPPPPPEYE^EdPGkPGt7l>s)mPHyTcOdT`OdUjR!z$O#Q!WTfgrw|!]!`#O#R#a#b#c#d#e#l#n#v#x$U$Z$j$p$s%S%Y%[%_%a%b%c%k%o%p%}&O&P&Q&R&W&^&`&e&r'O'R'WQ!d`Q!ebQ%y$}S'T&o'[R'_'ZT%Q#v%SR%u${R&n%uR&m%uS%Q#v%ST%W#x%YX$}#v#x%S%YS!zn!}Q$O!{X$|#v#x%S%YR%x$|Q!pjQ!slQ#gxQ#w!dQ&S%OR&p%yQ!ojQ!rlQ#fxQ#z!pQ#|!sQ$c#gW%T#v#x%S%YQ&z&SR'V&pQ%[#}Q&^%]Q&o%yR'['VQ'U&oR'`'[X%P#v#x%S%Yr#ax!h!i#Q#h$Q$k$m%d%i%n&]&b&h&j&{&}R%}%O!y![Tfgrw|!]!`#O#R#a#b#c#d#e#l#n$U$Z$j$p$s%[%_%a%b%c%k%o%p%}&O&P&Q&R&W&^&`&e&r'O'R'Wv#bx!h!i#Q#h$Q$^$k$m%d%i%n&]&b&h&j&u&{&}R&O%Oz#cx!h!i#Q#h$Q$^$_$k$m%d%i%n&]&b&h&j&u&v&{&}R&P%O|#Xx!h!i#Q#h$Q$^$_$k$m%O%d%i%n&]&b&h&j&u&v&{&}T$X#Y%z#QzTfgrw|!]!`#O#R#a#b#c#d#e#l#n#v#x$U$Z$j$p$s%S%Y%[%_%a%b%c%k%o%p%}&O&P&Q&R&W&^&`&e&r'O'R'Wz#Yx!h!i#Q#h$Q$^$_$k$m%d%i%n&]&b&h&j&u&v&{&}Q$]#`Q%z%OR&t%|!O#dx!h!i#Q#h$Q$^$_$`$k$m%d%i%n&]&b&h&j&u&v&w&{&}R&Q%O!S#ex!h!i#Q#h$Q$^$_$`$a$k$m%d%i%n&]&b&h&j&u&v&w&x&{&}R&R%Oz#^x!h!i#Q#h$Q$^$_$k$m%d%i%n&]&b&h&j&u&v&{&}Q$Y#YQ%{%OR&q%zQ%e$ZQ&c%cQ'X&rR']'WSeOdS!qkrQ$l#mQ%e$ZQ&X%UQ&c%cQ'X&rR']'Wg^O_dkr#m$Z%U%c&r'WfRO_dkr#m$Z%U%c&r'WR%o$rVmR!z$OUlR!z$O!y!ZTfgrw|!]!`#O#R#a#b#c#d#e#l#n$U$Z$j$p$s%[%_%a%b%c%k%o%p%}&O&P&Q&R&W&^&`&e&r'O'R'WT!|n!}T!{n!}gTO_dkr#m$Z%U%c&r'WQwTR$p#nQvTQ#TwQ#q!`]$T#R$U$s%a%b%pcuTw!`#R$U$s%a%b%pgfO_dkr#m$Z%U%c&r'WgWO_dkr#m$Z%U%c&r'WQ!`WR!aZggO_dkr#m$Z%U%c&r'WgZO_dkr#m$Z%U%c&r'WQ#s!aV%q$x%r&kR$w#rg]O_dkr#m$Z%U%c&r'WR#u!bz#`x!h!i#Q#h$Q$^$_$k$m%d%i%n&]&b&h&j&u&v&{&}R%|%O#Q!STfgrw|!]!`#O#R#a#b#c#d#e#l#n#v#x$U$Z$j$p$s%S%Y%[%_%a%b%c%k%o%p%}&O&P&Q&R&W&^&`&e&r'O'R'WQ$[#`Q%f$]Q&s%|R'Y&t#R!YTfgrw|!]!`#O#R#a#b#c#d#e#l#n#v#x$U$Z$j$p$s%S%Y%[%_%a%b%c%k%o%p%}&O&P&Q&R&W&^&`&e&r'O'R'W#R!]Tfgrw|!]!`#O#R#a#b#c#d#e#l#n#v#x$U$Z$j$p$s%S%Y%[%_%a%b%c%k%o%p%}&O&P&Q&R&W&^&`&e&r'O'R'W#R|Tfgrw|!]!`#O#R#a#b#c#d#e#l#n#v#x$U$Z$j$p$s%S%Y%[%_%a%b%c%k%o%p%}&O&P&Q&R&W&^&`&e&r'O'R'WX#j|#h#k$dX#l|#h#k$dR%k$kQ$i#kR%h$dT$j#k$dQ$h#kS%g$d$iR&g%h#R!OTfgrw|!]!`#O#R#a#b#c#d#e#l#n#v#x$U$Z$j$p$s%S%Y%[%_%a%b%c%k%o%p%}&O&P&Q&R&W&^&`&e&r'O'R'W#R!TTfgrw|!]!`#O#R#a#b#c#d#e#l#n#v#x$U$Z$j$p$s%S%Y%[%_%a%b%c%k%o%p%}&O&P&Q&R&W&^&`&e&r'O'R'W#R!RTfgrw|!]!`#O#R#a#b#c#d#e#l#n#v#x$U$Z$j$p$s%S%Y%[%_%a%b%c%k%o%p%}&O&P&Q&R&W&^&`&e&r'O'R'W#R!WTfgrw|!]!`#O#R#a#b#c#d#e#l#n#v#x$U$Z$j$p$s%S%Y%[%_%a%b%c%k%o%p%}&O&P&Q&R&W&^&`&e&r'O'R'W#R!VTfgrw|!]!`#O#R#a#b#c#d#e#l#n#v#x$U$Z$j$p$s%S%Y%[%_%a%b%c%k%o%p%}&O&P&Q&R&W&^&`&e&r'O'R'W#R!^Tfgrw|!]!`#O#R#a#b#c#d#e#l#n#v#x$U$Z$j$p$s%S%Y%[%_%a%b%c%k%o%p%}&O&P&Q&R&W&^&`&e&r'O'R'WR$r#pTbOdQdOR!gd#QiR`bfgr|!]!z#O#a#b#c#d#e#l#n#v#x$O$Z$j$p$}%S%Y%[%_%c%k%o%}&O&P&Q&R&W&^&`&e&o&r'O'R'W'Z'[bpTw!`#R$U$s%a%b%pT!lipQ%S#vR&U%SQ%^$QS&_%^&dR&d%dd_Odkr#m$Z%U%c&r'WR!c_Q!}nR$P!}Q#SvU$V#S$W$tQ$W#TR$t#qQ$y#sR%s$yQ#k|Q$d#hT$e#k$dQ%Y#xR&Z%YT%R#v%SX%O#v#x%S%YbxTw!`#R$U$s%a%b%pQ!hfQ!igQ#QrQ#h|Q#o!]Q$Q#OQ$^#aQ$_#bQ$`#cQ$a#dQ$b#eQ$k#lQ$m#nW%d$Z%c&r'WQ%i$jQ%n$pQ&]%[Y&b%_&`&e'O'RQ&h%kQ&j%oQ&u%}Q&v&OQ&w&PQ&x&QQ&y&RQ&{&WR&}&^QnRQ#}!zR%]$O!x![Tfgrw|!]!`#O#R#a#b#c#d#e#l#n$U$Z$j$p$s%[%_%a%b%c%k%o%p%}&O&P&Q&R&W&^&`&e&r'O'R'WX%P#v#x%S%YT%X#x%Y",
1325
+ nodeNames: "\u26A0 Comment Program TableStatement Kw Identifier table Ref ColumnDef DataType PrimaryKey Kw primary_key JoinDef JoinType Kw join Kw one Kw many Kw as Alias Kw on BinaryExpression = ComputedDef BinaryExpression Kw or BinaryExpression Kw and ComparisonOp != <> < > <= >= Kw like Kw not AddOp + - MulOp * / % InExpression Kw in InValueList QueryStatement FromClause Kw from TableName Subquery SubqueryExpression JoinClause Kw inner Kw left Kw right Kw full Kw cross SelectClause Kw select Kw distinct SelectItem Wildcard WhereClause Kw where GroupByClause Kw group Kw by HavingClause Kw having OrderByClause Kw order OrderItem Number Kw asc Kw desc LimitClause Kw limit Kw offset NullTestExpression Kw is Kw null UnaryExpression UnaryOperator CaseExpression Kw case WhenClause Kw when Kw then ElseClause Kw else Kw end ExistsExpression Kw exists String Boolean Kw true Kw false Null FunctionCall Count Kw count ExtractExpression Kw extract ExtractUnit Param Parenthetical InExpression NullTestExpression : ViewStatement ExtendStatement Kw extend",
1276
1326
  maxTerm: 180,
1277
1327
  nodeProps: [
1278
- ["group", -9, 25, 29, 32, 53, 63, 107, 146, 147, 148, "Expression", -12, 26, 97, 112, 114, 127, 130, 131, 136, 137, 138, 141, 145, "Expression Expression", -2, 61, 62, "TablePrimary"]
1328
+ ["group", -12, 7, 97, 112, 114, 127, 130, 131, 136, 137, 138, 141, 145, "Expression Expression", -9, 26, 29, 32, 53, 63, 107, 146, 147, 148, "Expression", -2, 61, 62, "TablePrimary"]
1279
1329
  ],
1280
1330
  skippedNodes: [0, 1],
1281
1331
  repeatNodeCount: 10,
1282
- tokenData: "*o~RoX^#Spq#Sqr#wrs$Stu$quv%cwx%hxy&Qyz&Vz{&[{|&a|}&f}!O&k!O!P'[!P!Q'a!Q![(p![!])Z!]!^)`!^!_)e!_!`)z!`!a*P!c!}*^#T#o*^#y#z#S$f$g#S#BY#BZ#S$IS$I_#S$I|$JO#S$JT$JU#S$KV$KW#S&FU&FV#S~#XY$l~X^#Spq#S#y#z#S$f$g#S#BY#BZ#S$IS$I_#S$I|$JO#S$JT$JU#S$KV$KW#S&FU&FV#S~#zP!_!`#}~$SOt~~$VTOr$Srs$fs;'S$S;'S;=`$k<%lO$S~$kO#v~~$nP;=`<%l$S~$tS!Q![%Q!c!}%Q#R#S%Q#T#o%Q~%VS$V~!Q![%Q!c!}%Q#R#S%Q#T#o%Q~%hO!U~~%kTOw%hwx$fx;'S%h;'S;=`%z<%lO%h~%}P;=`<%l%h~&VO$m~~&[O$t~~&aO!S~~&fO!P~~&kO$r~~&pP!Q~}!O&s~&xSP~OY&sZ;'S&s;'S;=`'U<%lO&s~'XP;=`<%l&s~'aO$o~~'fP!T~z{'i~'lTOz'iz{'{{;'S'i;'S;=`(j<%lO'i~(OVOz'iz{'{{!P'i!P!Q(e!Q;'S'i;'S;=`(j<%lO'i~(jOP~~(mP;=`<%l'i~(uQ#T~!O!P({!Q![(p~)OP!Q![)R~)WP#T~!Q![)R~)`O$Z~~)eO$y~~)jQv~!_!`)p!`!a)u~)uOx~~)zOu~~*POk~~*UPw~!_!`*X~*^Oy~~*cST~!Q![*^!c!}*^#R#S*^#T#o*^",
1332
+ tokenData: "*o~RoX^#Spq#Sqr#wrs$Stu$quv%cwx%hxy&Qyz&Vz{&[{|&a|}&f}!O&k!O!P'[!P!Q'a!Q![(p![!])Z!]!^)`!^!_)e!_!`)z!`!a*P!c!}*^#T#o*^#y#z#S$f$g#S#BY#BZ#S$IS$I_#S$I|$JO#S$JT$JU#S$KV$KW#S&FU&FV#S~#XY$l~X^#Spq#S#y#z#S$f$g#S#BY#BZ#S$IS$I_#S$I|$JO#S$JT$JU#S$KV$KW#S&FU&FV#S~#zP!_!`#}~$SOt~~$VTOr$Srs$fs;'S$S;'S;=`$k<%lO$S~$kO#v~~$nP;=`<%l$S~$tS!Q![%Q!c!}%Q#R#S%Q#T#o%Q~%VS$V~!Q![%Q!c!}%Q#R#S%Q#T#o%Q~%hO!U~~%kTOw%hwx$fx;'S%h;'S;=`%z<%lO%h~%}P;=`<%l%h~&VO$n~~&[O$t~~&aO!S~~&fO!P~~&kO$r~~&pP!Q~}!O&s~&xSP~OY&sZ;'S&s;'S;=`'U<%lO&s~'XP;=`<%l&s~'aO$m~~'fP!T~z{'i~'lTOz'iz{'{{;'S'i;'S;=`(j<%lO'i~(OVOz'iz{'{{!P'i!P!Q(e!Q;'S'i;'S;=`(j<%lO'i~(jOP~~(mP;=`<%l'i~(uQ#T~!O!P({!Q![(p~)OP!Q![)R~)WP#T~!Q![)R~)`O$Z~~)eO$y~~)jQv~!_!`)p!`!a)u~)uOx~~)zOu~~*POk~~*UPw~!_!`*X~*^Oy~~*cST~!Q![*^!c!}*^#R#S*^#T#o*^",
1283
1333
  tokenizers: [0],
1284
1334
  topRules: { "Program": [0, 2] },
1285
1335
  specialized: [{ term: 5, get: (value, stack) => specializeIdentifier(value, stack) << 1, external: specializeIdentifier }, { term: 5, get: (value) => spec_Identifier[value] || -1 }],
1286
- tokenPrec: 2957
1336
+ tokenPrec: 2964
1287
1337
  });
1288
1338
  }
1289
1339
  });
@@ -1535,7 +1585,7 @@ function getDiagnostics() {
1535
1585
  return diagnostics;
1536
1586
  }
1537
1587
  async function loadWorkspace(dir, includeMd) {
1538
- let files = await glob(includeMd ? "**/*.{gsql,md}" : "**/*.gsql", { cwd: dir, ignore: ["node_modules/**"] });
1588
+ let files = await glob(includeMd ? "**/*.{gsql,md}" : "**/*.gsql", { cwd: dir, ignore: ["node_modules/**"], follow: false });
1539
1589
  for await (let file of files) {
1540
1590
  try {
1541
1591
  let contents = await readFile(path2.join(dir, file), "utf-8");
@@ -1586,10 +1636,16 @@ function toSql(query, params = {}) {
1586
1636
  query = structuredClone(query);
1587
1637
  fillInParams(query, params);
1588
1638
  if (config.dialect == "snowflake") uppercaseMalloyQuery(query);
1589
- let tableQueries = Object.values(contents).map((t) => t.query);
1590
- let joinQueries = Object.values(contents).flatMap((t) => t.fields.map((f) => f.query));
1591
- let allQueries = [...tableQueries, ...joinQueries, query].filter((q) => !!q);
1592
- allQueries.forEach((q) => q.structRef = contents[q.baseTableName]);
1639
+ let visited = /* @__PURE__ */ new Set();
1640
+ function setStructRefs(obj) {
1641
+ if (!obj || typeof obj !== "object" || visited.has(obj)) return;
1642
+ visited.add(obj);
1643
+ if (obj.baseTableName && obj.pipeline) obj.structRef = contents[obj.baseTableName];
1644
+ if (obj.query) setStructRefs(obj.query);
1645
+ if (obj.fields) for (let f of obj.fields) setStructRefs(f);
1646
+ }
1647
+ Object.values(contents).forEach(setStructRefs);
1648
+ setStructRefs(query);
1593
1649
  let qm = new QueryModel({
1594
1650
  name: "generated_model",
1595
1651
  contents,
@@ -1607,7 +1663,7 @@ var init_core = __esm({
1607
1663
  init_params();
1608
1664
  init_util();
1609
1665
  init_config();
1610
- init_functions();
1666
+ init_functionDefs();
1611
1667
  init_parser();
1612
1668
  init_markdown();
1613
1669
  init_snowflake();
@@ -1848,6 +1904,9 @@ async function check(options) {
1848
1904
  log("No errors found \u{1F48E}");
1849
1905
  return true;
1850
1906
  }
1907
+ if (process.env.NODE_ENV == "test" && mdFile) {
1908
+ delete FILE_MAP[mdFile];
1909
+ }
1851
1910
  let host = `http://localhost:${config.port || Number(process.env.GRAPHENE_PORT) || 4e3}`;
1852
1911
  let pageUrl = "/" + mdFile.replace(/\.md$/, "").replace(/^\//, "").replace(/\\/g, "/");
1853
1912
  if (pageUrl === "/index") pageUrl = "/";
@@ -1998,6 +2057,7 @@ var init_check = __esm({
1998
2057
  init_mockFiles();
1999
2058
  init_background();
2000
2059
  init_util();
2060
+ init_analyze();
2001
2061
  browserConnections = [];
2002
2062
  pendingRequests = {};
2003
2063
  }
@@ -2167,6 +2227,10 @@ __export(bigQuery_exports, {
2167
2227
  BigQueryConnection: () => BigQueryConnection
2168
2228
  });
2169
2229
  import { BigQuery, BigQueryDate, BigQueryTimestamp } from "@google-cloud/bigquery";
2230
+ import { readFileSync as readFileSync3 } from "fs";
2231
+ function sqlStringLiteral(value) {
2232
+ return `'${value.replace(/'/g, "''")}'`;
2233
+ }
2170
2234
  var BigQueryConnection;
2171
2235
  var init_bigQuery = __esm({
2172
2236
  "connections/bigQuery.ts"() {
@@ -2174,6 +2238,8 @@ var init_bigQuery = __esm({
2174
2238
  init_config();
2175
2239
  BigQueryConnection = class {
2176
2240
  client;
2241
+ projectId;
2242
+ defaultNamespace;
2177
2243
  constructor(options = {}) {
2178
2244
  options.projectId ||= config.bigquery?.projectId;
2179
2245
  if (process.env.GOOGLE_CREDENTIALS_CONTENT) {
@@ -2181,8 +2247,14 @@ var init_bigQuery = __esm({
2181
2247
  options.projectId = parsed.project_id;
2182
2248
  options.credentials = parsed;
2183
2249
  }
2250
+ if (process.env.GOOGLE_APPLICATION_CREDENTIALS) {
2251
+ let tmp = JSON.parse(readFileSync3(process.env.GOOGLE_APPLICATION_CREDENTIALS, { encoding: "utf-8" }));
2252
+ options.projectId = tmp.project_id;
2253
+ }
2184
2254
  if (!options.projectId) throw new Error("projectId must be set in config or provided in service account credentials");
2255
+ this.projectId = options.projectId;
2185
2256
  this.client = new BigQuery({ ...options, userAgent: "Graphene" });
2257
+ this.defaultNamespace = config.namespace;
2186
2258
  }
2187
2259
  async runQuery(sql) {
2188
2260
  let [job] = await this.client.createQueryJob({ query: sql, useLegacySql: false });
@@ -2197,6 +2269,32 @@ var init_bigQuery = __esm({
2197
2269
  });
2198
2270
  return { rows, totalRows };
2199
2271
  }
2272
+ async listDatasets() {
2273
+ let [datasets] = await this.client.getDatasets();
2274
+ return datasets.map((d) => d.id || d.metadata.datasetReference?.datasetId);
2275
+ }
2276
+ async listTables(dataset) {
2277
+ if (!dataset) throw new Error("BigQuery requires a dataset");
2278
+ let res = await this.runQuery(`select table_schema as table_schema, table_name as table_name
2279
+ from \`${dataset}.INFORMATION_SCHEMA.TABLES\`
2280
+ where table_type in ('BASE TABLE', 'VIEW') order by table_name`);
2281
+ return res.rows.map((r) => `${r["table_schema"]}.${r["table_name"]}`);
2282
+ }
2283
+ async describeTable(target) {
2284
+ let parts = target.split(".");
2285
+ let table2 = parts.pop() || "";
2286
+ let dataset = parts.join(".");
2287
+ let sql = `
2288
+ select column_name as column_name, data_type as data_type, ordinal_position as ordinal_position
2289
+ from \`${dataset}.INFORMATION_SCHEMA.COLUMNS\`
2290
+ where lower(table_name) = lower(${sqlStringLiteral(table2)})
2291
+ order by ordinal_position
2292
+ `.trim();
2293
+ let res = await this.runQuery(sql);
2294
+ return res.rows.map((row) => {
2295
+ return { name: String(row["column_name"]), dataType: String(row["data_type"]) };
2296
+ });
2297
+ }
2200
2298
  };
2201
2299
  }
2202
2300
  });
@@ -2209,6 +2307,9 @@ __export(duckdb_exports, {
2209
2307
  import { promises as fs5 } from "fs";
2210
2308
  import path6 from "path";
2211
2309
  import { DuckDBTimestampValue, DuckDBInstance, DuckDBDateValue } from "@duckdb/node-api";
2310
+ function sqlStringLiteral2(value) {
2311
+ return `'${value.replace(/'/g, "''")}'`;
2312
+ }
2212
2313
  var DuckDBConnection;
2213
2314
  var init_duckdb = __esm({
2214
2315
  "connections/duckdb.ts"() {
@@ -2253,6 +2354,35 @@ var init_duckdb = __esm({
2253
2354
  });
2254
2355
  return { rows };
2255
2356
  }
2357
+ async listDatasets() {
2358
+ return await Promise.resolve([]);
2359
+ }
2360
+ async listTables() {
2361
+ let sql = `
2362
+ select table_schema as table_schema, table_name as table_name
2363
+ from information_schema.tables
2364
+ where table_type in ('BASE TABLE', 'VIEW') and table_schema not in ('information_schema', 'pg_catalog')
2365
+ order by table_schema, table_name
2366
+ `.trim();
2367
+ let res = await this.runQuery(sql);
2368
+ return res.rows.map((row) => String(row["table_name"]));
2369
+ }
2370
+ async describeTable(target) {
2371
+ let parts = target.split(".");
2372
+ let table2 = parts.pop() || "";
2373
+ let schema = parts[0];
2374
+ let schemaFilter = schema ? `lower(table_schema) = lower(${sqlStringLiteral2(schema)})` : "table_schema not in ('information_schema', 'pg_catalog')";
2375
+ let sql = `
2376
+ select column_name as column_name, data_type as data_type, ordinal_position as ordinal_position
2377
+ from information_schema.columns
2378
+ where lower(table_name) = lower(${sqlStringLiteral2(table2)}) and ${schemaFilter}
2379
+ order by ordinal_position
2380
+ `.trim();
2381
+ let res = await this.runQuery(sql);
2382
+ return res.rows.map((row) => {
2383
+ return { name: String(row["column_name"]), dataType: String(row["data_type"]) };
2384
+ });
2385
+ }
2256
2386
  };
2257
2387
  }
2258
2388
  });
@@ -2264,6 +2394,13 @@ __export(snowflake_exports, {
2264
2394
  });
2265
2395
  import { createPrivateKey } from "node:crypto";
2266
2396
  import snowflake from "snowflake-sdk";
2397
+ function snowflakeIdent(value) {
2398
+ if (!value) throw new Error("Snowflake identifiers cannot be empty");
2399
+ return `"${value.replace(/"/g, '""')}"`;
2400
+ }
2401
+ function sqlStringLiteral3(value) {
2402
+ return `'${value.replace(/'/g, "''")}'`;
2403
+ }
2267
2404
  var SnowflakeConnection;
2268
2405
  var init_snowflake2 = __esm({
2269
2406
  "connections/snowflake.ts"() {
@@ -2324,36 +2461,68 @@ var init_snowflake2 = __esm({
2324
2461
  });
2325
2462
  });
2326
2463
  }
2464
+ async listDatasets() {
2465
+ let res = await this.runQuery("show databases");
2466
+ return res.rows.map((row) => String(row["name"] || ""));
2467
+ }
2468
+ async listTables(dataset) {
2469
+ let parts = dataset.split(".");
2470
+ let database = parts.shift() || "";
2471
+ let schema = parts.join(".");
2472
+ let res = await this.runQuery(`
2473
+ select table_schema as "table_schema", table_name as "table_name"
2474
+ from ${snowflakeIdent(database)}.INFORMATION_SCHEMA.TABLES
2475
+ where table_type in ('BASE TABLE', 'VIEW') and table_schema = ${sqlStringLiteral3(schema)}
2476
+ order by table_name
2477
+ `);
2478
+ return res.rows.map((row) => `${row["table_schema"]}.${row["table_name"]}`);
2479
+ }
2480
+ async describeTable(target) {
2481
+ let parts = target.split(".");
2482
+ let database = parts.shift() || "";
2483
+ let table2 = parts.pop() || "";
2484
+ let schema = parts.join(".");
2485
+ let res = await this.runQuery(`
2486
+ select column_name as "column_name", data_type as "data_type", ordinal_position as ordinal_position
2487
+ from ${snowflakeIdent(database)}.INFORMATION_SCHEMA.COLUMNS
2488
+ where upper(table_schema) = upper(${sqlStringLiteral3(schema)}) and upper(table_name) = upper(${sqlStringLiteral3(table2)})
2489
+ order by ordinal_position
2490
+ `);
2491
+ return res.rows.map((row) => {
2492
+ return { name: String(row["column_name"]), dataType: String(row["data_type"]) };
2493
+ });
2494
+ }
2327
2495
  };
2328
2496
  }
2329
2497
  });
2330
2498
 
2331
2499
  // connections/index.ts
2332
- async function runQuery(sql) {
2333
- if (config.host) {
2334
- let resp = await authenticatedFetch("/_api/query", {
2335
- method: "POST",
2336
- headers: { "Content-Type": "application/json" },
2337
- body: JSON.stringify({ sql })
2338
- });
2339
- return await resp.json();
2340
- }
2500
+ async function getConnection() {
2341
2501
  if (config.dialect === "bigquery") {
2342
2502
  let mod = await Promise.resolve().then(() => (init_bigQuery(), bigQuery_exports));
2343
- let conn = new mod.BigQueryConnection();
2344
- return await conn.runQuery(sql);
2503
+ return new mod.BigQueryConnection();
2345
2504
  } else if (config.dialect === "duckdb") {
2346
2505
  let mod = await Promise.resolve().then(() => (init_duckdb(), duckdb_exports));
2347
- let conn = new mod.DuckDBConnection({});
2348
- return await conn.runQuery(sql);
2506
+ return new mod.DuckDBConnection({});
2349
2507
  } else if (config.dialect === "snowflake") {
2350
2508
  let mod = await Promise.resolve().then(() => (init_snowflake2(), snowflake_exports));
2351
- let conn = new mod.SnowflakeConnection({});
2352
- return await conn.runQuery(sql);
2509
+ return new mod.SnowflakeConnection({});
2353
2510
  } else {
2354
2511
  throw new Error(`Unsupported dialect: ${config.dialect}`);
2355
2512
  }
2356
2513
  }
2514
+ async function runQuery(sql) {
2515
+ if (config.host) {
2516
+ let resp = await authenticatedFetch("/_api/query", {
2517
+ method: "POST",
2518
+ headers: { "Content-Type": "application/json" },
2519
+ body: JSON.stringify({ sql })
2520
+ });
2521
+ return await resp.json();
2522
+ }
2523
+ let conn = await getConnection();
2524
+ return await conn.runQuery(sql);
2525
+ }
2357
2526
  var init_connections = __esm({
2358
2527
  "connections/index.ts"() {
2359
2528
  "use strict";
@@ -2456,20 +2625,28 @@ var init_mdCompile = __esm({
2456
2625
  // serve2.ts
2457
2626
  var serve2_exports = {};
2458
2627
  __export(serve2_exports, {
2628
+ prepareDeps: () => prepareDeps,
2459
2629
  serve2: () => serve2
2460
2630
  });
2461
- import { createServer, optimizeDeps } from "vite";
2631
+ import { createServer, optimizeDeps, resolveConfig } from "vite";
2462
2632
  import { svelte, vitePreprocess } from "@sveltejs/vite-plugin-svelte";
2463
2633
  import fs7 from "fs-extra";
2634
+ import { glob as glob2 } from "glob";
2464
2635
  import crypto2 from "crypto";
2465
2636
  import { mdsvex } from "mdsvex";
2466
2637
  import path8 from "path";
2467
2638
  import { fileURLToPath as fileURLToPath2 } from "url";
2468
2639
  async function serve2() {
2640
+ let server = await createServer(await createConfig());
2641
+ await server.listen();
2642
+ console.log(`Server running at http://localhost:${server.config.server.port}`);
2643
+ return server;
2644
+ }
2645
+ async function createConfig() {
2469
2646
  uiRoot = path8.join(fileURLToPath2(import.meta.url), "../../ui");
2470
2647
  let port = Number(process.env.GRAPHENE_PORT) || 4e3;
2471
2648
  await fs7.ensureDir(path8.resolve(config.root, "node_modules/.graphene"));
2472
- let server = await createServer({
2649
+ return {
2473
2650
  root: config.root,
2474
2651
  plugins: [
2475
2652
  svelte({
@@ -2484,12 +2661,15 @@ async function serve2() {
2484
2661
  injectComponentImports()
2485
2662
  ]
2486
2663
  }),
2664
+ fixSvelteDepsInTests(),
2487
2665
  checkVitePlugin(),
2488
2666
  handleRequestPlugin,
2489
2667
  updateWorkspacePlugin,
2490
2668
  mockFilesForTests()
2491
2669
  ],
2492
- publicDir: path8.resolve(uiRoot),
2670
+ publicDir: path8.resolve(uiRoot, "public"),
2671
+ // on the fence about this one. This would make it less likely we need to optimize when alternating between dev and tests.
2672
+ // cacheDir: process.env.NODE_ENV == 'test' ? 'node_modules/.vite-tests' : 'node_modules/.vite',
2493
2673
  server: {
2494
2674
  port,
2495
2675
  fs: { strict: false },
@@ -2499,16 +2679,38 @@ async function serve2() {
2499
2679
  alias: {
2500
2680
  graphene: path8.resolve(uiRoot, "web.js")
2501
2681
  }
2682
+ },
2683
+ // vite's pre-bundling won't naturally discover these dependencies since they're transitive.
2684
+ // Instead, we need to list them out here so vite knows where they are.
2685
+ optimizeDeps: {
2686
+ noDiscovery: process.env.NODE_ENV == "test",
2687
+ // tests manually optimize before starting test workers
2688
+ include: [
2689
+ "@graphenedata/cli > svelte",
2690
+ "@graphenedata/cli > ssf",
2691
+ "@graphenedata/cli > @tidyjs/tidy",
2692
+ "@graphenedata/cli > chroma-js",
2693
+ "@graphenedata/cli > echarts/dist/echarts.esm.js",
2694
+ "@graphenedata/cli > @graphenedata/html2canvas"
2695
+ ]
2502
2696
  }
2503
- // optimizeDeps: { // this seems prudent in tests, but currently breaks because ssf needs to be optimized, even in tests
2504
- // noDiscovery: process.env.NODE_ENV == 'test',
2505
- // include: process.env.NODE_ENV == 'test' ? [] : undefined,
2506
- // },
2507
- });
2508
- await optimizeDeps(server.config);
2509
- await server.listen();
2510
- console.log(`Server running at http://localhost:${port}`);
2511
- return server;
2697
+ };
2698
+ }
2699
+ async function prepareDeps() {
2700
+ let cfg = await resolveConfig(await createConfig(), "serve");
2701
+ await optimizeDeps(cfg, true);
2702
+ }
2703
+ function fixSvelteDepsInTests() {
2704
+ let viteConfig;
2705
+ function configResolved(cfg) {
2706
+ viteConfig = cfg;
2707
+ }
2708
+ function buildStart() {
2709
+ if (process.env.NODE_ENV != "test") return;
2710
+ viteConfig.optimizeDeps.force = false;
2711
+ }
2712
+ buildStart.sequential = true;
2713
+ return { name: "fix-svelte-deps", enforce: "pre", sequential: true, configResolved, buildStart };
2512
2714
  }
2513
2715
  async function handleQuery(req, res) {
2514
2716
  let chunks = [];
@@ -2539,7 +2741,7 @@ async function handleQuery(req, res) {
2539
2741
  async function handlePage(server, res, filePath, mount) {
2540
2742
  res.setHeader("Content-Type", "text/html");
2541
2743
  let mdMount = mount ? `
2542
- import Page from ${JSON.stringify(filePath)};
2744
+ import Page from ${JSON.stringify(filePath)}
2543
2745
  new Page({ target: document.getElementById('content'), props: {} })
2544
2746
  ` : "";
2545
2747
  let html = await server.transformIndexHtml(filePath, `<!doctype html>
@@ -2548,15 +2750,11 @@ async function handlePage(server, res, filePath, mount) {
2548
2750
  <meta charset="UTF-8" />
2549
2751
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
2550
2752
  <title>Graphene</title>
2551
- <link rel="icon" href="/assets/favicon.ico" />
2552
- <link rel="preconnect" href="https://fonts.googleapis.com">
2553
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
2554
- <link href="https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap" rel="stylesheet">
2753
+ <link rel="icon" href="/favicon.ico" />
2555
2754
  </head>
2556
2755
  <body>
2557
- <main>
2558
- <div id="content"></div>
2559
- </main>
2756
+ <nav id="nav"></nav>
2757
+ <main id="content"></main>
2560
2758
  <script type="module">
2561
2759
  import 'graphene' // do this first so we can track errors caused by importing the md file
2562
2760
  ${mdMount}
@@ -2575,11 +2773,12 @@ function mockFilesForTests() {
2575
2773
  },
2576
2774
  load(id) {
2577
2775
  if (!id.endsWith("?mock")) return null;
2578
- return mockFileMap[id.replace(config.root + "/", "").replace(/\?mock$/, "")];
2776
+ let content = mockFileMap[id.replace(config.root + "/", "").replace(/\?mock$/, "")];
2777
+ return content;
2579
2778
  }
2580
2779
  };
2581
2780
  }
2582
- var uiRoot, workspaceLoadPromise, updateWorkspacePlugin, handleRequestPlugin;
2781
+ var uiRoot, workspaceLoadPromise, mdFiles, updateWorkspacePlugin, handleRequestPlugin;
2583
2782
  var init_serve2 = __esm({
2584
2783
  "serve2.ts"() {
2585
2784
  "use strict";
@@ -2588,15 +2787,38 @@ var init_serve2 = __esm({
2588
2787
  init_mdCompile();
2589
2788
  init_check();
2590
2789
  init_mockFiles();
2790
+ mdFiles = [];
2591
2791
  updateWorkspacePlugin = {
2592
2792
  name: "updateWorkspace",
2793
+ resolveId(id) {
2794
+ if (id == "virtual:nav") return "\0virtual:nav";
2795
+ },
2796
+ load(id) {
2797
+ if (id != "\0virtual:nav") return;
2798
+ let allFiles = [...mdFiles];
2799
+ if (process.env.NODE_ENV == "test") {
2800
+ for (let key of Object.keys(mockFileMap)) {
2801
+ if (!allFiles.includes(key)) allFiles.push(key);
2802
+ }
2803
+ }
2804
+ return `export default ${JSON.stringify(allFiles)}`;
2805
+ },
2593
2806
  configureServer: (s) => {
2594
- s.watcher.add("**/*.gsql");
2595
- s.watcher.on("change", () => {
2807
+ let refresh = async () => {
2596
2808
  clearWorkspace();
2597
2809
  workspaceLoadPromise = loadWorkspace(config.root, false);
2598
- });
2599
- workspaceLoadPromise = loadWorkspace(config.root, false);
2810
+ mdFiles = await glob2("**/*.md", { cwd: config.root, ignore: ["node_modules/**"] });
2811
+ mdFiles = mdFiles.filter((f) => !config.ignoredFiles?.includes(path8.basename(f).toLowerCase()));
2812
+ if (process.env.NODE_ENV == "test") {
2813
+ mdFiles.push(...Object.keys(mockFileMap));
2814
+ }
2815
+ let mod = s.moduleGraph.getModuleById("\0virtual:nav");
2816
+ if (!mod) return;
2817
+ s.reloadModule(mod);
2818
+ };
2819
+ s.watcher.add(["**/*.gsql", "**/*.md"]);
2820
+ s.watcher.on("all", refresh);
2821
+ refresh();
2600
2822
  }
2601
2823
  };
2602
2824
  handleRequestPlugin = {
@@ -2608,14 +2830,15 @@ var init_serve2 = __esm({
2608
2830
  if (pathName == "/_api/query") return await handleQuery(req, res);
2609
2831
  if (pathName == "/__ct") return await handlePage(s, res, "__ct", false);
2610
2832
  if (!pathName || pathName == "/") pathName = "index";
2611
- let mdPath = path8.join(config.root, pathName + ".md");
2612
- if (await fs7.exists(mdPath)) {
2833
+ let relativeMdPath = pathName.replace(/^\//, "") + ".md";
2834
+ let mdPath = path8.join(config.root, relativeMdPath);
2835
+ if (mockFileMap[relativeMdPath] || await fs7.exists(mdPath)) {
2613
2836
  await handlePage(s, res, mdPath, true);
2614
2837
  } else {
2615
2838
  next();
2616
2839
  }
2617
2840
  } catch (err) {
2618
- console.error(err);
2841
+ if (process.env.NODE_ENV != "test") console.error(err);
2619
2842
  res.statusCode = 500;
2620
2843
  res.end(JSON.stringify([{ message: err.message, stack: err.stack }]));
2621
2844
  }
@@ -2636,6 +2859,8 @@ init_auth();
2636
2859
  import { Command } from "commander";
2637
2860
  import fs8 from "fs-extra";
2638
2861
  import path9 from "path";
2862
+ import dotenv from "dotenv";
2863
+ dotenv.config({ quiet: true });
2639
2864
  var program = new Command();
2640
2865
  program.name("graphene").description("Graphene CLI").version("1.0.0");
2641
2866
  program.hook("preAction", async () => {
@@ -2660,6 +2885,31 @@ program.command("run").description("Run a query against your database").argument
2660
2885
  let res = await runQuery(sql);
2661
2886
  printTable(res.rows);
2662
2887
  });
2888
+ program.command("schema").description("Inspect database tables or describe a table").argument("[schema | table]", "Optional schema or table name to describe").action(async (tableArg) => {
2889
+ let connection = await getConnection();
2890
+ let datasets = await connection.listDatasets();
2891
+ if (!tableArg && datasets.length > 1) {
2892
+ return console.log(`Datasets available:
2893
+ ${datasets.join("\n")}`);
2894
+ }
2895
+ let dsToList = null;
2896
+ let parts = tableArg ? tableArg.split(".") : [];
2897
+ if (datasets.includes(tableArg)) dsToList = tableArg;
2898
+ else if (!tableArg && datasets.length == 1) dsToList = datasets[0];
2899
+ else if (!tableArg && config.namespace) dsToList = config.namespace;
2900
+ else if (!tableArg && config.dialect == "duckdb") dsToList = "<default>";
2901
+ else if (tableArg && config.dialect == "snowflake" && parts.length == 2) dsToList = tableArg;
2902
+ if (dsToList) {
2903
+ let tables = await connection.listTables(dsToList);
2904
+ return console.log(`Tables${dsToList ? ` in ${dsToList}` : ""}:
2905
+ ${tables.join("\n")}`);
2906
+ }
2907
+ let cols = await connection.describeTable(tableArg);
2908
+ if (!cols.length) return console.log(`Table ${tableArg} not found`);
2909
+ console.log(`table ${tableArg} (`);
2910
+ cols.forEach((col) => console.log(` ${col.name} ${col.dataType}`));
2911
+ console.log(")");
2912
+ });
2663
2913
  program.command("serve").description("Run the local server").option("--bg", "Run the server in the background").action(async (options) => {
2664
2914
  await stopGrapheneIfRunning();
2665
2915
  if (options.bg) {