@uwdata/mosaic-inputs 0.11.0 → 0.12.1

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.
@@ -5,7 +5,8 @@ function throttle(callback, debounce = false) {
5
5
  let next;
6
6
  let pending = NIL;
7
7
  function invoke(event) {
8
- curr = callback(event).finally(() => {
8
+ curr = callback(event).catch(() => {
9
+ }).finally(() => {
9
10
  if (next) {
10
11
  const { value } = next;
11
12
  next = null;
@@ -66,11 +67,12 @@ var MosaicClient = class {
66
67
  return this._filterBy;
67
68
  }
68
69
  /**
69
- * Return a boolean indicating if the client query can be indexed. Should
70
- * return true if changes to the filterBy selection does not change the
71
- * groupby domain of the client query.
70
+ * Return a boolean indicating if the client query can be sped up with
71
+ * materialized views of pre-aggregated data. Should return true if changes to
72
+ * the filterBy selection does not change the groupby domain of the client
73
+ * query.
72
74
  */
73
- get filterIndexable() {
75
+ get filterStable() {
74
76
  return true;
75
77
  }
76
78
  /**
@@ -737,8 +739,8 @@ function toNumber(value) {
737
739
  }
738
740
  return Number(value);
739
741
  }
740
- function divide(num, div) {
741
- return Number(num / div) + Number(num % div) / Number(div);
742
+ function divide(num, div2) {
743
+ return Number(num / div2) + Number(num % div2) / Number(div2);
742
744
  }
743
745
  var asUint64 = (v) => BigInt.asUintN(64, v);
744
746
  function fromDecimal128(buf2, offset) {
@@ -1056,14 +1058,14 @@ var Float16Batch = class extends NumberBatch {
1056
1058
  );
1057
1059
  const expo = (v & 31744) >> 10;
1058
1060
  const sigf = (v & 1023) / 1024;
1059
- const sign = (-1) ** ((v & 32768) >> 15);
1061
+ const sign2 = (-1) ** ((v & 32768) >> 15);
1060
1062
  switch (expo) {
1061
1063
  case 31:
1062
- return sign * (sigf ? Number.NaN : 1 / 0);
1064
+ return sign2 * (sigf ? Number.NaN : 1 / 0);
1063
1065
  case 0:
1064
- return sign * (sigf ? 6103515625e-14 * sigf : 0);
1066
+ return sign2 * (sigf ? 6103515625e-14 * sigf : 0);
1065
1067
  }
1066
- return sign * 2 ** (expo - 15) * (1 + sigf);
1068
+ return sign2 * 2 ** (expo - 15) * (1 + sigf);
1067
1069
  }
1068
1070
  };
1069
1071
  var BoolBatch = class extends ArrayBatch {
@@ -1729,8 +1731,8 @@ var Table = class _Table {
1729
1731
  * @returns {Table} A new table with columns matching the specified names.
1730
1732
  */
1731
1733
  select(names, as) {
1732
- const all2 = this.names;
1733
- const indices = names.map((name) => all2.indexOf(name));
1734
+ const all = this.names;
1735
+ const indices = names.map((name) => all.indexOf(name));
1734
1736
  return this.selectAt(indices, as);
1735
1737
  }
1736
1738
  /**
@@ -2485,7 +2487,9 @@ function socketConnector(uri = "ws://localhost:3000/") {
2485
2487
  * Query the DuckDB server.
2486
2488
  * @param {object} query
2487
2489
  * @param {'exec' | 'arrow' | 'json' | 'create-bundle' | 'load-bundle'} [query.type] The query type.
2488
- * @param {string} query.sql A SQL query string.
2490
+ * @param {string} [query.sql] A SQL query string.
2491
+ * @param {string[]} [query.queries] The queries used to create a bundle.
2492
+ * @param {string} [query.name] The name of a bundle to create or load.
2489
2493
  * @returns the query result
2490
2494
  */
2491
2495
  query(query) {
@@ -2496,71 +2500,82 @@ function socketConnector(uri = "ws://localhost:3000/") {
2496
2500
  };
2497
2501
  }
2498
2502
 
2499
- // ../sql/src/ref.js
2500
- var Ref = class {
2503
+ // ../sql/src/constants.js
2504
+ var COLUMN_REF = "COLUMN_REF";
2505
+ var COLUMN_PARAM = "COLUMN_PARAM";
2506
+ var TABLE_REF = "TABLE_REF";
2507
+ var LITERAL = "LITERAL";
2508
+ var ORDER_BY = "ORDER_BY";
2509
+ var CAST = "CAST";
2510
+ var CASE = "CASE";
2511
+ var WHEN = "WHEN";
2512
+ var UNARY_OPERATOR = "UNARY";
2513
+ var UNARY_POSTFIX_OPERATOR = "UNARY_POSTFIX";
2514
+ var BINARY_OPERATOR = "BINARY";
2515
+ var BETWEEN_OPERATOR = "BETWEEN";
2516
+ var NOT_BETWEEN_OPERATOR = "NOT_BETWEEN";
2517
+ var LOGICAL_OPERATOR = "LOGICAL_OPERATOR";
2518
+ var IN_OPERATOR = "IN";
2519
+ var FUNCTION = "FUNCTION";
2520
+ var AGGREGATE = "AGGREGATE";
2521
+ var WINDOW = "WINDOW";
2522
+ var WINDOW_DEF = "WINDOW_DEF";
2523
+ var WINDOW_FRAME = "WINDOW_FRAME";
2524
+ var EXPRESSION = "EXPRESSION";
2525
+ var FRAGMENT = "FRAGMENT";
2526
+ var VERBATIM = "VERBATIM";
2527
+ var PARAM = "PARAM";
2528
+ var WITH_CLAUSE = "WITH_CLAUSE";
2529
+ var SELECT_CLAUSE = "SELECT_CLAUSE";
2530
+ var FROM_CLAUSE = "FROM_CLAUSE";
2531
+ var SAMPLE_CLAUSE = "SAMPLE_CLAUSE";
2532
+ var WINDOW_CLAUSE = "WINDOW_CLAUSE";
2533
+ var SELECT_QUERY = "SELECT_QUERY";
2534
+ var DESCRIBE_QUERY = "DESCRIBE_QUERY";
2535
+ var SET_OPERATION = "SET_OPERATION";
2536
+
2537
+ // ../sql/src/ast/node.js
2538
+ function isNode(value) {
2539
+ return value instanceof SQLNode;
2540
+ }
2541
+ var SQLNode = class {
2501
2542
  /**
2502
- * Create a new Ref instance.
2503
- * @param {string|Ref|null} table The table name.
2504
- * @param {string|null} [column] The column name.
2543
+ * Instantiate a SQL AST node.
2544
+ * @param {string} type The SQL AST node type.
2505
2545
  */
2506
- constructor(table2, column2) {
2507
- if (table2) this.table = String(table2);
2508
- if (column2) this.column = column2;
2546
+ constructor(type) {
2547
+ this.type = type;
2509
2548
  }
2549
+ };
2550
+ var ExprNode = class extends SQLNode {
2551
+ };
2552
+
2553
+ // ../sql/src/ast/literal.js
2554
+ var LiteralNode = class extends ExprNode {
2510
2555
  /**
2511
- * Get the list of referenced columns. Either a single element array
2512
- * if column is non-null, otherwise an empty array.
2556
+ * Instantiate an literal node.
2557
+ * @param {*} value The literal value.
2513
2558
  */
2514
- get columns() {
2515
- return this.column ? [this.column] : [];
2559
+ constructor(value) {
2560
+ super(LITERAL);
2561
+ this.value = value;
2516
2562
  }
2517
2563
  /**
2518
- * Generate a SQL string for this reference.
2519
- * @returns {string} The SQL string.
2564
+ * Generate a SQL query string for this node.
2565
+ * @returns {string}
2520
2566
  */
2521
2567
  toString() {
2522
- const { table: table2, column: column2 } = this;
2523
- if (column2) {
2524
- const col = column2.startsWith("*") ? column2 : `"${column2}"`;
2525
- return `${table2 ? `${quoteTableName(table2)}.` : ""}${col}`;
2526
- } else {
2527
- return table2 ? quoteTableName(table2) : "NULL";
2528
- }
2568
+ return literalToSQL(this.value);
2529
2569
  }
2530
2570
  };
2531
- function quoteTableName(table2) {
2532
- const pieces = table2.split(".");
2533
- return pieces.map((p) => `"${p}"`).join(".");
2534
- }
2535
- function isColumnRefFor(ref, name) {
2536
- return ref instanceof Ref && ref.column === name;
2537
- }
2538
- function asColumn(value) {
2539
- return typeof value === "string" ? column(value) : value;
2540
- }
2541
- function asRelation(value) {
2542
- return typeof value === "string" ? relation(value) : value;
2543
- }
2544
- function relation(name) {
2545
- return new Ref(name);
2546
- }
2547
- function column(table2, column2 = null) {
2548
- if (arguments.length === 1) {
2549
- column2 = table2;
2550
- table2 = null;
2551
- }
2552
- return new Ref(table2, column2);
2553
- }
2554
-
2555
- // ../sql/src/to-sql.js
2556
2571
  function literalToSQL(value) {
2557
2572
  switch (typeof value) {
2558
- case "boolean":
2559
- return value ? "TRUE" : "FALSE";
2573
+ case "number":
2574
+ return Number.isFinite(value) ? `${value}` : "NULL";
2560
2575
  case "string":
2561
2576
  return `'${value.replace(`'`, `''`)}'`;
2562
- case "number":
2563
- return Number.isFinite(value) ? String(value) : "NULL";
2577
+ case "boolean":
2578
+ return value ? "TRUE" : "FALSE";
2564
2579
  default:
2565
2580
  if (value == null) {
2566
2581
  return "NULL";
@@ -2570,1032 +2585,1681 @@ function literalToSQL(value) {
2570
2585
  const y2 = value.getUTCFullYear();
2571
2586
  const m = value.getUTCMonth();
2572
2587
  const d = value.getUTCDate();
2573
- return ts === Date.UTC(y2, m, d) ? `MAKE_DATE(${y2}, ${m + 1}, ${d})` : `EPOCH_MS(${ts})`;
2588
+ return ts === Date.UTC(y2, m, d) ? `DATE '${y2}-${m + 1}-${d}'` : `epoch_ms(${ts})`;
2574
2589
  } else if (value instanceof RegExp) {
2575
2590
  return `'${value.source}'`;
2576
2591
  } else {
2577
- return String(value);
2592
+ return `${value}`;
2578
2593
  }
2579
2594
  }
2580
2595
  }
2581
2596
 
2582
- // ../sql/src/expression.js
2583
- var isParamLike = (value) => typeof value?.addEventListener === "function";
2584
- function isSQLExpression(value) {
2585
- return value instanceof SQLExpression;
2586
- }
2587
- var SQLExpression = class {
2588
- /**
2589
- * Create a new SQL expression instance.
2590
- * @param {(string | ParamLike | SQLExpression | import('./ref.js').Ref)[]} parts The parts of the expression.
2591
- * @param {string[]} [columns=[]] The column dependencies
2592
- * @param {object} [props] Additional properties for this expression.
2593
- */
2594
- constructor(parts, columns, props) {
2595
- this._expr = Array.isArray(parts) ? parts : [parts];
2596
- this._deps = columns || [];
2597
- this.annotate(props);
2598
- const params = this._expr.filter((part) => isParamLike(part));
2599
- if (params.length > 0) {
2600
- this._params = Array.from(new Set(params));
2601
- this._params.forEach((param) => {
2602
- param.addEventListener("value", () => update(this, this.map?.get("value")));
2603
- });
2604
- } else {
2605
- this.addEventListener = void 0;
2606
- }
2597
+ // ../sql/src/ast/param.js
2598
+ var ParamNode = class extends ExprNode {
2599
+ /**
2600
+ * Instantiate a param node with a dynamic parameter.
2601
+ * @param {import('../types.js').ParamLike} param The dynamic parameter.
2602
+ */
2603
+ constructor(param) {
2604
+ super(PARAM);
2605
+ this.param = param;
2607
2606
  }
2608
2607
  /**
2609
- * A reference to this expression.
2610
- * Provides compatibility with param-like objects.
2608
+ * Returns the current parameter value.
2609
+ * @returns {*}
2611
2610
  */
2612
2611
  get value() {
2613
- return this;
2612
+ return this.param.value;
2614
2613
  }
2615
2614
  /**
2616
- * The column dependencies of this expression.
2617
- * @returns {string[]} The columns dependencies.
2618
- */
2619
- get columns() {
2620
- const { _params, _deps } = this;
2621
- if (_params) {
2622
- const pset = new Set(_params.flatMap((p) => {
2623
- const cols = p.value?.columns;
2624
- return Array.isArray(cols) ? cols : [];
2625
- }));
2626
- if (pset.size) {
2627
- const set = new Set(_deps);
2628
- pset.forEach((col) => set.add(col));
2629
- return Array.from(set);
2630
- }
2631
- }
2632
- return _deps;
2615
+ * Generate a SQL query string for this node.
2616
+ * @returns {string}
2617
+ */
2618
+ toString() {
2619
+ return literalToSQL(this.value);
2633
2620
  }
2621
+ };
2622
+
2623
+ // ../sql/src/util/string.js
2624
+ function parseIdentifier(id) {
2625
+ return id.split(".");
2626
+ }
2627
+ function quoteIdentifier(value) {
2628
+ return `"${value}"`;
2629
+ }
2630
+ function unquote(s) {
2631
+ return s && isDoubleQuoted(s) ? s.slice(1, -1) : s;
2632
+ }
2633
+ function isDoubleQuoted(s) {
2634
+ return s[0] === '"' && s[s.length - 1] === '"';
2635
+ }
2636
+
2637
+ // ../sql/src/ast/table-ref.js
2638
+ function isTableRef(value) {
2639
+ return value instanceof TableRefNode;
2640
+ }
2641
+ var TableRefNode = class extends ExprNode {
2634
2642
  /**
2635
- * The first column dependency in this expression, or undefined if none.
2636
- * @returns {string} The first column dependency.
2643
+ * Instantiate a table reference node.
2644
+ * @param {string | string[]} table The table name.
2637
2645
  */
2638
- get column() {
2639
- return this._deps.length ? this._deps[0] : this.columns[0];
2646
+ constructor(table2) {
2647
+ super(TABLE_REF);
2648
+ this.table = [table2].flat();
2640
2649
  }
2641
2650
  /**
2642
- * Annotate this expression instance with additional properties.
2643
- * @param {object[]} [props] One or more objects with properties to add.
2644
- * @returns This SQL expression.
2651
+ * The table name without database or schema namespaces.
2652
+ * @returns {string}
2645
2653
  */
2646
- annotate(...props) {
2647
- return Object.assign(this, ...props);
2654
+ get name() {
2655
+ return this.table[this.table.length - 1];
2648
2656
  }
2649
2657
  /**
2650
- * Generate a SQL code string corresponding to this expression.
2651
- * @returns {string} A SQL code string.
2658
+ * Generate a SQL query string for this node.
2659
+ * @returns {string}
2652
2660
  */
2653
2661
  toString() {
2654
- return this._expr.map((p) => isParamLike(p) && !isSQLExpression(p) ? literalToSQL(p.value) : p).join("");
2662
+ return this.table.map((t) => quoteIdentifier(t)).join(".");
2655
2663
  }
2664
+ };
2665
+
2666
+ // ../sql/src/ast/function.js
2667
+ var FunctionNode = class extends ExprNode {
2656
2668
  /**
2657
- * Add an event listener callback for the provided event type.
2658
- * @param {string} type The event type to listen for (for example, "value").
2659
- * @param {(a: SQLExpression) => Promise?} callback The callback function to
2660
- * invoke upon updates. A callback may optionally return a Promise that
2661
- * upstream listeners may await before proceeding.
2669
+ * Instantiate a function node.
2670
+ * @param {string} name The function name.
2671
+ * @param {ExprNode[]} [args=[]] The function arguments.
2662
2672
  */
2663
- addEventListener(type, callback) {
2664
- const map2 = this.map || (this.map = /* @__PURE__ */ new Map());
2665
- const set = map2.get(type) || (map2.set(type, /* @__PURE__ */ new Set()), map2.get(type));
2666
- set.add(callback);
2673
+ constructor(name, args = []) {
2674
+ super(FUNCTION);
2675
+ this.name = name;
2676
+ this.args = args;
2667
2677
  }
2668
- };
2669
- function update(expr, callbacks) {
2670
- if (callbacks?.size) {
2671
- return Promise.allSettled(Array.from(callbacks, (fn) => fn(expr)));
2678
+ /**
2679
+ * Generate a SQL query string for this node.
2680
+ * @returns {string}
2681
+ */
2682
+ toString() {
2683
+ const { name, args } = this;
2684
+ return `${name}(${args.join(", ")})`;
2672
2685
  }
2686
+ };
2687
+
2688
+ // ../sql/src/util/function.js
2689
+ function fn(name, ...args) {
2690
+ return new FunctionNode(name, argsList(args).map(asNode));
2673
2691
  }
2674
- function parseSQL(strings, exprs) {
2675
- const spans = [strings[0]];
2676
- const cols = /* @__PURE__ */ new Set();
2677
- const n = exprs.length;
2678
- for (let i = 0, k = 0; i < n; ) {
2679
- const e = exprs[i];
2680
- if (isParamLike(e)) {
2681
- spans[++k] = e;
2682
- } else {
2683
- if (Array.isArray(e?.columns)) {
2684
- e.columns.forEach((col) => cols.add(col));
2685
- }
2686
- spans[k] += typeof e === "string" ? e : literalToSQL(e);
2687
- }
2688
- const s = strings[++i];
2689
- if (isParamLike(spans[k])) {
2690
- spans[++k] = s;
2691
- } else {
2692
- spans[k] += s;
2693
- }
2694
- }
2695
- return { spans, cols: Array.from(cols) };
2692
+ function aggFn(name, ...args) {
2693
+ return new AggregateNode(name, argsList(args).map(asNode));
2696
2694
  }
2697
- function sql(strings, ...exprs) {
2698
- const { spans, cols } = parseSQL(strings, exprs);
2699
- return new SQLExpression(spans, cols);
2695
+ function exprList(list2, cast2 = asNode) {
2696
+ return list2.flat().filter((x2) => x2 != null).map((x2) => cast2(x2));
2700
2697
  }
2701
-
2702
- // ../sql/src/desc.js
2703
- function desc(expr) {
2704
- const e = asColumn(expr);
2705
- return sql`${e} DESC NULLS LAST`.annotate({ label: e?.label, desc: true });
2698
+ function argsList(list2) {
2699
+ const n = list2.length;
2700
+ let i = n;
2701
+ for (; i > 0 && list2[i - 1] === void 0; --i) ;
2702
+ return i < n ? list2.slice(0, i) : list2;
2706
2703
  }
2707
2704
 
2708
- // ../sql/src/literal.js
2709
- var literal = (value) => ({
2710
- value,
2711
- toString: () => literalToSQL(value)
2712
- });
2713
-
2714
- // ../sql/src/operators.js
2715
- function visit2(callback) {
2716
- callback(this.op, this);
2717
- this.children?.forEach((v) => v.visit(callback));
2718
- }
2719
- function logical(op, clauses) {
2720
- const children = clauses.filter((x2) => x2 != null).map(asColumn);
2721
- const strings = children.map((c, i) => i ? ` ${op} ` : "");
2722
- if (children.length === 1) {
2723
- strings.push("");
2724
- } else if (children.length > 1) {
2725
- strings[0] = "(";
2726
- strings.push(")");
2727
- }
2728
- return sql(strings, ...children).annotate({ op, children, visit: visit2 });
2729
- }
2730
- var and = (...clauses) => logical("AND", clauses.flat());
2731
- var or = (...clauses) => logical("OR", clauses.flat());
2732
- var unaryOp = (op) => (a) => sql`(${op} ${asColumn(a)})`.annotate({ op, a, visit: visit2 });
2733
- var not = unaryOp("NOT");
2734
- var unaryPostOp = (op) => (a) => sql`(${asColumn(a)} ${op})`.annotate({ op, a, visit: visit2 });
2735
- var isNull = unaryPostOp("IS NULL");
2736
- var isNotNull = unaryPostOp("IS NOT NULL");
2737
- var binaryOp = (op) => (a, b) => sql`(${asColumn(a)} ${op} ${asColumn(b)})`.annotate({ op, a, b, visit: visit2 });
2738
- var eq = binaryOp("=");
2739
- var neq = binaryOp("<>");
2740
- var lt = binaryOp("<");
2741
- var gt = binaryOp(">");
2742
- var lte = binaryOp("<=");
2743
- var gte = binaryOp(">=");
2744
- var isDistinct = binaryOp("IS DISTINCT FROM");
2745
- var isNotDistinct = binaryOp("IS NOT DISTINCT FROM");
2746
- function rangeOp(op, a, range, exclusive) {
2747
- a = asColumn(a);
2748
- const prefix2 = op.startsWith("NOT ") ? "NOT " : "";
2749
- const expr = !range ? sql`` : exclusive ? sql`${prefix2}(${range[0]} <= ${a} AND ${a} < ${range[1]})` : sql`(${a} ${op} ${range[0]} AND ${range[1]})`;
2750
- return expr.annotate({ op, visit: visit2, field: a, range });
2751
- }
2752
- var isBetween = (a, range, exclusive) => rangeOp("BETWEEN", a, range, exclusive);
2753
-
2754
- // ../sql/src/repeat.js
2755
- function repeat(length2, str) {
2756
- return Array.from({ length: length2 }, () => str);
2705
+ // ../sql/src/util/type-check.js
2706
+ function isString(value) {
2707
+ return typeof value === "string";
2757
2708
  }
2758
-
2759
- // ../sql/src/functions.js
2760
- function functionCall(op, type) {
2761
- return (...values) => {
2762
- const args = values.map(asColumn);
2763
- const cast2 = type ? `::${type}` : "";
2764
- const expr = args.length ? sql([`${op}(`, ...repeat(args.length - 1, ", "), `)${cast2}`], ...args) : sql`${op}()${cast2}`;
2765
- return expr.annotate({ func: op, args });
2766
- };
2709
+ function isArray2(value) {
2710
+ return Array.isArray(value);
2711
+ }
2712
+ function isParamLike(value) {
2713
+ return value && typeof value.addEventListener === "function" && value.dynamic !== false && "value" in value;
2767
2714
  }
2768
- var regexp_matches = functionCall("REGEXP_MATCHES");
2769
- var contains = functionCall("CONTAINS");
2770
- var prefix = functionCall("PREFIX");
2771
- var suffix = functionCall("SUFFIX");
2772
- var lower = functionCall("LOWER");
2773
- var upper = functionCall("UPPER");
2774
- var length = functionCall("LENGTH");
2775
- var isNaN2 = functionCall("ISNAN");
2776
- var isFinite = functionCall("ISFINITE");
2777
- var isInfinite = functionCall("ISINF");
2778
2715
 
2779
- // ../sql/src/windows.js
2780
- var WindowFunction = class _WindowFunction extends SQLExpression {
2781
- /**
2782
- * Create a new WindowFunction instance.
2783
- * @param {string} op The window operation indicator.
2784
- * @param {*} func The window function expression.
2785
- * @param {*} [type] The SQL data type to cast to.
2786
- * @param {string} [name] The window definition name.
2787
- * @param {*} [group] Grouping (partition by) expressions.
2788
- * @param {*} [order] Sorting (order by) expressions.
2789
- * @param {*} [frame] The window frame definition.
2790
- */
2791
- constructor(op, func, type, name, group = "", order = "", frame = "") {
2792
- let expr;
2793
- const noWindowParams = !(group || order || frame);
2794
- if (name && noWindowParams) {
2795
- expr = name ? sql`${func} OVER "${name}"` : sql`${func} OVER ()`;
2796
- } else {
2797
- const s1 = group && order ? " " : "";
2798
- const s2 = (group || order) && frame ? " " : "";
2799
- expr = sql`${func} OVER (${name ? `"${name}" ` : ""}${group}${s1}${order}${s2}${frame})`;
2800
- }
2801
- if (type) {
2802
- expr = sql`(${expr})::${type}`;
2803
- }
2804
- const { _expr, _deps } = expr;
2805
- super(_expr, _deps);
2806
- this.window = op;
2807
- this.func = func;
2808
- this.type = type;
2716
+ // ../sql/src/ast/window.js
2717
+ var WindowClauseNode = class extends SQLNode {
2718
+ /**
2719
+ * Instantiate a window clause node.
2720
+ * @param {string} name The window name.
2721
+ * @param {WindowDefNode} def The window definition.
2722
+ */
2723
+ constructor(name, def) {
2724
+ super(WINDOW_CLAUSE);
2809
2725
  this.name = name;
2810
- this.group = group;
2811
- this.order = order;
2812
- this.frame = frame;
2726
+ this.def = def;
2813
2727
  }
2814
- get basis() {
2815
- return this.column;
2728
+ toString() {
2729
+ return `${quoteIdentifier(this.name)} AS ${this.def}`;
2816
2730
  }
2817
- get label() {
2818
- const { func } = this;
2819
- return func.label ?? func.toString();
2731
+ };
2732
+ var WindowNode = class _WindowNode extends ExprNode {
2733
+ /**
2734
+ * Instantiate a window node.
2735
+ * @param {WindowFunctionNode | AggregateNode} func The window function call.
2736
+ * @param {WindowDefNode} [over] The window definition or name.
2737
+ */
2738
+ constructor(func, over2 = new WindowDefNode()) {
2739
+ super(WINDOW);
2740
+ this.func = func;
2741
+ this.def = over2;
2820
2742
  }
2821
2743
  /**
2822
- * Return an updated window function over a named window definition.
2744
+ * Return an updated window over a named window definition.
2823
2745
  * @param {string} name The window definition name.
2824
- * @returns {WindowFunction} A new window function.
2746
+ * @returns {WindowNode} A new window node.
2825
2747
  */
2826
2748
  over(name) {
2827
- const { window: op, func, type, group, order, frame } = this;
2828
- return new _WindowFunction(op, func, type, name, group, order, frame);
2749
+ return new _WindowNode(this.func, this.def.over(name));
2829
2750
  }
2830
2751
  /**
2831
- * Return an updated window function with the given partitioning.
2832
- * @param {*} expr The grouping (partition by) criteria for the window function.
2833
- * @returns {WindowFunction} A new window function.
2752
+ * Return an updated window with the given partitions.
2753
+ * @param {...import('../types.js').ExprVarArgs} expr The partition by criteria.
2754
+ * @returns {WindowNode} A new window node.
2834
2755
  */
2835
2756
  partitionby(...expr) {
2836
- const exprs = expr.flat().filter((x2) => x2).map(asColumn);
2837
- const group = sql(
2838
- ["PARTITION BY ", repeat(exprs.length - 1, ", "), ""],
2839
- ...exprs
2840
- );
2841
- const { window: op, func, type, name, order, frame } = this;
2842
- return new _WindowFunction(op, func, type, name, group, order, frame);
2757
+ return new _WindowNode(this.func, this.def.partitionby(...expr));
2843
2758
  }
2844
2759
  /**
2845
- * Return an updated window function with the given ordering.
2846
- * @param {*} expr The sorting (order by) criteria for the window function.
2847
- * @returns {WindowFunction} A new window function.
2760
+ * Return an updated window with the given ordering.
2761
+ * @param {...import('../types.js').ExprVarArgs} expr The order by criteria.
2762
+ * @returns {WindowNode} A new window node.
2848
2763
  */
2849
2764
  orderby(...expr) {
2850
- const exprs = expr.flat().filter((x2) => x2).map(asColumn);
2851
- const order = sql(
2852
- ["ORDER BY ", repeat(exprs.length - 1, ", "), ""],
2853
- ...exprs
2854
- );
2855
- const { window: op, func, type, name, group, frame } = this;
2856
- return new _WindowFunction(op, func, type, name, group, order, frame);
2765
+ return new _WindowNode(this.func, this.def.orderby(...expr));
2857
2766
  }
2858
2767
  /**
2859
- * Return an updated window function with the given rows frame.
2860
- * @param {(number|null)[] | import('./expression.js').ParamLike} expr The row-based window frame.
2861
- * @returns {WindowFunction} A new window function.
2768
+ * Return an updated window with the given rows frame.
2769
+ * @param {FrameExtent} extent The row-based window frame extent.
2770
+ * @returns {WindowNode} A new window node.
2862
2771
  */
2863
- rows(expr) {
2864
- const frame = windowFrame("ROWS", expr);
2865
- const { window: op, func, type, name, group, order } = this;
2866
- return new _WindowFunction(op, func, type, name, group, order, frame);
2772
+ rows(extent) {
2773
+ return new _WindowNode(this.func, this.def.rows(extent));
2867
2774
  }
2868
2775
  /**
2869
- * Return an updated window function with the given range frame.
2870
- * @param {(number|null)[] | import('./expression.js').ParamLike} expr The range-based window frame.
2871
- * @returns {WindowFunction} A new window function.
2776
+ * Return an updated window with the given range frame.
2777
+ * @param {FrameExtent} extent The range-based window frame extent.
2778
+ * @returns {WindowNode} A new window node.
2872
2779
  */
2873
- range(expr) {
2874
- const frame = windowFrame("RANGE", expr);
2875
- const { window: op, func, type, name, group, order } = this;
2876
- return new _WindowFunction(op, func, type, name, group, order, frame);
2877
- }
2878
- };
2879
- function windowFrame(type, frame) {
2880
- if (isParamLike(frame)) {
2881
- const expr = sql`${frame}`;
2882
- expr.toString = () => `${type} ${frameToSQL(frame.value)}`;
2883
- return expr;
2884
- }
2885
- return `${type} ${frameToSQL(frame)}`;
2886
- }
2887
- function frameToSQL(frame) {
2888
- const [prev, next] = frame;
2889
- const a = prev === 0 ? "CURRENT ROW" : Number.isFinite(prev) ? `${Math.abs(prev)} PRECEDING` : "UNBOUNDED PRECEDING";
2890
- const b = next === 0 ? "CURRENT ROW" : Number.isFinite(next) ? `${Math.abs(next)} FOLLOWING` : "UNBOUNDED FOLLOWING";
2891
- return `BETWEEN ${a} AND ${b}`;
2892
- }
2893
- function winf(op, type) {
2894
- return (...values) => {
2895
- const func = functionCall(op)(...values);
2896
- return new WindowFunction(op, func, type);
2897
- };
2898
- }
2899
- var row_number = winf("ROW_NUMBER", "INTEGER");
2900
- var rank = winf("RANK", "INTEGER");
2901
- var dense_rank = winf("DENSE_RANK", "INTEGER");
2902
- var percent_rank = winf("PERCENT_RANK");
2903
- var cume_dist = winf("CUME_DIST");
2904
- var ntile = winf("NTILE");
2905
- var lag = winf("LAG");
2906
- var lead = winf("LEAD");
2907
- var first_value = winf("FIRST_VALUE");
2908
- var last_value = winf("LAST_VALUE");
2909
- var nth_value = winf("NTH_VALUE");
2910
-
2911
- // ../sql/src/aggregates.js
2912
- function agg(strings, ...exprs) {
2913
- return sql(strings, ...exprs).annotate({ aggregate: true });
2914
- }
2915
- var AggregateFunction = class _AggregateFunction extends SQLExpression {
2916
- /**
2917
- * Create a new AggregateFunction instance.
2918
- * @param {*} op The aggregate operation.
2919
- * @param {*} [args] The aggregate function arguments.
2920
- * @param {*} [type] The SQL data type to cast to.
2921
- * @param {boolean} [isDistinct] Flag indicating if this is a distinct value aggregate.
2922
- * @param {*} [filter] Filtering expression to apply prior to aggregation.
2923
- */
2924
- constructor(op, args, type, isDistinct2, filter) {
2925
- args = (args || []).map(asColumn);
2926
- const { strings, exprs } = aggExpr(op, args, type, isDistinct2, filter);
2927
- const { spans, cols } = parseSQL(strings, exprs);
2928
- super(spans, cols);
2929
- this.aggregate = op;
2930
- this.args = args;
2931
- this.type = type;
2932
- this.isDistinct = isDistinct2;
2933
- this.filter = filter;
2934
- }
2935
- get basis() {
2936
- return this.column;
2937
- }
2938
- get label() {
2939
- const { aggregate: op, args, isDistinct: isDistinct2 } = this;
2940
- const dist = isDistinct2 ? "DISTINCT" + (args.length ? " " : "") : "";
2941
- const tail = args.length ? `(${dist}${args.map(unquoted).join(", ")})` : "";
2942
- return `${op.toLowerCase()}${tail}`;
2780
+ range(extent) {
2781
+ return new _WindowNode(this.func, this.def.range(extent));
2943
2782
  }
2944
2783
  /**
2945
- * Return a new derived aggregate function over distinct values.
2946
- * @returns {AggregateFunction} A new aggregate function.
2784
+ * Generate a SQL query string for this node.
2785
+ * @returns {string}
2947
2786
  */
2948
- distinct() {
2949
- const { aggregate: op, args, type, filter } = this;
2950
- return new _AggregateFunction(op, args, type, true, filter);
2787
+ toString() {
2788
+ return `${this.func} OVER ${this.def}`;
2951
2789
  }
2790
+ };
2791
+ var WindowDefNode = class extends SQLNode {
2952
2792
  /**
2953
- * Return a new derived aggregate function that filters values.
2954
- * @param {*} filter The filter expresion.
2955
- * @returns {AggregateFunction} A new aggregate function.
2793
+ * Instantiate a window definition node.
2794
+ * @param {string} [name] The base window definition name.
2795
+ * @param {ExprNode[]} [partition] The partition by criteria.
2796
+ * @param {ExprNode[]} [order] The order by criteria.
2797
+ * @param {WindowFrameNode} [frame] The window frame definition.
2956
2798
  */
2957
- where(filter) {
2958
- const { aggregate: op, args, type, isDistinct: isDistinct2 } = this;
2959
- return new _AggregateFunction(op, args, type, isDistinct2, filter);
2799
+ constructor(name, partition, order, frame) {
2800
+ super(WINDOW_DEF);
2801
+ this.name = name;
2802
+ this.partition = partition;
2803
+ this.order = order;
2804
+ this.frame = frame;
2960
2805
  }
2961
2806
  /**
2962
- * Return a new window function over this aggregate.
2963
- * @returns {WindowFunction} A new aggregate function.
2807
+ * Return an updated window definition with the given base name.
2808
+ * @param {string} name The base window definition name.
2809
+ * @returns {WindowDefNode} A new window definition node.
2964
2810
  */
2965
- window() {
2966
- const { aggregate: op, args, type, isDistinct: isDistinct2 } = this;
2967
- const func = new _AggregateFunction(op, args, null, isDistinct2);
2968
- return new WindowFunction(op, func, type);
2811
+ over(name) {
2812
+ return deriveDef(this, { name });
2969
2813
  }
2970
2814
  /**
2971
- * Return a window function over this aggregate with the given partitioning.
2972
- * @param {*} expr The grouping (partition by) criteria for the window function.
2973
- * @returns {WindowFunction} A new window function.
2815
+ * Return an updated window definition with the given partitions.
2816
+ * @param {...import('../types.js').ExprVarArgs} expr The partition by criteria.
2817
+ * @returns {WindowDefNode} A new window definition node.
2974
2818
  */
2975
2819
  partitionby(...expr) {
2976
- return this.window().partitionby(...expr);
2820
+ return deriveDef(this, { partition: exprList(expr) });
2977
2821
  }
2978
2822
  /**
2979
- * Return a window function over this aggregate with the given ordering.
2980
- * @param {*} expr The sorting (order by) criteria for the window function.
2981
- * @returns {WindowFunction} A new window function.
2823
+ * Return an updated window definition with the given ordering.
2824
+ * @param {...import('../types.js').ExprVarArgs} expr The order by criteria.
2825
+ * @returns {WindowDefNode} A new window definition node.
2982
2826
  */
2983
2827
  orderby(...expr) {
2984
- return this.window().orderby(...expr);
2828
+ return deriveDef(this, { order: exprList(expr) });
2985
2829
  }
2986
2830
  /**
2987
- * Return a window function over this aggregate with the given row frame.
2988
- * @param {(number|null)[] | import('./expression.js').ParamLike} frame The row-based window frame.
2989
- * @returns {WindowFunction} A new window function.
2831
+ * Return an updated window definition with the given rows frame.
2832
+ * @param {FrameExtent} extent The row-based window frame extent.
2833
+ * @returns {WindowDefNode} A new window definition node.
2990
2834
  */
2991
- rows(frame) {
2992
- return this.window().rows(frame);
2835
+ rows(extent) {
2836
+ return deriveDef(this, { frame: new WindowFrameNode(extent) });
2993
2837
  }
2994
2838
  /**
2995
- * Return a window function over this aggregate with the given range frame.
2996
- * @param {(number|null)[] | import('./expression.js').ParamLike} frame The range-based window frame.
2997
- * @returns {WindowFunction} A new window function.
2839
+ * Return an updated window definition with the given range frame.
2840
+ * @param {FrameExtent} extent The range-based window frame extent.
2841
+ * @returns {WindowDefNode} A new window definition node.
2998
2842
  */
2999
- range(frame) {
3000
- return this.window().range(frame);
3001
- }
3002
- };
3003
- function aggExpr(op, args, type, isDistinct2, filter) {
3004
- const close = `)${type ? `::${type}` : ""}`;
3005
- let strings = [`${op}(${isDistinct2 ? "DISTINCT " : ""}`];
3006
- let exprs = [];
3007
- if (args.length) {
3008
- strings = strings.concat([
3009
- ...repeat(args.length - 1, ", "),
3010
- `${close}${filter ? " FILTER (WHERE " : ""}`,
3011
- ...filter ? [")"] : []
3012
- ]);
3013
- exprs = [...args, ...filter ? [filter] : []];
3014
- } else {
3015
- strings[0] += "*" + close;
3016
- }
3017
- return { exprs, strings };
3018
- }
3019
- function unquoted(value) {
3020
- const s = literalToSQL(value);
3021
- return s && s.startsWith('"') && s.endsWith('"') ? s.slice(1, -1) : s;
3022
- }
3023
- function aggf(op, type) {
3024
- return (...args) => new AggregateFunction(op, args, type);
3025
- }
3026
- var count = aggf("COUNT", "INTEGER");
3027
- var avg = aggf("AVG");
3028
- var mean = aggf("AVG");
3029
- var mad = aggf("MAD");
3030
- var max = aggf("MAX");
3031
- var min = aggf("MIN");
3032
- var sum = aggf("SUM", "DOUBLE");
3033
- var product = aggf("PRODUCT");
3034
- var median = aggf("MEDIAN");
3035
- var quantile = aggf("QUANTILE");
3036
- var mode = aggf("MODE");
3037
- var variance = aggf("VARIANCE");
3038
- var stddev = aggf("STDDEV");
3039
- var skewness = aggf("SKEWNESS");
3040
- var kurtosis = aggf("KURTOSIS");
3041
- var entropy = aggf("ENTROPY");
3042
- var varPop = aggf("VAR_POP");
3043
- var stddevPop = aggf("STDDEV_POP");
3044
- var corr = aggf("CORR");
3045
- var covariance = aggf("COVAR_SAMP");
3046
- var covarPop = aggf("COVAR_POP");
3047
- var regrIntercept = aggf("REGR_INTERCEPT");
3048
- var regrSlope = aggf("REGR_SLOPE");
3049
- var regrCount = aggf("REGR_COUNT");
3050
- var regrR2 = aggf("REGR_R2");
3051
- var regrSYY = aggf("REGR_SYY");
3052
- var regrSXX = aggf("REGR_SXX");
3053
- var regrSXY = aggf("REGR_SXY");
3054
- var regrAvgX = aggf("REGR_AVGX");
3055
- var regrAvgY = aggf("REGR_AVGY");
3056
- var first = aggf("FIRST");
3057
- var last = aggf("LAST");
3058
- var argmin = aggf("ARG_MIN");
3059
- var argmax = aggf("ARG_MAX");
3060
- var stringAgg = aggf("STRING_AGG");
3061
- var arrayAgg = aggf("ARRAY_AGG");
3062
-
3063
- // ../sql/src/datetime.js
3064
- var epoch_ms = (expr) => {
3065
- return sql`epoch_ms(${asColumn(expr)})`;
3066
- };
3067
-
3068
- // ../sql/src/spatial.js
3069
- var geojson = functionCall("ST_AsGeoJSON");
3070
- var x = functionCall("ST_X");
3071
- var y = functionCall("ST_Y");
3072
- var centroid = functionCall("ST_CENTROID");
3073
-
3074
- // ../sql/src/Query.js
3075
- var Query = class _Query {
3076
- static select(...expr) {
3077
- return new _Query().select(...expr);
3078
- }
3079
- static from(...expr) {
3080
- return new _Query().from(...expr);
3081
- }
3082
- static with(...expr) {
3083
- return new _Query().with(...expr);
3084
- }
3085
- static union(...queries) {
3086
- return new SetOperation("UNION", queries.flat());
3087
- }
3088
- static unionAll(...queries) {
3089
- return new SetOperation("UNION ALL", queries.flat());
3090
- }
3091
- static intersect(...queries) {
3092
- return new SetOperation("INTERSECT", queries.flat());
3093
- }
3094
- static except(...queries) {
3095
- return new SetOperation("EXCEPT", queries.flat());
3096
- }
3097
- static describe(query) {
3098
- const q = query.clone();
3099
- const { clone, toString } = q;
3100
- return Object.assign(q, {
3101
- describe: true,
3102
- clone: () => _Query.describe(clone.call(q)),
3103
- toString: () => `DESCRIBE ${toString.call(q)}`
3104
- });
3105
- }
3106
- constructor() {
3107
- this.query = {
3108
- with: [],
3109
- select: [],
3110
- from: [],
3111
- where: [],
3112
- groupby: [],
3113
- having: [],
3114
- window: [],
3115
- qualify: [],
3116
- orderby: []
3117
- };
3118
- this.cteFor = null;
3119
- }
3120
- clone() {
3121
- const q = new _Query();
3122
- q.query = { ...this.query };
3123
- return q;
2843
+ range(extent) {
2844
+ return deriveDef(this, { frame: new WindowFrameNode(extent, true) });
3124
2845
  }
3125
2846
  /**
3126
- * Retrieve current WITH common table expressions (CTEs).
3127
- * @returns {any[]}
2847
+ * Generate a SQL query string for this node.
2848
+ * @returns {string}
3128
2849
  */
3129
- /**
3130
- * Add WITH common table expressions (CTEs).
3131
- * @param {...any} expr Expressions to add.
3132
- * @returns {this}
3133
- */
3134
- with(...expr) {
3135
- const { query } = this;
3136
- if (expr.length === 0) {
3137
- return query.with;
3138
- } else {
3139
- const list2 = [];
3140
- const add = (as, q) => {
3141
- const query2 = q.clone();
3142
- query2.cteFor = this;
3143
- list2.push({ as, query: query2 });
3144
- };
3145
- expr.flat().forEach((e) => {
3146
- if (e == null) {
3147
- } else if (e.as && e.query) {
3148
- add(e.as, e.query);
3149
- } else {
3150
- for (const as in e) {
3151
- add(as, e[as]);
3152
- }
3153
- }
3154
- });
3155
- query.with = query.with.concat(list2);
3156
- return this;
3157
- }
2850
+ toString() {
2851
+ const { name, partition, order, frame } = this;
2852
+ const base = name && quoteIdentifier(name);
2853
+ const def = [
2854
+ base,
2855
+ partition?.length && `PARTITION BY ${partition.join(", ")}`,
2856
+ order?.length && `ORDER BY ${order.join(", ")}`,
2857
+ frame
2858
+ ].filter((x2) => x2);
2859
+ return base && def.length < 2 ? base : `(${def.join(" ")})`;
3158
2860
  }
2861
+ };
2862
+ var WindowFrameNode = class extends SQLNode {
3159
2863
  /**
3160
- * Retrieve current SELECT expressions.
3161
- * @returns {any[]}
2864
+ * Instantiate a window frame definition node.
2865
+ * @param {FrameExtent} extent The frame extent as [preceding, following]
2866
+ * row or interval offsets.
2867
+ * @param {boolean} [range] The frame type: `true` for range, otherwise rows.
2868
+ * @param {ExprNode} [exclude] The window exclusion criteria.
3162
2869
  */
3163
- /**
3164
- * Add SELECT expressions.
3165
- * @param {...any} expr Expressions to add.
3166
- * @returns {this}
3167
- */
3168
- select(...expr) {
3169
- const { query } = this;
3170
- if (expr.length === 0) {
3171
- return query.select;
3172
- } else {
3173
- const list2 = [];
3174
- for (const e of expr.flat()) {
3175
- if (e == null) {
3176
- } else if (typeof e === "string") {
3177
- list2.push({ as: e, expr: asColumn(e) });
3178
- } else if (e instanceof Ref) {
3179
- list2.push({ as: e.column, expr: e });
3180
- } else if (Array.isArray(e)) {
3181
- list2.push({ as: e[0], expr: e[1] });
3182
- } else {
3183
- for (const as in e) {
3184
- list2.push({ as: unquote(as), expr: asColumn(e[as]) });
3185
- }
3186
- }
3187
- }
3188
- const keys = new Set(list2.map((x2) => x2.as));
3189
- query.select = query.select.filter((x2) => !keys.has(x2.as)).concat(list2.filter((x2) => x2.expr));
3190
- return this;
3191
- }
3192
- }
3193
- $select(...expr) {
3194
- this.query.select = [];
3195
- return this.select(...expr);
3196
- }
3197
- distinct(value = true) {
3198
- this.query.distinct = !!value;
3199
- return this;
2870
+ constructor(extent, range = false, exclude = void 0) {
2871
+ super(WINDOW_FRAME);
2872
+ this.extent = isParamLike(extent) ? new ParamNode(extent) : extent;
2873
+ this.range = range;
2874
+ this.exclude = exclude;
3200
2875
  }
3201
2876
  /**
3202
- * Retrieve current from expressions.
3203
- * @returns {any[]}
2877
+ * Generate a SQL query string for this node.
2878
+ * @returns {string}
3204
2879
  */
3205
- /**
3206
- * Provide table from expressions.
3207
- * @param {...any} expr
3208
- * @returns {this}
3209
- */
3210
- from(...expr) {
3211
- const { query } = this;
3212
- if (expr.length === 0) {
3213
- return query.from;
3214
- } else {
3215
- const list2 = [];
3216
- expr.flat().forEach((e) => {
3217
- if (e == null) {
3218
- } else if (typeof e === "string") {
3219
- list2.push({ as: e, from: asRelation(e) });
3220
- } else if (e instanceof Ref) {
3221
- list2.push({ as: e.table, from: e });
3222
- } else if (isQuery(e) || isSQLExpression(e)) {
3223
- list2.push({ from: e });
3224
- } else if (Array.isArray(e)) {
3225
- list2.push({ as: unquote(e[0]), from: asRelation(e[1]) });
3226
- } else {
3227
- for (const as in e) {
3228
- list2.push({ as: unquote(as), from: asRelation(e[as]) });
3229
- }
3230
- }
3231
- });
3232
- query.from = query.from.concat(list2);
3233
- return this;
3234
- }
3235
- }
3236
- $from(...expr) {
3237
- this.query.from = [];
3238
- return this.from(...expr);
2880
+ toString() {
2881
+ const { range, exclude, extent } = this;
2882
+ const type = range ? "RANGE" : "ROWS";
2883
+ const [prev, next] = isNode(extent) ? extent.value : extent;
2884
+ const a = frameValue(prev, "PRECEDING");
2885
+ const b = frameValue(next, "FOLLOWING");
2886
+ return `${type} BETWEEN ${a} AND ${b}${exclude ? ` ${exclude}` : ""}`;
3239
2887
  }
2888
+ };
2889
+ function deriveDef(def, options) {
2890
+ return new WindowDefNode(
2891
+ options.name ?? def.name,
2892
+ options.partition ?? def.partition,
2893
+ options.order ?? def.order,
2894
+ options.frame ?? def.frame
2895
+ );
2896
+ }
2897
+ function frameValue(value, order) {
2898
+ return value === 0 ? "CURRENT ROW" : Number.isFinite(value) ? `${Math.abs(value)} ${order}` : `UNBOUNDED ${order}`;
2899
+ }
2900
+
2901
+ // ../sql/src/ast/column-ref.js
2902
+ function isColumnRef(value) {
2903
+ return value instanceof ColumnRefNode;
2904
+ }
2905
+ var ColumnRefNode = class extends ExprNode {
3240
2906
  /**
3241
- * Retrieve current SAMPLE settings.
3242
- * @returns {any[]}
2907
+ * Instantiate a column reference node.
2908
+ * @param {import('./table-ref.js').TableRefNode} [table] The table reference.
3243
2909
  */
3244
- /**
3245
- * Set SAMPLE settings.
3246
- * @param {number|object} value The percentage or number of rows to sample.
3247
- * @param {string} [method] The sampling method to use.
3248
- * @returns {this}
3249
- */
3250
- sample(value, method) {
3251
- const { query } = this;
3252
- if (arguments.length === 0) {
3253
- return query.sample;
3254
- } else {
3255
- let spec = value;
3256
- if (typeof value === "number") {
3257
- spec = value > 0 && value < 1 ? { perc: 100 * value, method } : { rows: Math.round(value), method };
3258
- }
3259
- query.sample = spec;
3260
- return this;
3261
- }
2910
+ constructor(type, table2) {
2911
+ super(type);
2912
+ this.table = table2;
3262
2913
  }
3263
2914
  /**
3264
- * Retrieve current WHERE expressions.
3265
- * @returns {any[]}
2915
+ * Returns the column name.
2916
+ * @returns {string}
3266
2917
  */
3267
- /**
3268
- * Add WHERE expressions.
3269
- * @param {...any} expr Expressions to add.
3270
- * @returns {this}
3271
- */
3272
- where(...expr) {
3273
- const { query } = this;
3274
- if (expr.length === 0) {
3275
- return query.where;
3276
- } else {
3277
- query.where = query.where.concat(
3278
- expr.flat().filter((x2) => x2)
3279
- );
3280
- return this;
3281
- }
3282
- }
3283
- $where(...expr) {
3284
- this.query.where = [];
3285
- return this.where(...expr);
2918
+ get column() {
2919
+ return null;
3286
2920
  }
3287
2921
  /**
3288
- * Retrieve current GROUP BY expressions.
3289
- * @returns {any[]}
2922
+ * Generate a SQL query string for this node.
2923
+ * @returns {string}
3290
2924
  */
3291
- /**
3292
- * Add GROUP BY expressions.
3293
- * @param {...any} expr Expressions to add.
3294
- * @returns {this}
3295
- */
3296
- groupby(...expr) {
3297
- const { query } = this;
3298
- if (expr.length === 0) {
3299
- return query.groupby;
3300
- } else {
3301
- query.groupby = query.groupby.concat(
3302
- expr.flat().filter((x2) => x2).map(asColumn)
3303
- );
3304
- return this;
3305
- }
3306
- }
3307
- $groupby(...expr) {
3308
- this.query.groupby = [];
3309
- return this.groupby(...expr);
2925
+ toString() {
2926
+ const { column: column2, table: table2 } = this;
2927
+ const tref = `${table2 ?? ""}`;
2928
+ const id = column2 === "*" ? "*" : quoteIdentifier(column2);
2929
+ return (tref ? tref + "." : "") + id;
3310
2930
  }
2931
+ };
2932
+ var ColumnNameRefNode = class extends ColumnRefNode {
3311
2933
  /**
3312
- * Retrieve current HAVING expressions.
3313
- * @returns {any[]}
2934
+ * Instantiate a column reference node.
2935
+ * @param {string} name The column name.
2936
+ * @param {import('./table-ref.js').TableRefNode} [table] The table reference.
3314
2937
  */
3315
- /**
3316
- * Add HAVING expressions.
3317
- * @param {...any} expr Expressions to add.
3318
- * @returns {this}
3319
- */
3320
- having(...expr) {
3321
- const { query } = this;
3322
- if (expr.length === 0) {
3323
- return query.having;
3324
- } else {
3325
- query.having = query.having.concat(
3326
- expr.flat().filter((x2) => x2)
3327
- );
3328
- return this;
3329
- }
2938
+ constructor(name, table2) {
2939
+ super(COLUMN_REF, table2);
2940
+ this.name = name;
3330
2941
  }
3331
2942
  /**
3332
- * Retrieve current WINDOW definitions.
3333
- * @returns {any[]}
2943
+ * Returns the column name.
2944
+ * @returns {string}
3334
2945
  */
3335
- /**
3336
- * Add WINDOW definitions.
3337
- * @param {...any} expr Expressions to add.
3338
- * @returns {this}
3339
- */
3340
- window(...expr) {
3341
- const { query } = this;
3342
- if (expr.length === 0) {
3343
- return query.window;
3344
- } else {
3345
- const list2 = [];
3346
- expr.flat().forEach((e) => {
3347
- if (e == null) {
3348
- } else {
3349
- for (const as in e) {
3350
- list2.push({ as: unquote(as), expr: e[as] });
3351
- }
3352
- }
3353
- });
3354
- query.window = query.window.concat(list2);
3355
- return this;
3356
- }
2946
+ get column() {
2947
+ return this.name;
3357
2948
  }
2949
+ };
2950
+
2951
+ // ../sql/src/ast/column-param.js
2952
+ var ColumnParamNode = class extends ColumnRefNode {
3358
2953
  /**
3359
- * Retrieve current QUALIFY expressions.
3360
- * @returns {any[]}
2954
+ * Instantiate a column param node.
2955
+ * @param {import('./param.js').ParamNode} param The column name as a
2956
+ * parameter node.
2957
+ * @param {import('./table-ref.js').TableRefNode} [table] The table
2958
+ * reference.
3361
2959
  */
3362
- /**
3363
- * Add QUALIFY expressions.
3364
- * @param {...any} expr Expressions to add.
3365
- * @returns {this}
3366
- */
3367
- qualify(...expr) {
3368
- const { query } = this;
3369
- if (expr.length === 0) {
3370
- return query.qualify;
3371
- } else {
3372
- query.qualify = query.qualify.concat(
3373
- expr.flat().filter((x2) => x2)
3374
- );
3375
- return this;
3376
- }
2960
+ constructor(param, table2) {
2961
+ super(COLUMN_PARAM, table2);
2962
+ this.param = param;
3377
2963
  }
3378
2964
  /**
3379
- * Retrieve current ORDER BY expressions.
3380
- * @returns {any[]}
2965
+ * Returns the column name.
2966
+ * @returns {string}
3381
2967
  */
3382
- /**
3383
- * Add ORDER BY expressions.
3384
- * @param {...any} expr Expressions to add.
3385
- * @returns {this}
3386
- */
3387
- orderby(...expr) {
3388
- const { query } = this;
3389
- if (expr.length === 0) {
3390
- return query.orderby;
3391
- } else {
3392
- query.orderby = query.orderby.concat(
3393
- expr.flat().filter((x2) => x2).map(asColumn)
3394
- );
3395
- return this;
3396
- }
2968
+ get column() {
2969
+ return `${this.param.value}`;
3397
2970
  }
2971
+ };
2972
+
2973
+ // ../sql/src/functions/column.js
2974
+ function column(name, table2) {
2975
+ const tref = asTableRef(table2);
2976
+ return isParamLike(name) ? new ColumnParamNode(new ParamNode(name), tref) : new ColumnNameRefNode(name, tref);
2977
+ }
2978
+
2979
+ // ../sql/src/ast/verbatim.js
2980
+ var VerbatimNode = class extends ExprNode {
3398
2981
  /**
3399
- * Retrieve current LIMIT value.
3400
- * @returns {number|null}
2982
+ * Instantiate a raw node with verbatim content.
2983
+ * @param {string} value The verbatim content to include.
3401
2984
  */
2985
+ constructor(value) {
2986
+ super(VERBATIM);
2987
+ this.value = value;
2988
+ }
3402
2989
  /**
3403
- * Set the query result LIMIT.
3404
- * @param {number} value The limit value.
3405
- * @returns {this}
3406
- */
3407
- limit(value) {
3408
- const { query } = this;
3409
- if (arguments.length === 0) {
3410
- return query.limit;
3411
- } else {
3412
- query.limit = Number.isFinite(value) ? value : void 0;
3413
- return this;
3414
- }
2990
+ * Generate a SQL query string for this node.
2991
+ * @returns {string}
2992
+ */
2993
+ toString() {
2994
+ return this.value;
2995
+ }
2996
+ };
2997
+
2998
+ // ../sql/src/functions/literal.js
2999
+ function literal(value) {
3000
+ return new LiteralNode(value);
3001
+ }
3002
+ function verbatim(value) {
3003
+ return new VerbatimNode(value);
3004
+ }
3005
+
3006
+ // ../sql/src/functions/table-ref.js
3007
+ function tableRef(...ids) {
3008
+ const args = exprList(ids, String);
3009
+ return args?.length ? new TableRefNode(args) : void 0;
3010
+ }
3011
+
3012
+ // ../sql/src/util/ast.js
3013
+ function asNode(value) {
3014
+ return isString(value) ? parseColumnRef(value) : asLiteral(value);
3015
+ }
3016
+ function asVerbatim(value) {
3017
+ return isString(value) ? verbatim(value) : asLiteral(value);
3018
+ }
3019
+ function asLiteral(value) {
3020
+ return value instanceof ExprNode ? value : isParamLike(value) ? new ParamNode(value) : literal(value);
3021
+ }
3022
+ function asTableRef(value) {
3023
+ return isString(value) ? parseTableRef(value) : isArray2(value) ? tableRef(value) : value;
3024
+ }
3025
+ function parseColumnRef(ref) {
3026
+ const ids = parseIdentifier(ref);
3027
+ return column(ids.pop(), tableRef(ids));
3028
+ }
3029
+ function parseTableRef(ref) {
3030
+ return tableRef(parseIdentifier(ref));
3031
+ }
3032
+
3033
+ // ../sql/src/ast/aggregate.js
3034
+ var AggregateNode = class _AggregateNode extends ExprNode {
3035
+ /**
3036
+ * Instantiate an aggregate function node.
3037
+ * @param {string} name The aggregate function name.
3038
+ * @param {ExprNode[]} args The aggregate function arguments.
3039
+ * @param {boolean} [distinct] The distinct flag.
3040
+ * @param {ExprNode} [filter] Filter expression.
3041
+ */
3042
+ constructor(name, args, distinct2, filter) {
3043
+ super(AGGREGATE);
3044
+ this.name = name;
3045
+ this.args = args;
3046
+ this.isDistinct = distinct2;
3047
+ this.filter = filter;
3048
+ }
3049
+ /**
3050
+ * Return a new derived aggregate over distinct values.
3051
+ * @param {boolean} [isDistinct=true] The distinct flag.
3052
+ * @returns {AggregateNode} A new aggregate node.
3053
+ */
3054
+ distinct(isDistinct2 = true) {
3055
+ return new _AggregateNode(this.name, this.args, isDistinct2, this.filter);
3056
+ }
3057
+ /**
3058
+ * Return a new derived aggregate function that filters values.
3059
+ * @param {ExprNode | string} filter The filter expression.
3060
+ * @returns {AggregateNode} A new aggregate node.
3061
+ */
3062
+ where(filter) {
3063
+ if (isString(filter)) filter = asVerbatim(filter);
3064
+ return new _AggregateNode(this.name, this.args, this.isDistinct, filter);
3065
+ }
3066
+ /**
3067
+ * Return a new window function over this aggregate.
3068
+ * @returns {WindowNode} A new window node.
3069
+ */
3070
+ window() {
3071
+ return new WindowNode(this);
3072
+ }
3073
+ /**
3074
+ * Return a new window function over this aggregate with the given partitions.
3075
+ * @param {...import('../types.js').ExprVarArgs} expr The partition by criteria.
3076
+ * @returns {WindowNode} A new window node.
3077
+ */
3078
+ partitionby(...expr) {
3079
+ return this.window().partitionby(...expr);
3415
3080
  }
3416
3081
  /**
3417
- * Retrieve current OFFSET value.
3418
- * @returns {number|null}
3082
+ * Return a new window function over this aggregate with the given ordering.
3083
+ * @param {...import('../types.js').ExprVarArgs} expr The order by criteria.
3084
+ * @returns {WindowNode} A new window node.
3419
3085
  */
3086
+ orderby(...expr) {
3087
+ return this.window().orderby(...expr);
3088
+ }
3089
+ /**
3090
+ * Generate a SQL query string for this node.
3091
+ * @returns {string}
3092
+ */
3093
+ toString() {
3094
+ const { name, args, isDistinct: isDistinct2, filter } = this;
3095
+ const dist = isDistinct2 ? "DISTINCT " : "";
3096
+ const arg = args?.length ? args.join(", ") : "*";
3097
+ const filt = filter ? ` FILTER (WHERE ${filter})` : "";
3098
+ return `${name}(${dist}${arg})${filt}`;
3099
+ }
3100
+ };
3101
+ var aggregateNames = [
3102
+ "any_value",
3103
+ "approx_count_distinct",
3104
+ "approx_quantile",
3105
+ "arbitrary",
3106
+ "arg_max",
3107
+ "arg_max_null",
3108
+ "arg_min",
3109
+ "arg_min_null",
3110
+ "array_agg",
3111
+ "avg",
3112
+ "bit_and",
3113
+ "bit_or",
3114
+ "bit_xor",
3115
+ "bitstring_agg",
3116
+ "bool_and",
3117
+ "bool_or",
3118
+ "corr",
3119
+ "count",
3120
+ "covar_pop",
3121
+ "covar_samp",
3122
+ "entropy",
3123
+ "favg",
3124
+ "first",
3125
+ "fsum",
3126
+ "geomean",
3127
+ "kurtosis_pop",
3128
+ "kurtosis",
3129
+ "last",
3130
+ "mad",
3131
+ "max",
3132
+ "max_by",
3133
+ "median",
3134
+ "min",
3135
+ "min_by",
3136
+ "mode",
3137
+ "product",
3138
+ "quantile",
3139
+ "quantile_cont",
3140
+ "quantile_disc",
3141
+ "regr_avgx",
3142
+ "regr_avgy",
3143
+ "regr_count",
3144
+ "regr_intercept",
3145
+ "regr_r2",
3146
+ "regr_sxx",
3147
+ "regr_sxy",
3148
+ "regr_syy",
3149
+ "regr_slope",
3150
+ "reservoir_quantile",
3151
+ "skewness",
3152
+ "stddev",
3153
+ "stddev_pop",
3154
+ "stddev_samp",
3155
+ "string_agg",
3156
+ "sum",
3157
+ "variance",
3158
+ "var_pop",
3159
+ "var_samp"
3160
+ ];
3161
+
3162
+ // ../sql/src/ast/between-op.js
3163
+ var AbstractBetweenOpNode = class extends ExprNode {
3164
+ /**
3165
+ * Instantiate an abstract between operator node.
3166
+ * @param {string} type The node type.
3167
+ * @param {ExprNode} expr The input expression.
3168
+ * @param {[ExprNode, ExprNode]} extent The range extent.
3169
+ */
3170
+ constructor(type, expr, extent) {
3171
+ super(type);
3172
+ this.expr = expr;
3173
+ this.extent = extent;
3174
+ }
3175
+ /**
3176
+ * Generate a SQL query string for this node.
3177
+ * @returns {string}
3178
+ */
3179
+ toSQL(op) {
3180
+ const { extent: r, expr } = this;
3181
+ return r ? `(${expr} ${op} ${r[0]} AND ${r[1]})` : "";
3182
+ }
3183
+ };
3184
+ var BetweenOpNode = class extends AbstractBetweenOpNode {
3185
+ /**
3186
+ * Instantiate a between operator node.
3187
+ * @param {ExprNode} expr The input expression.
3188
+ * @param {[ExprNode, ExprNode]} extent
3189
+ * The range extent.
3190
+ */
3191
+ constructor(expr, extent) {
3192
+ super(BETWEEN_OPERATOR, expr, extent);
3193
+ }
3194
+ /**
3195
+ * Generate a SQL query string for this node.
3196
+ * @returns {string}
3197
+ */
3198
+ toString() {
3199
+ return super.toSQL("BETWEEN");
3200
+ }
3201
+ };
3202
+ var NotBetweenOpNode = class extends AbstractBetweenOpNode {
3203
+ /**
3204
+ * Instantiate a not between operator node.
3205
+ * @param {ExprNode} expr The input expression.
3206
+ * @param {[ExprNode, ExprNode]} extent
3207
+ * The range extent.
3208
+ */
3209
+ constructor(expr, extent) {
3210
+ super(NOT_BETWEEN_OPERATOR, expr, extent);
3211
+ }
3420
3212
  /**
3421
- * Set the query result OFFSET.
3422
- * @param {number} value The offset value.
3423
- * @returns {this}
3424
- */
3213
+ * Generate a SQL query string for this node.
3214
+ * @returns {string}
3215
+ */
3216
+ toString() {
3217
+ return super.toSQL("NOT BETWEEN");
3218
+ }
3219
+ };
3220
+
3221
+ // ../sql/src/ast/binary-op.js
3222
+ var BinaryOpNode = class extends ExprNode {
3223
+ /**
3224
+ * Instantiate a binary operator node.
3225
+ * @param {string} op The operator type.
3226
+ * @param {ExprNode} left The left input expression.
3227
+ * @param {ExprNode} right The right input expression.
3228
+ */
3229
+ constructor(op, left, right) {
3230
+ super(BINARY_OPERATOR);
3231
+ this.op = op;
3232
+ this.left = left;
3233
+ this.right = right;
3234
+ }
3235
+ /**
3236
+ * Generate a SQL query string for this node.
3237
+ * @returns {string}
3238
+ */
3239
+ toString() {
3240
+ return `(${this.left} ${this.op} ${this.right})`;
3241
+ }
3242
+ };
3243
+
3244
+ // ../sql/src/ast/cast.js
3245
+ var CastNode = class extends ExprNode {
3246
+ /**
3247
+ * Instantiate a cast node.
3248
+ * @param {ExprNode} expr The expression to type cast.
3249
+ * @param {string} type The type to cast to.
3250
+ */
3251
+ constructor(expr, type) {
3252
+ super(CAST);
3253
+ this.expr = expr;
3254
+ this.cast = type;
3255
+ }
3256
+ /**
3257
+ * Generate a SQL query string for this node.
3258
+ * @returns {string}
3259
+ */
3260
+ toString() {
3261
+ return `(${this.expr})::${this.cast}`;
3262
+ }
3263
+ };
3264
+
3265
+ // ../sql/src/ast/fragment.js
3266
+ var FragmentNode = class extends ExprNode {
3267
+ /**
3268
+ * Instantiate a fragment node with arbitrary content.
3269
+ * @param {ExprNode[]} spans The consecutive parts making up the fragment.
3270
+ */
3271
+ constructor(spans) {
3272
+ super(FRAGMENT);
3273
+ this.spans = spans;
3274
+ }
3275
+ /**
3276
+ * Generate a SQL query string for this node.
3277
+ * @returns {string}
3278
+ */
3279
+ toString() {
3280
+ return this.spans.join("");
3281
+ }
3282
+ };
3283
+
3284
+ // ../sql/src/ast/sample.js
3285
+ var SampleClauseNode = class extends SQLNode {
3286
+ /**
3287
+ * Instantiate a sample clause node.
3288
+ * @param {number} size The sample size as either a row count or percentage.
3289
+ * @param {boolean} [perc=false] Flag indicating if the sampling unit is
3290
+ * rows (`false`) or a percentage (`true`).
3291
+ * @param {SampleMethod} [method] The sampling method. If unspecified,
3292
+ * a default method is applied based on the sampling unit.
3293
+ * @param {number} [seed] The random seed.
3294
+ */
3295
+ constructor(size, perc = false, method = void 0, seed = void 0) {
3296
+ super(SAMPLE_CLAUSE);
3297
+ this.size = size;
3298
+ this.perc = perc;
3299
+ this.method = method;
3300
+ this.seed = seed;
3301
+ }
3302
+ toString() {
3303
+ const { size, perc, method, seed } = this;
3304
+ const unit = perc ? "%" : " ROWS";
3305
+ const s = seed != null ? `, ${seed}` : "";
3306
+ return `${size}${unit}${method ? ` (${method}${s})` : ""}`;
3307
+ }
3308
+ };
3309
+
3310
+ // ../sql/src/ast/select.js
3311
+ var SelectClauseNode = class extends SQLNode {
3312
+ /**
3313
+ * Instantiate a select node.
3314
+ * @param {ExprNode} expr The select expression.
3315
+ * @param {string} alias The output name.
3316
+ */
3317
+ constructor(expr, alias) {
3318
+ super(SELECT_CLAUSE);
3319
+ this.expr = expr;
3320
+ this.alias = alias;
3321
+ }
3322
+ /**
3323
+ * Generate a SQL query string for this node.
3324
+ * @returns {string}
3325
+ */
3326
+ toString() {
3327
+ const { expr, alias } = this;
3328
+ return !alias || isColumnRefFor(expr, alias) ? `${expr}` : `${expr} AS ${quoteIdentifier(alias)}`;
3329
+ }
3330
+ };
3331
+ function isColumnRefFor(expr, name) {
3332
+ return expr instanceof ColumnRefNode && expr.table == null && expr.column === name;
3333
+ }
3334
+
3335
+ // ../sql/src/ast/with.js
3336
+ var WithClauseNode = class extends SQLNode {
3337
+ /**
3338
+ * Instantiate a with clause node for a common table expression (CTE).
3339
+ * @param {string} name The common table expression (CTE) name.
3340
+ * @param {Query} query The common table expression (CTE) query.
3341
+ */
3342
+ constructor(name, query) {
3343
+ super(WITH_CLAUSE);
3344
+ this.name = name;
3345
+ this.query = query;
3346
+ }
3347
+ toString() {
3348
+ return `"${this.name}" AS (${this.query})`;
3349
+ }
3350
+ };
3351
+
3352
+ // ../sql/src/ast/query.js
3353
+ function isQuery(value) {
3354
+ return value instanceof Query;
3355
+ }
3356
+ function isSelectQuery(value) {
3357
+ return value instanceof SelectQuery;
3358
+ }
3359
+ function isDescribeQuery(value) {
3360
+ return value instanceof DescribeQuery;
3361
+ }
3362
+ var Query = class extends ExprNode {
3363
+ /**
3364
+ * Create a new select query with the given SELECT expressions.
3365
+ * @param {...import('../types.js').SelectExpr} expr The SELECT expressions.
3366
+ * @returns {SelectQuery}
3367
+ */
3368
+ static select(...expr) {
3369
+ return new SelectQuery().select(...expr);
3370
+ }
3371
+ /**
3372
+ * Create a new select query with the given FROM expressions.
3373
+ * @param {...import('../types.js').FromExpr} expr The FROM expressions.
3374
+ * @returns {SelectQuery}
3375
+ */
3376
+ static from(...expr) {
3377
+ return new SelectQuery().from(...expr);
3378
+ }
3379
+ /**
3380
+ * Create a new select query with the given WITH CTE queries.
3381
+ * @param {...import('../types.js').WithExpr} expr The WITH CTE queries.
3382
+ * @returns {SelectQuery}
3383
+ */
3384
+ static with(...expr) {
3385
+ return new SelectQuery().with(...expr);
3386
+ }
3387
+ /**
3388
+ * Create a new UNION set operation over the given queries.
3389
+ * @param {...Query} queries The queries.
3390
+ * @returns {SetOperation}
3391
+ */
3392
+ static union(...queries) {
3393
+ return new SetOperation("UNION", queries.flat());
3394
+ }
3395
+ /**
3396
+ * Create a new UNION ALL set operation over the given queries.
3397
+ * @param {...Query} queries The queries.
3398
+ * @returns {SetOperation}
3399
+ */
3400
+ static unionAll(...queries) {
3401
+ return new SetOperation("UNION ALL", queries.flat());
3402
+ }
3403
+ /**
3404
+ * Create a new INTERSECT set operation over the given queries.
3405
+ * @param {...Query} queries The queries.
3406
+ * @returns {SetOperation}
3407
+ */
3408
+ static intersect(...queries) {
3409
+ return new SetOperation("INTERSECT", queries.flat());
3410
+ }
3411
+ /**
3412
+ * Create a new EXCEPT set operation over the given queries.
3413
+ * @param {...Query} queries The queries.
3414
+ * @returns {SetOperation}
3415
+ */
3416
+ static except(...queries) {
3417
+ return new SetOperation("EXCEPT", queries.flat());
3418
+ }
3419
+ /**
3420
+ * Create a new describe query for the given input query.
3421
+ * @param {Query} query The query to describe.
3422
+ * @returns {DescribeQuery}
3423
+ */
3424
+ static describe(query) {
3425
+ return new DescribeQuery(query);
3426
+ }
3427
+ /**
3428
+ * Instantiate a new query.
3429
+ */
3430
+ constructor(type) {
3431
+ super(type);
3432
+ this._orderby = [];
3433
+ this._limit = void 0;
3434
+ this._offset = void 0;
3435
+ this.cteFor = null;
3436
+ }
3437
+ /**
3438
+ * Return a list of subqueries.
3439
+ * @returns {Query[]}
3440
+ */
3441
+ get subqueries() {
3442
+ return [];
3443
+ }
3444
+ /**
3445
+ * Clone this query.
3446
+ * @returns {Query}
3447
+ */
3448
+ clone() {
3449
+ return this;
3450
+ }
3451
+ /**
3452
+ * Add ORDER BY expressions.
3453
+ * @param {...import('../types.js').OrderByExpr} expr Expressions to add.
3454
+ * @returns
3455
+ */
3456
+ orderby(...expr) {
3457
+ this._orderby = this._orderby.concat(exprList(expr));
3458
+ return this;
3459
+ }
3460
+ /**
3461
+ * Set the query result LIMIT.
3462
+ * @param {number} value The limit value.
3463
+ * @returns {this}
3464
+ */
3465
+ limit(value) {
3466
+ this._limit = Number.isFinite(value) ? value : void 0;
3467
+ return this;
3468
+ }
3469
+ /**
3470
+ * Set the query result OFFSET.
3471
+ * @param {number} value The offset value.
3472
+ * @returns {this}
3473
+ */
3425
3474
  offset(value) {
3426
- const { query } = this;
3427
- if (arguments.length === 0) {
3428
- return query.offset;
3475
+ this._offset = Number.isFinite(value) ? value : void 0;
3476
+ return this;
3477
+ }
3478
+ };
3479
+ var SelectQuery = class _SelectQuery extends Query {
3480
+ /**
3481
+ * Instantiate a new select query.
3482
+ */
3483
+ constructor() {
3484
+ super(SELECT_QUERY);
3485
+ this._with = [];
3486
+ this._select = [];
3487
+ this._from = [];
3488
+ this._where = [];
3489
+ this._sample = void 0;
3490
+ this._groupby = [];
3491
+ this._having = [];
3492
+ this._window = [];
3493
+ this._qualify = [];
3494
+ }
3495
+ /**
3496
+ * Return a list of subqueries.
3497
+ * @returns {Query[]}
3498
+ */
3499
+ get subqueries() {
3500
+ const q = this.cteFor || this;
3501
+ const w = q instanceof _SelectQuery ? q._with : [];
3502
+ const cte = w.reduce((obj, c) => (obj[c.name] = c.query, obj), {});
3503
+ const queries = [];
3504
+ this._from.forEach(({ expr }) => {
3505
+ if (isQuery(expr)) {
3506
+ queries.push(expr);
3507
+ } else if (isTableRef(expr)) {
3508
+ const subq = cte[expr.name];
3509
+ if (subq) queries.push(subq);
3510
+ }
3511
+ });
3512
+ return queries;
3513
+ }
3514
+ /**
3515
+ * Clone this query.
3516
+ * @returns {SelectQuery}
3517
+ */
3518
+ clone() {
3519
+ return Object.assign(new _SelectQuery(), this);
3520
+ }
3521
+ /**
3522
+ * Add WITH common table expressions (CTEs).
3523
+ * @param {...import('../types.js').WithExpr} expr Expressions to add.
3524
+ * @returns {this}
3525
+ */
3526
+ with(...expr) {
3527
+ const list2 = [];
3528
+ const add2 = (name, q) => {
3529
+ const query = q.clone();
3530
+ query.cteFor = this;
3531
+ list2.push(new WithClauseNode(name, query));
3532
+ };
3533
+ expr.flat().forEach((e) => {
3534
+ if (e != null) for (const name in e) add2(name, e[name]);
3535
+ });
3536
+ this._with = this._with.concat(list2);
3537
+ return this;
3538
+ }
3539
+ /**
3540
+ * Add SELECT expressions.
3541
+ * @param {...import('../types.js').SelectExpr} expr Expressions to add.
3542
+ * @returns {this}
3543
+ */
3544
+ select(...expr) {
3545
+ const list2 = [];
3546
+ const add2 = (v, as) => list2.push(
3547
+ new SelectClauseNode(v == null ? v : asNode(v), unquote(as))
3548
+ );
3549
+ expr.flat().forEach((e) => {
3550
+ if (e == null) return;
3551
+ else if (isString(e)) add2(e, e);
3552
+ else if (isColumnRef(e)) add2(e, e.column);
3553
+ else if (isArray2(e)) add2(e[1], e[0]);
3554
+ else for (const alias in e) add2(e[alias], alias);
3555
+ });
3556
+ const keys = new Set(list2.map((x2) => x2.alias));
3557
+ this._select = this._select.filter((x2) => !keys.has(x2.alias)).concat(list2.filter((x2) => x2.expr));
3558
+ return this;
3559
+ }
3560
+ /**
3561
+ * Set SELECT expressions, replacing any prior expressions.
3562
+ * @param {...import('../types.js').SelectExpr} expr Expressions to add.
3563
+ * @returns {this}
3564
+ */
3565
+ setSelect(...expr) {
3566
+ this._select = [];
3567
+ return this.select(...expr);
3568
+ }
3569
+ /**
3570
+ * Indicate if this query should retrieve distinct values only.
3571
+ * @param {boolean} value The distinct flag
3572
+ * @returns {this}
3573
+ */
3574
+ distinct(value = true) {
3575
+ this._distinct = !!value;
3576
+ return this;
3577
+ }
3578
+ /**
3579
+ * Add table FROM expressions.
3580
+ * @param {...import('../types.js').FromExpr} expr Expressions to add.
3581
+ * @returns {this}
3582
+ */
3583
+ from(...expr) {
3584
+ const list2 = [];
3585
+ const add2 = (v, as) => list2.push(new FromClauseNode(asTableRef(v), unquote(as)));
3586
+ expr.flat().forEach((e) => {
3587
+ if (e == null) return;
3588
+ else if (isString(e)) add2(e, e);
3589
+ else if (isTableRef(e)) add2(e, e.name);
3590
+ else if (isNode(e)) add2(e);
3591
+ else if (isArray2(e)) add2(e[1], e[0]);
3592
+ else for (const alias in e) add2(e[alias], alias);
3593
+ });
3594
+ this._from = this._from.concat(list2);
3595
+ return this;
3596
+ }
3597
+ /**
3598
+ * Set FROM expressions, replacing any prior expressions.
3599
+ * @param {...import('../types.js').FromExpr} expr Expressions to add.
3600
+ * @returns {this}
3601
+ */
3602
+ setFrom(...expr) {
3603
+ this._from = [];
3604
+ return this.from(...expr);
3605
+ }
3606
+ /**
3607
+ * Set SAMPLE settings.
3608
+ * @param {number | SampleClauseNode} value Either a sample clause node
3609
+ * or the sample size as either a row count or percentage.
3610
+ * @param {import('./sample.js').SampleMethod} [method] The sampling method
3611
+ * to use.
3612
+ * @param {number} [seed] The random seed.
3613
+ * @returns {this}
3614
+ */
3615
+ sample(value, method, seed) {
3616
+ let clause;
3617
+ if (typeof value === "number") {
3618
+ const perc = value > 0 && value < 1;
3619
+ const size = perc ? value * 100 : Math.floor(value);
3620
+ clause = new SampleClauseNode(size, perc, method, seed);
3429
3621
  } else {
3430
- query.offset = Number.isFinite(value) ? value : void 0;
3431
- return this;
3622
+ clause = value;
3432
3623
  }
3624
+ this._sample = clause;
3625
+ return this;
3433
3626
  }
3434
- get subqueries() {
3435
- const { query, cteFor } = this;
3436
- const ctes = (cteFor?.query || query).with;
3437
- const cte = ctes?.reduce((o, { as, query: query2 }) => (o[as] = query2, o), {});
3438
- const q = [];
3439
- query.from.forEach(({ from }) => {
3440
- if (isQuery(from)) {
3441
- q.push(from);
3442
- } else if (cte[from.table]) {
3443
- const sub = cte[from.table];
3444
- q.push(sub);
3627
+ /**
3628
+ * Add WHERE expressions.
3629
+ * @param {...import('../types.js').FilterExpr} expr Expressions to add.
3630
+ * @returns {this}
3631
+ */
3632
+ where(...expr) {
3633
+ this._where = this._where.concat(exprList(expr, asVerbatim));
3634
+ return this;
3635
+ }
3636
+ /**
3637
+ * Set WHERE expressions, replacing any prior expressions.
3638
+ * @param {...import('../types.js').FilterExpr} expr Expressions to add.
3639
+ * @returns {this}
3640
+ */
3641
+ setWhere(...expr) {
3642
+ this._where = [];
3643
+ return this.where(...expr);
3644
+ }
3645
+ /**
3646
+ * Add GROUP BY expressions.
3647
+ * @param {...import('../types.js').GroupByExpr} expr Expressions to add.
3648
+ * @returns {this}
3649
+ */
3650
+ groupby(...expr) {
3651
+ this._groupby = this._groupby.concat(exprList(expr));
3652
+ return this;
3653
+ }
3654
+ /**
3655
+ * Set GROUP BY expressions, replacing any prior expressions.
3656
+ * @param {...import('../types.js').GroupByExpr} expr Expressions to add.
3657
+ * @returns {this}
3658
+ */
3659
+ setGroupby(...expr) {
3660
+ this._groupby = [];
3661
+ return this.groupby(...expr);
3662
+ }
3663
+ /**
3664
+ * Add HAVING expressions.
3665
+ * @param {...import('../types.js').FilterExpr} expr Expressions to add.
3666
+ * @returns {this}
3667
+ */
3668
+ having(...expr) {
3669
+ this._having = this._having.concat(exprList(expr, asVerbatim));
3670
+ return this;
3671
+ }
3672
+ /**
3673
+ * Add WINDOW definitions.
3674
+ * @param {...any} expr Expressions to add.
3675
+ * @returns {this}
3676
+ */
3677
+ window(...expr) {
3678
+ const list2 = [];
3679
+ expr.flat().forEach((e) => {
3680
+ if (e != null) for (const name in e) {
3681
+ list2.push(new WindowClauseNode(unquote(name), e[name]));
3445
3682
  }
3446
3683
  });
3447
- return q;
3684
+ this._window = this._window.concat(list2);
3685
+ return this;
3686
+ }
3687
+ /**
3688
+ * Add QUALIFY expressions.
3689
+ * @param {...import('../types.js').FilterExpr} expr Expressions to add.
3690
+ * @returns {this}
3691
+ */
3692
+ qualify(...expr) {
3693
+ this._qualify = this._qualify.concat(exprList(expr, asVerbatim));
3694
+ return this;
3448
3695
  }
3696
+ /**
3697
+ * Generate a SQL query string.
3698
+ * @returns {string}
3699
+ */
3449
3700
  toString() {
3450
3701
  const {
3451
- with: cte,
3452
- select,
3453
- distinct: distinct2,
3454
- from,
3455
- sample,
3456
- where,
3457
- groupby,
3458
- having,
3459
- window,
3460
- qualify,
3461
- orderby,
3462
- limit,
3463
- offset
3464
- } = this.query;
3702
+ _with,
3703
+ _select,
3704
+ _distinct,
3705
+ _from,
3706
+ _sample,
3707
+ _where,
3708
+ _groupby,
3709
+ _having,
3710
+ _window,
3711
+ _qualify,
3712
+ _orderby,
3713
+ _limit,
3714
+ _offset
3715
+ } = this;
3465
3716
  const sql2 = [];
3466
- if (cte.length) {
3467
- const list2 = cte.map(({ as, query }) => `"${as}" AS (${query})`);
3468
- sql2.push(`WITH ${list2.join(", ")}`);
3469
- }
3470
- const sels = select.map(
3471
- ({ as, expr }) => isColumnRefFor(expr, as) && !expr.table ? `${expr}` : `${expr} AS "${as}"`
3472
- );
3473
- sql2.push(`SELECT${distinct2 ? " DISTINCT" : ""} ${sels.join(", ")}`);
3474
- if (from.length) {
3475
- const rels = from.map(({ as, from: from2 }) => {
3476
- const rel = isQuery(from2) ? `(${from2})` : `${from2}`;
3477
- return !as || as === from2.table ? rel : `${rel} AS "${as}"`;
3478
- });
3479
- sql2.push(`FROM ${rels.join(", ")}`);
3480
- }
3481
- if (where.length) {
3482
- const clauses = where.map(String).filter((x2) => x2).join(" AND ");
3717
+ if (_with.length) sql2.push(`WITH ${_with.join(", ")}`);
3718
+ sql2.push(`SELECT${_distinct ? " DISTINCT" : ""} ${_select.join(", ")}`);
3719
+ if (_from.length) sql2.push(`FROM ${_from.join(", ")}`);
3720
+ if (_where.length) {
3721
+ const clauses = _where.map(String).filter((x2) => x2).join(" AND ");
3483
3722
  if (clauses) sql2.push(`WHERE ${clauses}`);
3484
3723
  }
3485
- if (sample) {
3486
- const { rows, perc, method, seed } = sample;
3487
- const size = rows ? `${rows} ROWS` : `${perc} PERCENT`;
3488
- const how = method ? ` (${method}${seed != null ? `, ${seed}` : ""})` : "";
3489
- sql2.push(`USING SAMPLE ${size}${how}`);
3724
+ if (_sample) sql2.push(`USING SAMPLE ${_sample}`);
3725
+ if (_groupby.length) {
3726
+ sql2.push(`GROUP BY ${_groupby.join(", ")}`);
3490
3727
  }
3491
- if (groupby.length) {
3492
- sql2.push(`GROUP BY ${groupby.join(", ")}`);
3493
- }
3494
- if (having.length) {
3495
- const clauses = having.map(String).filter((x2) => x2).join(" AND ");
3728
+ if (_having.length) {
3729
+ const clauses = _having.map(String).filter((x2) => x2).join(" AND ");
3496
3730
  if (clauses) sql2.push(`HAVING ${clauses}`);
3497
3731
  }
3498
- if (window.length) {
3499
- const windows = window.map(({ as, expr }) => `"${as}" AS (${expr})`);
3500
- sql2.push(`WINDOW ${windows.join(", ")}`);
3501
- }
3502
- if (qualify.length) {
3503
- const clauses = qualify.map(String).filter((x2) => x2).join(" AND ");
3732
+ if (_window.length) sql2.push(`WINDOW ${_window.join(", ")}`);
3733
+ if (_qualify.length) {
3734
+ const clauses = _qualify.map(String).filter((x2) => x2).join(" AND ");
3504
3735
  if (clauses) sql2.push(`QUALIFY ${clauses}`);
3505
3736
  }
3506
- if (orderby.length) {
3507
- sql2.push(`ORDER BY ${orderby.join(", ")}`);
3508
- }
3509
- if (Number.isFinite(limit)) {
3510
- sql2.push(`LIMIT ${limit}`);
3511
- }
3512
- if (Number.isFinite(offset)) {
3513
- sql2.push(`OFFSET ${offset}`);
3514
- }
3737
+ if (_orderby.length) sql2.push(`ORDER BY ${_orderby.join(", ")}`);
3738
+ if (Number.isFinite(_limit)) sql2.push(`LIMIT ${_limit}`);
3739
+ if (Number.isFinite(_offset)) sql2.push(`OFFSET ${_offset}`);
3515
3740
  return sql2.join(" ");
3516
3741
  }
3517
3742
  };
3518
- var SetOperation = class _SetOperation {
3743
+ var DescribeQuery = class _DescribeQuery extends SQLNode {
3744
+ /**
3745
+ * Instantiate a describe query.
3746
+ */
3747
+ constructor(query) {
3748
+ super(DESCRIBE_QUERY);
3749
+ this.query = query;
3750
+ }
3751
+ /**
3752
+ * Clone this describe query.
3753
+ * @returns {DescribeQuery}
3754
+ */
3755
+ clone() {
3756
+ return new _DescribeQuery(this.query.clone());
3757
+ }
3758
+ /**
3759
+ * Generate a SQL query string.
3760
+ * @returns {string}
3761
+ */
3762
+ toString() {
3763
+ return `DESCRIBE ${this.query}`;
3764
+ }
3765
+ };
3766
+ var SetOperation = class _SetOperation extends Query {
3767
+ /**
3768
+ * Instantiate a new set operation instance.
3769
+ * @param {string} op The set operation.
3770
+ * @param {Query[]} queries The subqueries.
3771
+ */
3519
3772
  constructor(op, queries) {
3773
+ super(SET_OPERATION);
3520
3774
  this.op = op;
3521
- this.queries = queries.map((q) => q.clone());
3522
- this.query = { orderby: [] };
3523
- this.cteFor = null;
3775
+ this.queries = queries;
3524
3776
  }
3777
+ /**
3778
+ * Return a list of subqueries.
3779
+ * @returns {Query[]}
3780
+ */
3781
+ get subqueries() {
3782
+ const { queries, cteFor } = this;
3783
+ if (cteFor) queries.forEach((q) => q.cteFor = cteFor);
3784
+ return queries;
3785
+ }
3786
+ /**
3787
+ * Clone this set operation.
3788
+ * @returns {SetOperation}
3789
+ */
3525
3790
  clone() {
3526
- const q = new _SetOperation(this.op, this.queries);
3527
- q.query = { ...this.query };
3528
- return q;
3791
+ const { op, queries, ...rest } = this;
3792
+ return Object.assign(new _SetOperation(op, queries), rest);
3529
3793
  }
3530
- orderby(...expr) {
3531
- const { query } = this;
3532
- if (expr.length === 0) {
3533
- return query.orderby;
3794
+ /**
3795
+ * Generate a SQL query string.
3796
+ * @returns {string}
3797
+ */
3798
+ toString() {
3799
+ const { op, queries, _orderby, _limit, _offset } = this;
3800
+ const sql2 = [queries.join(` ${op} `)];
3801
+ if (_orderby.length) sql2.push(`ORDER BY ${_orderby.join(", ")}`);
3802
+ if (Number.isFinite(_limit)) sql2.push(`LIMIT ${_limit}`);
3803
+ if (Number.isFinite(_offset)) sql2.push(`OFFSET ${_offset}`);
3804
+ return sql2.join(" ");
3805
+ }
3806
+ };
3807
+
3808
+ // ../sql/src/ast/from.js
3809
+ var FromClauseNode = class extends SQLNode {
3810
+ /**
3811
+ * Instantiate a from node.
3812
+ * @param {SQLNode} expr The from expression.
3813
+ * @param {string} alias The output name.
3814
+ */
3815
+ constructor(expr, alias) {
3816
+ super(FROM_CLAUSE);
3817
+ this.expr = expr;
3818
+ this.alias = alias;
3819
+ }
3820
+ /**
3821
+ * Generate a SQL query string for this node.
3822
+ * @returns {string}
3823
+ */
3824
+ toString() {
3825
+ const { expr, alias } = this;
3826
+ const ref = isQuery(expr) ? `(${expr})` : `${expr}`;
3827
+ return alias && !(isTableRef(expr) && expr.table.join(".") === alias) ? `${ref} AS ${quoteIdentifier(alias)}` : `${ref}`;
3828
+ }
3829
+ };
3830
+
3831
+ // ../sql/src/ast/in-op.js
3832
+ var InOpNode = class extends ExprNode {
3833
+ /**
3834
+ * Instantiate an in operator node.
3835
+ * @param {ExprNode} expr The input expression.
3836
+ * @param {ExprNode[]} values The value set.
3837
+ */
3838
+ constructor(expr, values) {
3839
+ super(IN_OPERATOR);
3840
+ this.expr = expr;
3841
+ this.values = values;
3842
+ }
3843
+ /**
3844
+ * Generate a SQL query string for this node.
3845
+ * @returns {string}
3846
+ */
3847
+ toString() {
3848
+ return `(${this.expr} IN (${this.values.join(", ")}))`;
3849
+ }
3850
+ };
3851
+
3852
+ // ../sql/src/ast/logical-op.js
3853
+ var LogicalOpNode = class extends ExprNode {
3854
+ /**
3855
+ * Instantiate a logical operator node.
3856
+ * @param {string} op The logical operation.
3857
+ * @param {T[]} clauses The input clause expressions.
3858
+ */
3859
+ constructor(op, clauses) {
3860
+ super(LOGICAL_OPERATOR);
3861
+ this.op = op;
3862
+ this.clauses = clauses;
3863
+ }
3864
+ /**
3865
+ * Generate a SQL query string for this node.
3866
+ * @returns {string}
3867
+ */
3868
+ toString() {
3869
+ const c = this.clauses;
3870
+ return c.length === 0 ? "" : c.length === 1 ? `${c[0]}` : `(${c.join(` ${this.op} `)})`;
3871
+ }
3872
+ };
3873
+ var AndNode = class extends LogicalOpNode {
3874
+ /**
3875
+ * Instantiate a logical AND operator node.
3876
+ * @param {T[]} clauses The input clause expressions.
3877
+ */
3878
+ constructor(clauses) {
3879
+ super("AND", clauses);
3880
+ }
3881
+ };
3882
+ var OrNode = class extends LogicalOpNode {
3883
+ /**
3884
+ * Instantiate a logical OR operator node.
3885
+ * @param {T[]} clauses The input clause expressions.
3886
+ */
3887
+ constructor(clauses) {
3888
+ super("OR", clauses);
3889
+ }
3890
+ };
3891
+
3892
+ // ../sql/src/ast/order-by.js
3893
+ var OrderByNode = class extends ExprNode {
3894
+ /**
3895
+ * Instantiate an order by entry node.
3896
+ * @param {ExprNode} expr The expression to order by.
3897
+ * @param {boolean | undefined} [desc] Flag indicating descending order.
3898
+ * @param {boolean | undefined} [nullsFirst] Flag indicating if null
3899
+ * values should be sorted first.
3900
+ */
3901
+ constructor(expr, desc2, nullsFirst) {
3902
+ super(ORDER_BY);
3903
+ this.expr = expr;
3904
+ this.desc = desc2;
3905
+ this.nullsFirst = nullsFirst;
3906
+ }
3907
+ /**
3908
+ * Generate a SQL query string for this node.
3909
+ * @returns {string}
3910
+ */
3911
+ toString() {
3912
+ const { expr, desc: desc2, nullsFirst } = this;
3913
+ const dir = desc2 ? " DESC" : desc2 === false ? " ASC" : "";
3914
+ const nf = nullsFirst ? " NULLS FIRST" : nullsFirst === false ? " NULLS LAST" : "";
3915
+ return `${expr}${dir}${nf}`;
3916
+ }
3917
+ };
3918
+
3919
+ // ../sql/src/ast/unary-op.js
3920
+ var AbstractUnaryOpNode = class extends ExprNode {
3921
+ /**
3922
+ * Instantiate an abstract unary operator node.
3923
+ * @param {string} type The node type.
3924
+ * @param {string} op The operator type.
3925
+ * @param {ExprNode} expr The input expression.
3926
+ */
3927
+ constructor(type, op, expr) {
3928
+ super(type);
3929
+ this.op = op;
3930
+ this.expr = expr;
3931
+ }
3932
+ };
3933
+ var UnaryPosftixOpNode = class extends AbstractUnaryOpNode {
3934
+ /**
3935
+ * Instantiate a unary operator node.
3936
+ * @param {string} op The operator type.
3937
+ * @param {ExprNode} expr The input expression.
3938
+ */
3939
+ constructor(op, expr) {
3940
+ super(UNARY_POSTFIX_OPERATOR, op, expr);
3941
+ }
3942
+ /**
3943
+ * Generate a SQL query string for this node.
3944
+ * @returns {string}
3945
+ */
3946
+ toString() {
3947
+ return `(${this.expr} ${this.op})`;
3948
+ }
3949
+ };
3950
+
3951
+ // ../sql/src/functions/aggregate.js
3952
+ function argmax(y2, x2) {
3953
+ return aggFn("arg_max", y2, x2);
3954
+ }
3955
+ function argmin(y2, x2) {
3956
+ return aggFn("arg_min", y2, x2);
3957
+ }
3958
+ function count(expr) {
3959
+ return aggFn("count", expr);
3960
+ }
3961
+ function max(expr) {
3962
+ return aggFn("max", expr);
3963
+ }
3964
+ function min(expr) {
3965
+ return aggFn("min", expr);
3966
+ }
3967
+ function regrAvgX(x2, y2) {
3968
+ return aggFn("regr_avgx", x2, y2);
3969
+ }
3970
+ function regrAvgY(x2, y2) {
3971
+ return aggFn("regr_avgy", x2, y2);
3972
+ }
3973
+ function regrCount(x2, y2) {
3974
+ return aggFn("regr_count", x2, y2);
3975
+ }
3976
+ function sum(expr) {
3977
+ return aggFn("sum", expr);
3978
+ }
3979
+
3980
+ // ../sql/src/functions/cast.js
3981
+ function cast(expr, type) {
3982
+ return new CastNode(asNode(expr), type);
3983
+ }
3984
+ function int322(expr) {
3985
+ return cast(expr, "INTEGER");
3986
+ }
3987
+ function float642(expr) {
3988
+ return cast(expr, "DOUBLE");
3989
+ }
3990
+
3991
+ // ../sql/src/functions/datetime.js
3992
+ function epoch_ms(expr) {
3993
+ return fn("epoch_ms", expr);
3994
+ }
3995
+
3996
+ // ../sql/src/functions/numeric.js
3997
+ function exp(expr) {
3998
+ return fn("exp", expr);
3999
+ }
4000
+ function log(expr) {
4001
+ return fn("log", expr);
4002
+ }
4003
+ function ln(expr) {
4004
+ return fn("ln", expr);
4005
+ }
4006
+ function sign(expr) {
4007
+ return fn("sign", expr);
4008
+ }
4009
+ function abs(expr) {
4010
+ return fn("abs", expr);
4011
+ }
4012
+ function sqrt(expr) {
4013
+ return fn("sqrt", expr);
4014
+ }
4015
+ function ceil(expr) {
4016
+ return fn("ceil", expr);
4017
+ }
4018
+ function floor(expr) {
4019
+ return fn("floor", expr);
4020
+ }
4021
+ function round(expr, places) {
4022
+ return fn("round", expr, places);
4023
+ }
4024
+
4025
+ // ../sql/src/functions/operators.js
4026
+ function unaryPostfixOp(op, expr) {
4027
+ return new UnaryPosftixOpNode(op, asNode(expr));
4028
+ }
4029
+ function binaryOp(op, left, right) {
4030
+ return new BinaryOpNode(op, asNode(left), asNode(right));
4031
+ }
4032
+ function betweenOp(expr, extent, negate = false) {
4033
+ const Op = negate ? NotBetweenOpNode : BetweenOpNode;
4034
+ return new Op(asNode(expr), extent?.map(asNode));
4035
+ }
4036
+ function and(...clauses) {
4037
+ return new AndNode(exprList(clauses));
4038
+ }
4039
+ function or(...clauses) {
4040
+ return new OrNode(exprList(clauses));
4041
+ }
4042
+ function isNull(expr) {
4043
+ return unaryPostfixOp("IS NULL", expr);
4044
+ }
4045
+ function isNotNull(expr) {
4046
+ return unaryPostfixOp("IS NOT NULL", expr);
4047
+ }
4048
+ function add(left, right) {
4049
+ return binaryOp("+", left, right);
4050
+ }
4051
+ function sub(left, right) {
4052
+ return binaryOp("-", left, right);
4053
+ }
4054
+ function mul(left, right) {
4055
+ return binaryOp("*", left, right);
4056
+ }
4057
+ function div(left, right) {
4058
+ return binaryOp("/", left, right);
4059
+ }
4060
+ function pow(left, right) {
4061
+ return binaryOp("**", left, right);
4062
+ }
4063
+ function isNotDistinct(left, right) {
4064
+ return binaryOp("IS NOT DISTINCT FROM", left, right);
4065
+ }
4066
+ function isBetween(expr, extent) {
4067
+ return betweenOp(expr, extent, false);
4068
+ }
4069
+ function isIn(expr, values) {
4070
+ return new InOpNode(asNode(expr), values.map(asNode));
4071
+ }
4072
+
4073
+ // ../sql/src/functions/order-by.js
4074
+ function desc(expr, nullsFirst) {
4075
+ return new OrderByNode(asNode(expr), true, nullsFirst);
4076
+ }
4077
+
4078
+ // ../sql/src/functions/sql-template-tag.js
4079
+ function sql(strings, ...exprs) {
4080
+ return new FragmentNode(parseSQL(strings, exprs));
4081
+ }
4082
+ function parseSQL(strings, exprs) {
4083
+ const spans = [strings[0]];
4084
+ const n = exprs.length;
4085
+ for (let i = 0, k = 0; i < n; ) {
4086
+ const e = exprs[i];
4087
+ if (isNode(e)) {
4088
+ spans[++k] = e;
4089
+ } else if (isParamLike(e)) {
4090
+ spans[++k] = new ParamNode(e);
3534
4091
  } else {
3535
- query.orderby = query.orderby.concat(
3536
- expr.flat().filter((x2) => x2).map(asColumn)
3537
- );
3538
- return this;
4092
+ spans[k] += isString(e) ? e : literal(e);
3539
4093
  }
3540
- }
3541
- limit(value) {
3542
- const { query } = this;
3543
- if (arguments.length === 0) {
3544
- return query.limit;
4094
+ const s = strings[++i];
4095
+ if (isNode(spans[k])) {
4096
+ spans[++k] = s;
3545
4097
  } else {
3546
- query.limit = Number.isFinite(value) ? value : void 0;
3547
- return this;
4098
+ spans[k] += s;
3548
4099
  }
3549
4100
  }
3550
- offset(value) {
3551
- const { query } = this;
3552
- if (arguments.length === 0) {
3553
- return query.offset;
3554
- } else {
3555
- query.offset = Number.isFinite(value) ? value : void 0;
3556
- return this;
4101
+ return spans.filter((s) => s).map((s) => isString(s) ? new VerbatimNode(s) : s);
4102
+ }
4103
+
4104
+ // ../sql/src/functions/string.js
4105
+ function strFn(name, expr, ...args) {
4106
+ return fn(name, expr, ...argsList(args).map(asLiteral));
4107
+ }
4108
+ function regexp_matches(string, pattern, options) {
4109
+ return strFn("regexp_matches", string, pattern, options);
4110
+ }
4111
+ function contains(string, search_string) {
4112
+ return strFn("contains", string, search_string);
4113
+ }
4114
+ function prefix(string, search_string) {
4115
+ return strFn("starts_with", string, search_string);
4116
+ }
4117
+ function suffix(string, search_string) {
4118
+ return strFn("ends_with", string, search_string);
4119
+ }
4120
+
4121
+ // ../sql/src/visit/recurse.js
4122
+ var recurse = {
4123
+ [AGGREGATE]: ["args", "filter"],
4124
+ [BETWEEN_OPERATOR]: ["expr", "extent"],
4125
+ [BINARY_OPERATOR]: ["left", "right"],
4126
+ [CASE]: ["expr", "_when", "_else"],
4127
+ [CAST]: ["expr"],
4128
+ [COLUMN_PARAM]: ["param", "table"],
4129
+ [COLUMN_REF]: ["table"],
4130
+ [DESCRIBE_QUERY]: ["query"],
4131
+ [EXPRESSION]: ["node"],
4132
+ [FRAGMENT]: ["spans"],
4133
+ [FROM_CLAUSE]: ["expr"],
4134
+ [FUNCTION]: ["args"],
4135
+ [IN_OPERATOR]: ["expr", "values"],
4136
+ [LOGICAL_OPERATOR]: ["clauses"],
4137
+ [NOT_BETWEEN_OPERATOR]: ["expr", "extent"],
4138
+ [ORDER_BY]: ["expr"],
4139
+ [PARAM]: ["value"],
4140
+ [SELECT_CLAUSE]: ["expr"],
4141
+ [SELECT_QUERY]: ["_with", "_select", "_from", "_where", "_sample", "_groupby", "_having", "_window", "_qualify", "_orderby"],
4142
+ [SET_OPERATION]: ["subqueries", "_orderby"],
4143
+ [UNARY_OPERATOR]: ["expr"],
4144
+ [WHEN]: ["when", "then"],
4145
+ [WINDOW]: ["func", "def"],
4146
+ [WINDOW_CLAUSE]: ["def"],
4147
+ [WINDOW_DEF]: ["partition", "order", "frame"],
4148
+ [WINDOW_FRAME]: ["extent"]
4149
+ };
4150
+
4151
+ // ../sql/src/visit/rewrite.js
4152
+ function rewrite(node, map2) {
4153
+ if (map2.has(node)) {
4154
+ return map2.get(node);
4155
+ } else if (isNode(node)) {
4156
+ const props = recurse[node.type];
4157
+ const n = props?.length ?? 0;
4158
+ for (let i = 0; i < n; ++i) {
4159
+ const prop = props[i];
4160
+ const child = node[prop];
4161
+ if (Array.isArray(child)) {
4162
+ const m = child.length;
4163
+ for (let j = 0; j < m; ++j) {
4164
+ child[j] = rewrite(child[j], map2);
4165
+ }
4166
+ } else if (child) {
4167
+ node[prop] = rewrite(child, map2);
4168
+ }
3557
4169
  }
3558
4170
  }
3559
- get subqueries() {
3560
- const { queries, cteFor } = this;
3561
- if (cteFor) queries.forEach((q) => q.cteFor = cteFor);
3562
- return queries;
3563
- }
3564
- toString() {
3565
- const { op, queries, query: { orderby, limit, offset } } = this;
3566
- const sql2 = [queries.join(` ${op} `)];
3567
- if (orderby.length) {
3568
- sql2.push(`ORDER BY ${orderby.join(", ")}`);
3569
- }
3570
- if (Number.isFinite(limit)) {
3571
- sql2.push(`LIMIT ${limit}`);
3572
- }
3573
- if (Number.isFinite(offset)) {
3574
- sql2.push(`OFFSET ${offset}`);
4171
+ return node;
4172
+ }
4173
+
4174
+ // ../sql/src/visit/walk.js
4175
+ function walk(node, visit2) {
4176
+ if (!isNode(node)) return;
4177
+ const result = visit2(node);
4178
+ if (result) return result;
4179
+ const props = recurse[node.type];
4180
+ const n = props?.length ?? 0;
4181
+ for (let i = 0; i < n; ++i) {
4182
+ const value = node[props[i]];
4183
+ if (Array.isArray(value)) {
4184
+ const m = value.length;
4185
+ for (let j = 0; j < m; ++j) {
4186
+ if (value[j] && +walk(value[j], visit2) < 0) {
4187
+ return result;
4188
+ }
4189
+ }
4190
+ } else if (value && +walk(value, visit2) < 0) {
4191
+ return -1;
3575
4192
  }
3576
- return sql2.join(" ");
3577
4193
  }
3578
- };
3579
- function isQuery(value) {
3580
- return value instanceof Query || value instanceof SetOperation;
3581
4194
  }
3582
- function isDescribeQuery(value) {
3583
- return isQuery(value) && value.describe;
4195
+
4196
+ // ../sql/src/visit/visitors.js
4197
+ var aggrRegExp = new RegExp(`^(${aggregateNames.join("|")})$`);
4198
+ var funcRegExp = /(\\'|\\"|"(?:\\"|[^"])*"|'(?:\\'|[^'])*'|\w+\()/g;
4199
+ function hasVerbatimAggregate(s) {
4200
+ return s.split(funcRegExp).some((tok) => tok.endsWith("(") && aggrRegExp.test(tok.slice(0, -1)));
4201
+ }
4202
+ function isAggregateExpression(root) {
4203
+ let agg = 0;
4204
+ walk(root, (node) => {
4205
+ switch (node.type) {
4206
+ case WINDOW:
4207
+ return -1;
4208
+ // aggs can't include windows
4209
+ case AGGREGATE:
4210
+ agg |= 1;
4211
+ return -1;
4212
+ case FRAGMENT:
4213
+ case VERBATIM: {
4214
+ let s = `${node}`.toLowerCase();
4215
+ const sub2 = s.indexOf("(select ");
4216
+ if (sub2 >= 0) s = s.slice(0, sub2);
4217
+ if (s.includes(") over ")) return -1;
4218
+ if (hasVerbatimAggregate(s)) {
4219
+ agg |= 2;
4220
+ return -1;
4221
+ }
4222
+ return 1;
4223
+ }
4224
+ }
4225
+ });
4226
+ return agg;
3584
4227
  }
3585
- function unquote(s) {
3586
- return isDoubleQuoted(s) ? s.slice(1, -1) : s;
4228
+ function collectAggregates(root) {
4229
+ const aggs = /* @__PURE__ */ new Set();
4230
+ walk(root, (node) => {
4231
+ if (node.type === AGGREGATE) {
4232
+ aggs.add(node);
4233
+ }
4234
+ });
4235
+ return Array.from(aggs);
3587
4236
  }
3588
- function isDoubleQuoted(s) {
3589
- return s[0] === '"' && s[s.length - 1] === '"';
4237
+ function collectColumns(root) {
4238
+ const cols = {};
4239
+ walk(root, (node) => {
4240
+ if (node.type === COLUMN_REF) {
4241
+ cols[node] = node;
4242
+ }
4243
+ });
4244
+ return Object.values(cols);
4245
+ }
4246
+
4247
+ // ../sql/src/load/create.js
4248
+ function createTable2(name, query, {
4249
+ replace = false,
4250
+ temp = false,
4251
+ view = false
4252
+ } = {}) {
4253
+ return "CREATE" + (replace ? " OR REPLACE " : " ") + (temp ? "TEMP " : "") + (view ? "VIEW" : "TABLE") + (replace ? " " : " IF NOT EXISTS ") + name + " AS " + query;
3590
4254
  }
3591
4255
 
3592
- // ../sql/src/scales.js
4256
+ // ../sql/src/transforms/scales.js
3593
4257
  var identity = (x2) => x2;
3594
4258
  function scaleLinear() {
3595
4259
  return {
3596
4260
  apply: identity,
3597
4261
  invert: identity,
3598
- sqlApply: asColumn,
4262
+ sqlApply: asNode,
3599
4263
  sqlInvert: identity
3600
4264
  };
3601
4265
  }
@@ -3604,23 +4268,23 @@ function scaleLog({ base = null } = {}) {
3604
4268
  return {
3605
4269
  apply: Math.log,
3606
4270
  invert: Math.exp,
3607
- sqlApply: (c) => sql`LN(${asColumn(c)})`,
3608
- sqlInvert: (c) => sql`EXP(${c})`
4271
+ sqlApply: (c) => ln(c),
4272
+ sqlInvert: (c) => exp(c)
3609
4273
  };
3610
4274
  } else if (base === 10) {
3611
4275
  return {
3612
4276
  apply: Math.log10,
3613
4277
  invert: (x2) => Math.pow(10, x2),
3614
- sqlApply: (c) => sql`LOG(${asColumn(c)})`,
3615
- sqlInvert: (c) => sql`POW(10, ${c})`
4278
+ sqlApply: (c) => log(c),
4279
+ sqlInvert: (c) => pow(10, c)
3616
4280
  };
3617
4281
  } else {
3618
4282
  const b = +base;
3619
4283
  return {
3620
4284
  apply: (x2) => Math.log(x2) / Math.log(b),
3621
4285
  invert: (x2) => Math.pow(b, x2),
3622
- sqlApply: (c) => sql`LN(${asColumn(c)}) / LN(${b})`,
3623
- sqlInvert: (c) => sql`POW(${b}, ${c})`
4286
+ sqlApply: (c) => div(ln(c), ln(b)),
4287
+ sqlInvert: (c) => pow(b, c)
3624
4288
  };
3625
4289
  }
3626
4290
  }
@@ -3629,16 +4293,16 @@ function scaleSymlog({ constant = 1 } = {}) {
3629
4293
  return {
3630
4294
  apply: (x2) => Math.sign(x2) * Math.log1p(Math.abs(x2)),
3631
4295
  invert: (x2) => Math.sign(x2) * Math.exp(Math.abs(x2) - _),
3632
- sqlApply: (c) => (c = asColumn(c), sql`SIGN(${c}) * LN(${_} + ABS(${c}))`),
3633
- sqlInvert: (c) => sql`SIGN(${c}) * (EXP(ABS(${c})) - ${_})`
4296
+ sqlApply: (c) => (c = asNode(c), mul(sign(c), ln(add(_, abs(c))))),
4297
+ sqlInvert: (c) => mul(sign(c), sub(exp(abs(c)), _))
3634
4298
  };
3635
4299
  }
3636
4300
  function scaleSqrt() {
3637
4301
  return {
3638
4302
  apply: (x2) => Math.sign(x2) * Math.sqrt(Math.abs(x2)),
3639
4303
  invert: (x2) => Math.sign(x2) * x2 * x2,
3640
- sqlApply: (c) => (c = asColumn(c), sql`SIGN(${c}) * SQRT(ABS(${c}))`),
3641
- sqlInvert: (c) => sql`SIGN(${c}) * (${c}) ** 2`
4304
+ sqlApply: (c) => (c = asNode(c), mul(sign(c), sqrt(abs(c)))),
4305
+ sqlInvert: (c) => mul(sign(c), pow(c, 2))
3642
4306
  };
3643
4307
  }
3644
4308
  function scalePow({ exponent = 1 } = {}) {
@@ -3646,15 +4310,15 @@ function scalePow({ exponent = 1 } = {}) {
3646
4310
  return {
3647
4311
  apply: (x2) => Math.sign(x2) * Math.pow(Math.abs(x2), e),
3648
4312
  invert: (x2) => Math.sign(x2) * Math.pow(Math.abs(x2), 1 / e),
3649
- sqlApply: (c) => (c = asColumn(c), sql`SIGN(${c}) * POW(ABS(${c}), ${e})`),
3650
- sqlInvert: (c) => sql`SIGN(${c}) * POW(ABS(${c}), 1/${e})`
4313
+ sqlApply: (c) => (c = asNode(c), mul(sign(c), pow(abs(c), e))),
4314
+ sqlInvert: (c) => mul(sign(c), pow(abs(c), div(1, e)))
3651
4315
  };
3652
4316
  }
3653
4317
  function scaleTime() {
3654
4318
  return {
3655
4319
  apply: (x2) => +x2,
3656
4320
  invert: (x2) => new Date(x2),
3657
- sqlApply: (c) => c instanceof Date ? +c : epoch_ms(asColumn(c)),
4321
+ sqlApply: (c) => c instanceof Date ? literal(+c) : isDateLiteral(c) ? literal(+c.value) : epoch_ms(c),
3658
4322
  sqlInvert: identity
3659
4323
  };
3660
4324
  }
@@ -3672,259 +4336,8 @@ function scaleTransform(options) {
3672
4336
  const scale = scales[options.type];
3673
4337
  return scale ? { ...options, ...scale(options) } : null;
3674
4338
  }
3675
-
3676
- // ../sql/src/load/create.js
3677
- function create(name, query, {
3678
- replace = false,
3679
- temp = true,
3680
- view = false
3681
- } = {}) {
3682
- return "CREATE" + (replace ? " OR REPLACE " : " ") + (temp ? "TEMP " : "") + (view ? "VIEW" : "TABLE") + (replace ? " " : " IF NOT EXISTS ") + name + " AS " + query;
3683
- }
3684
-
3685
- // ../core/src/util/index-columns.js
3686
- function indexColumns(client) {
3687
- if (!client.filterIndexable) return null;
3688
- const q = client.query();
3689
- const from = getBase(q, (q2) => q2.from()?.[0].from.table);
3690
- if (typeof from !== "string" || !q.select) return null;
3691
- const aggr = [];
3692
- const dims = [];
3693
- const aux = {};
3694
- const avg2 = (ref) => {
3695
- const name = ref.column;
3696
- const expr = getBase(q, (q2) => q2.select().find((c) => c.as === name)?.expr);
3697
- return `(SELECT AVG(${expr ?? ref}) FROM "${from}")`;
3698
- };
3699
- for (const entry of q.select()) {
3700
- const { as, expr: { aggregate, args } } = entry;
3701
- const op = aggregate?.toUpperCase?.();
3702
- switch (op) {
3703
- case "COUNT":
3704
- case "SUM":
3705
- aggr.push({ [as]: agg`SUM("${as}")::DOUBLE` });
3706
- break;
3707
- case "AVG":
3708
- aggr.push({ [as]: avgExpr(aux, as, args[0]) });
3709
- break;
3710
- case "ARG_MAX":
3711
- aggr.push({ [as]: argmaxExpr(aux, as, args) });
3712
- break;
3713
- case "ARG_MIN":
3714
- aggr.push({ [as]: argminExpr(aux, as, args) });
3715
- break;
3716
- // variance statistics drop the original aggregate operation
3717
- // in favor of tracking auxiliary sufficient statistics
3718
- case "VARIANCE":
3719
- case "VAR_SAMP":
3720
- aux[as] = null;
3721
- aggr.push({ [as]: varianceExpr(aux, args[0], avg2) });
3722
- break;
3723
- case "VAR_POP":
3724
- aux[as] = null;
3725
- aggr.push({ [as]: varianceExpr(aux, args[0], avg2, false) });
3726
- break;
3727
- case "STDDEV":
3728
- case "STDDEV_SAMP":
3729
- aux[as] = null;
3730
- aggr.push({ [as]: agg`SQRT(${varianceExpr(aux, args[0], avg2)})` });
3731
- break;
3732
- case "STDDEV_POP":
3733
- aux[as] = null;
3734
- aggr.push({ [as]: agg`SQRT(${varianceExpr(aux, args[0], avg2, false)})` });
3735
- break;
3736
- case "COVAR_SAMP":
3737
- aux[as] = null;
3738
- aggr.push({ [as]: covarianceExpr(aux, args, avg2) });
3739
- break;
3740
- case "COVAR_POP":
3741
- aux[as] = null;
3742
- aggr.push({ [as]: covarianceExpr(aux, args, avg2, false) });
3743
- break;
3744
- case "CORR":
3745
- aux[as] = null;
3746
- aggr.push({ [as]: corrExpr(aux, args, avg2) });
3747
- break;
3748
- // regression statistics
3749
- case "REGR_COUNT":
3750
- aux[as] = null;
3751
- aggr.push({ [as]: agg`${regrCountExpr(aux, args)}::DOUBLE` });
3752
- break;
3753
- case "REGR_AVGX":
3754
- aux[as] = null;
3755
- aggr.push({ [as]: regrAvgXExpr(aux, args) });
3756
- break;
3757
- case "REGR_AVGY":
3758
- aux[as] = null;
3759
- aggr.push({ [as]: regrAvgYExpr(aux, args) });
3760
- break;
3761
- case "REGR_SYY":
3762
- aux[as] = null;
3763
- aggr.push({ [as]: regrVarExpr(aux, 0, args, avg2) });
3764
- break;
3765
- case "REGR_SXX":
3766
- aux[as] = null;
3767
- aggr.push({ [as]: regrVarExpr(aux, 1, args, avg2) });
3768
- break;
3769
- case "REGR_SXY":
3770
- aux[as] = null;
3771
- aggr.push({ [as]: covarianceExpr(aux, args, avg2, null) });
3772
- break;
3773
- case "REGR_SLOPE":
3774
- aux[as] = null;
3775
- aggr.push({ [as]: regrSlopeExpr(aux, args, avg2) });
3776
- break;
3777
- case "REGR_INTERCEPT":
3778
- aux[as] = null;
3779
- aggr.push({ [as]: regrInterceptExpr(aux, args, avg2) });
3780
- break;
3781
- case "REGR_R2":
3782
- aux[as] = null;
3783
- aggr.push({ [as]: agg`(${corrExpr(aux, args, avg2)}) ** 2` });
3784
- break;
3785
- // aggregates that commute directly
3786
- case "MAX":
3787
- case "MIN":
3788
- case "BIT_AND":
3789
- case "BIT_OR":
3790
- case "BIT_XOR":
3791
- case "BOOL_AND":
3792
- case "BOOL_OR":
3793
- case "PRODUCT":
3794
- aggr.push({ [as]: agg`${op}("${as}")` });
3795
- break;
3796
- // otherwise, check if dimension
3797
- default:
3798
- if (!aggregate) dims.push(as);
3799
- else return null;
3800
- }
3801
- }
3802
- if (!aggr.length) return null;
3803
- return { from, dims, aggr, aux };
3804
- }
3805
- function auxName(type, ...args) {
3806
- const cols = args.length ? "_" + args.map(sanitize).join("_") : "";
3807
- return `__${type}${cols}__`;
3808
- }
3809
- function sanitize(col) {
3810
- return `${col}`.replaceAll('"', "").replaceAll(" ", "_");
3811
- }
3812
- function getBase(query, get) {
3813
- const subq = query.subqueries;
3814
- if (query.select && subq.length === 0) {
3815
- return get(query);
3816
- }
3817
- const base = getBase(subq[0], get);
3818
- for (let i = 1; i < subq.length; ++i) {
3819
- const value = getBase(subq[i], get);
3820
- if (value === void 0) continue;
3821
- if (value !== base) return NaN;
3822
- }
3823
- return base;
3824
- }
3825
- function countExpr(aux, arg) {
3826
- const n = auxName("count", arg);
3827
- aux[n] = agg`COUNT(${arg})`;
3828
- return agg`SUM(${n})`.annotate({ name: n });
3829
- }
3830
- function avgExpr(aux, as, arg) {
3831
- const n = countExpr(aux, arg);
3832
- return agg`(SUM("${as}" * ${n.name}) / ${n})`;
3833
- }
3834
- function argmaxExpr(aux, as, [, y2]) {
3835
- const max2 = auxName("max", y2);
3836
- aux[max2] = agg`MAX(${y2})`;
3837
- return agg`ARG_MAX("${as}", ${max2})`;
3838
- }
3839
- function argminExpr(aux, as, [, y2]) {
3840
- const min2 = auxName("min", y2);
3841
- aux[min2] = agg`MIN(${y2})`;
3842
- return agg`ARG_MIN("${as}", ${min2})`;
3843
- }
3844
- function varianceExpr(aux, x2, avg2, correction = true) {
3845
- const n = countExpr(aux, x2);
3846
- const ssq = auxName("rssq", x2);
3847
- const sum2 = auxName("rsum", x2);
3848
- const delta = sql`${x2} - ${avg2(x2)}`;
3849
- aux[ssq] = agg`SUM((${delta}) ** 2)`;
3850
- aux[sum2] = agg`SUM(${delta})`;
3851
- const adj = correction ? ` - 1` : "";
3852
- return agg`(SUM(${ssq}) - (SUM(${sum2}) ** 2 / ${n})) / (${n}${adj})`;
3853
- }
3854
- function covarianceExpr(aux, args, avg2, correction = true) {
3855
- const n = regrCountExpr(aux, args);
3856
- const sxy = regrSumXYExpr(aux, args, avg2);
3857
- const sx = regrSumExpr(aux, 1, args, avg2);
3858
- const sy = regrSumExpr(aux, 0, args, avg2);
3859
- const adj = correction === null ? "" : correction ? ` / (${n} - 1)` : ` / ${n}`;
3860
- return agg`(${sxy} - ${sx} * ${sy} / ${n})${adj}`;
3861
- }
3862
- function corrExpr(aux, args, avg2) {
3863
- const n = regrCountExpr(aux, args);
3864
- const sxy = regrSumXYExpr(aux, args, avg2);
3865
- const sxx = regrSumSqExpr(aux, 1, args, avg2);
3866
- const syy = regrSumSqExpr(aux, 0, args, avg2);
3867
- const sx = regrSumExpr(aux, 1, args, avg2);
3868
- const sy = regrSumExpr(aux, 0, args, avg2);
3869
- const vx = agg`(${sxx} - (${sx} ** 2) / ${n})`;
3870
- const vy = agg`(${syy} - (${sy} ** 2) / ${n})`;
3871
- return agg`(${sxy} - ${sx} * ${sy} / ${n}) / SQRT(${vx} * ${vy})`;
3872
- }
3873
- function regrCountExpr(aux, [y2, x2]) {
3874
- const n = auxName("count", y2, x2);
3875
- aux[n] = agg`REGR_COUNT(${y2}, ${x2})`;
3876
- return agg`SUM(${n})`.annotate({ name: n });
3877
- }
3878
- function regrSumExpr(aux, i, args, avg2) {
3879
- const v = args[i];
3880
- const o = args[1 - i];
3881
- const sum2 = auxName("rs", v);
3882
- aux[sum2] = agg`SUM(${v} - ${avg2(v)}) FILTER (${o} IS NOT NULL)`;
3883
- return agg`SUM(${sum2})`;
3884
- }
3885
- function regrSumSqExpr(aux, i, args, avg2) {
3886
- const v = args[i];
3887
- const u = args[1 - i];
3888
- const ssq = auxName("rss", v);
3889
- aux[ssq] = agg`SUM((${v} - ${avg2(v)}) ** 2) FILTER (${u} IS NOT NULL)`;
3890
- return agg`SUM(${ssq})`;
3891
- }
3892
- function regrSumXYExpr(aux, args, avg2) {
3893
- const [y2, x2] = args;
3894
- const sxy = auxName("sxy", y2, x2);
3895
- aux[sxy] = agg`SUM((${x2} - ${avg2(x2)}) * (${y2} - ${avg2(y2)}))`;
3896
- return agg`SUM(${sxy})`;
3897
- }
3898
- function regrAvgXExpr(aux, args) {
3899
- const [y2, x2] = args;
3900
- const n = regrCountExpr(aux, args);
3901
- const a = auxName("avg", x2, y2);
3902
- aux[a] = agg`REGR_AVGX(${y2}, ${x2})`;
3903
- return agg`(SUM(${a} * ${n.name}) / ${n})`;
3904
- }
3905
- function regrAvgYExpr(aux, args) {
3906
- const [y2, x2] = args;
3907
- const n = regrCountExpr(aux, args);
3908
- const a = auxName("avg", y2, x2);
3909
- aux[a] = agg`REGR_AVGY(${y2}, ${x2})`;
3910
- return agg`(SUM(${a} * ${n.name}) / ${n})`;
3911
- }
3912
- function regrVarExpr(aux, i, args, avg2) {
3913
- const n = regrCountExpr(aux, args);
3914
- const sum2 = regrSumExpr(aux, i, args, avg2);
3915
- const ssq = regrSumSqExpr(aux, i, args, avg2);
3916
- return agg`(${ssq} - (${sum2} ** 2 / ${n}))`;
3917
- }
3918
- function regrSlopeExpr(aux, args, avg2) {
3919
- const cov = covarianceExpr(aux, args, avg2, null);
3920
- const varx = regrVarExpr(aux, 1, args, avg2);
3921
- return agg`(${cov}) / ${varx}`;
3922
- }
3923
- function regrInterceptExpr(aux, args, avg2) {
3924
- const ax = regrAvgXExpr(aux, args);
3925
- const ay = regrAvgYExpr(aux, args);
3926
- const m = regrSlopeExpr(aux, args, avg2);
3927
- return agg`${ay} - (${m}) * ${ax}`;
4339
+ function isDateLiteral(x2) {
4340
+ return x2 instanceof LiteralNode && x2.value instanceof Date;
3928
4341
  }
3929
4342
 
3930
4343
  // ../core/src/util/hash.js
@@ -3936,7 +4349,7 @@ function fnv_hash(v) {
3936
4349
  if (d) a = fnv_multiply(a ^ d >> 8);
3937
4350
  a = fnv_multiply(a ^ c & 255);
3938
4351
  }
3939
- return fnv_mix(a);
4352
+ return fnv_mix(a) >>> 0;
3940
4353
  }
3941
4354
  function fnv_multiply(a) {
3942
4355
  return a + (a << 1) + (a << 4) + (a << 7) + (a << 8) + (a << 24);
@@ -3950,28 +4363,267 @@ function fnv_mix(a) {
3950
4363
  return a & 4294967295;
3951
4364
  }
3952
4365
 
3953
- // ../core/src/DataCubeIndexer.js
4366
+ // ../core/src/preagg/sufficient-statistics.js
4367
+ function sufficientStatistics(node, preagg, avg2) {
4368
+ switch (node.name) {
4369
+ case "count":
4370
+ case "sum":
4371
+ return sumExpr(preagg, node);
4372
+ case "avg":
4373
+ return avgExpr(preagg, node);
4374
+ case "arg_max":
4375
+ return argmaxExpr(preagg, node);
4376
+ case "arg_min":
4377
+ return argminExpr(preagg, node);
4378
+ // variance statistics drop the original aggregate operation
4379
+ // in favor of tracking sufficient statistics
4380
+ case "variance":
4381
+ case "var_samp":
4382
+ return varianceExpr(preagg, node, avg2);
4383
+ case "var_pop":
4384
+ return varianceExpr(preagg, node, avg2, false);
4385
+ case "stddev":
4386
+ case "stddev_samp":
4387
+ return sqrt(varianceExpr(preagg, node, avg2));
4388
+ case "stddev_pop":
4389
+ return sqrt(varianceExpr(preagg, node, avg2, false));
4390
+ case "covar_samp":
4391
+ return covarianceExpr(preagg, node, avg2);
4392
+ case "covar_pop":
4393
+ return covarianceExpr(preagg, node, avg2, false);
4394
+ case "corr":
4395
+ return corrExpr(preagg, node, avg2);
4396
+ // regression statistics
4397
+ case "regr_count":
4398
+ return regrCountExpr(preagg, node).expr;
4399
+ case "regr_avgx":
4400
+ return regrAvgXExpr(preagg, node);
4401
+ case "regr_avgy":
4402
+ return regrAvgYExpr(preagg, node);
4403
+ case "regr_syy":
4404
+ return regrVarExpr(preagg, 0, node, avg2);
4405
+ case "regr_sxx":
4406
+ return regrVarExpr(preagg, 1, node, avg2);
4407
+ case "regr_sxy":
4408
+ return covarianceExpr(preagg, node, avg2, null);
4409
+ case "regr_slope":
4410
+ return regrSlopeExpr(preagg, node, avg2);
4411
+ case "regr_intercept":
4412
+ return regrInterceptExpr(preagg, node, avg2);
4413
+ case "regr_r2":
4414
+ return pow(corrExpr(preagg, node, avg2), 2);
4415
+ // aggregates that commute directly
4416
+ case "max":
4417
+ case "min":
4418
+ case "bit_and":
4419
+ case "bit_or":
4420
+ case "bit_xor":
4421
+ case "bool_and":
4422
+ case "bool_or":
4423
+ case "product": {
4424
+ const name = colName(node);
4425
+ preagg[name] = node;
4426
+ return sql`${node.name}("${name}")`;
4427
+ }
4428
+ // unsupported aggregate, return null to indicate failure
4429
+ default:
4430
+ return null;
4431
+ }
4432
+ }
4433
+ function colName(node) {
4434
+ return "pre_" + fnv_hash(`${node}`).toString(16);
4435
+ }
4436
+ function addStat(preagg, expr, node) {
4437
+ const filter = node?.filter;
4438
+ if (filter) {
4439
+ expr = expr.filter ? expr.where(and(filter, expr.filter)) : expr.where(filter);
4440
+ }
4441
+ const name = colName(expr);
4442
+ preagg[name] = expr;
4443
+ return name;
4444
+ }
4445
+ function countExpr(preagg, node) {
4446
+ const name = addStat(preagg, count(node.args[0]), node);
4447
+ return { expr: sum(name), name };
4448
+ }
4449
+ function sumExpr(preagg, node) {
4450
+ return sum(addStat(preagg, node));
4451
+ }
4452
+ function avgExpr(preagg, node) {
4453
+ const as = addStat(preagg, node);
4454
+ const { expr, name } = countExpr(preagg, node);
4455
+ return div(sum(mul(as, name)), expr);
4456
+ }
4457
+ function argmaxExpr(preagg, node) {
4458
+ const expr = addStat(preagg, node);
4459
+ const maxy = addStat(preagg, max(node.args[1]), node);
4460
+ return argmax(expr, maxy);
4461
+ }
4462
+ function argminExpr(preagg, node) {
4463
+ const expr = addStat(preagg, node);
4464
+ const miny = addStat(preagg, min(node.args[1]), node);
4465
+ return argmin(expr, miny);
4466
+ }
4467
+ function varianceExpr(preagg, node, avg2, correction = true) {
4468
+ const x2 = node.args[0];
4469
+ const { expr: n } = countExpr(preagg, node);
4470
+ const delta = sub(x2, avg2(x2));
4471
+ const rssq = addStat(preagg, sum(pow(delta, 2)), node);
4472
+ const rsum = addStat(preagg, sum(delta), node);
4473
+ const denom = correction ? sub(n, 1) : n;
4474
+ return div(sub(sum(rssq), div(pow(sum(rsum), 2), n)), denom);
4475
+ }
4476
+ function covarianceExpr(preagg, node, avg2, correction = true) {
4477
+ const { expr: n } = regrCountExpr(preagg, node);
4478
+ const sxy = regrSumXYExpr(preagg, node, avg2);
4479
+ const sx = regrSumExpr(preagg, 1, node, avg2);
4480
+ const sy = regrSumExpr(preagg, 0, node, avg2);
4481
+ const num = sub(sxy, div(mul(sx, sy), n));
4482
+ return correction === null ? num : correction ? div(num, sub(n, 1)) : div(num, n);
4483
+ }
4484
+ function corrExpr(preagg, node, avg2) {
4485
+ const { expr: n } = regrCountExpr(preagg, node);
4486
+ const sxy = regrSumXYExpr(preagg, node, avg2);
4487
+ const sxx = regrSumSqExpr(preagg, 1, node, avg2);
4488
+ const syy = regrSumSqExpr(preagg, 0, node, avg2);
4489
+ const sx = regrSumExpr(preagg, 1, node, avg2);
4490
+ const sy = regrSumExpr(preagg, 0, node, avg2);
4491
+ const vx = sub(sxx, div(pow(sx, 2), n));
4492
+ const vy = sub(syy, div(pow(sy, 2), n));
4493
+ return div(
4494
+ sub(sxy, div(mul(sx, sy), n)),
4495
+ sqrt(mul(vx, vy))
4496
+ );
4497
+ }
4498
+ function regrCountExpr(preagg, node) {
4499
+ const [x2, y2] = node.args;
4500
+ const n = addStat(preagg, regrCount(x2, y2), node);
4501
+ return { expr: sum(n), name: n };
4502
+ }
4503
+ function regrSumExpr(preagg, i, node, avg2) {
4504
+ const args = node.args;
4505
+ const v = args[i];
4506
+ const o = args[1 - i];
4507
+ const rsum = sum(sub(v, avg2(v))).where(isNotNull(o));
4508
+ return sum(addStat(preagg, rsum, node));
4509
+ }
4510
+ function regrSumSqExpr(preagg, i, node, avg2) {
4511
+ const args = node.args;
4512
+ const v = args[i];
4513
+ const u = args[1 - i];
4514
+ const ssq = sum(pow(sub(v, avg2(v)), 2)).where(isNotNull(u));
4515
+ return sum(addStat(preagg, ssq, node));
4516
+ }
4517
+ function regrSumXYExpr(preagg, node, avg2) {
4518
+ const [y2, x2] = node.args;
4519
+ const sxy = sum(mul(sub(x2, avg2(x2)), sub(y2, avg2(y2))));
4520
+ return sum(addStat(preagg, sxy, node));
4521
+ }
4522
+ function regrAvgXExpr(preagg, node) {
4523
+ const [y2, x2] = node.args;
4524
+ const { expr: n, name } = regrCountExpr(preagg, node);
4525
+ const a = addStat(preagg, regrAvgX(y2, x2), node);
4526
+ return div(sum(mul(a, name)), n);
4527
+ }
4528
+ function regrAvgYExpr(preagg, node) {
4529
+ const [y2, x2] = node.args;
4530
+ const { expr: n, name } = regrCountExpr(preagg, node);
4531
+ const a = addStat(preagg, regrAvgY(y2, x2), node);
4532
+ return div(sum(mul(a, name)), n);
4533
+ }
4534
+ function regrVarExpr(preagg, i, node, avg2) {
4535
+ const { expr: n } = regrCountExpr(preagg, node);
4536
+ const sum2 = regrSumExpr(preagg, i, node, avg2);
4537
+ const ssq = regrSumSqExpr(preagg, i, node, avg2);
4538
+ return sub(ssq, div(pow(sum2, 2), n));
4539
+ }
4540
+ function regrSlopeExpr(preagg, node, avg2) {
4541
+ const cov = covarianceExpr(preagg, node, avg2, null);
4542
+ const varx = regrVarExpr(preagg, 1, node, avg2);
4543
+ return div(cov, varx);
4544
+ }
4545
+ function regrInterceptExpr(preagg, node, avg2) {
4546
+ const ax = regrAvgXExpr(preagg, node);
4547
+ const ay = regrAvgYExpr(preagg, node);
4548
+ const m = regrSlopeExpr(preagg, node, avg2);
4549
+ return sub(ay, mul(m, ax));
4550
+ }
4551
+
4552
+ // ../core/src/preagg/preagg-columns.js
4553
+ function preaggColumns(client) {
4554
+ if (!client.filterStable) return null;
4555
+ const q = client.query();
4556
+ if (!isSelectQuery(q)) return null;
4557
+ const from = getBase(q, (q2) => {
4558
+ const ref = q2._from[0]?.expr;
4559
+ return isTableRef(ref) ? ref.name : ref;
4560
+ });
4561
+ if (typeof from !== "string") return null;
4562
+ const aggrs = /* @__PURE__ */ new Map();
4563
+ const preagg = {};
4564
+ const output = {};
4565
+ const group = [];
4566
+ const avg2 = (ref) => {
4567
+ const name = ref.column;
4568
+ const expr = getBase(q, (q2) => q2._select.find((c) => c.alias === name)?.expr);
4569
+ return sql`(SELECT avg(${expr ?? ref}) FROM "${from}")`;
4570
+ };
4571
+ for (const { alias, expr } of q._select) {
4572
+ if (isAggregateExpression(expr) > 1) return null;
4573
+ const nodes = collectAggregates(expr);
4574
+ if (nodes.length === 0) {
4575
+ group.push(alias);
4576
+ preagg[alias] = expr;
4577
+ } else {
4578
+ for (const node of nodes) {
4579
+ if (node.isDistinct) return null;
4580
+ const agg = sufficientStatistics(node, preagg, avg2);
4581
+ if (!agg) return null;
4582
+ aggrs.set(node, agg);
4583
+ }
4584
+ output[alias] = rewrite(expr, aggrs);
4585
+ }
4586
+ }
4587
+ if (!aggrs.size) return null;
4588
+ return { group, preagg, output };
4589
+ }
4590
+ function getBase(query, get) {
4591
+ const subq = query.subqueries;
4592
+ if (isSelectQuery(query) && subq.length === 0) {
4593
+ return get(query);
4594
+ }
4595
+ const base = getBase(subq[0], get);
4596
+ for (let i = 1; i < subq.length; ++i) {
4597
+ const value = getBase(subq[i], get);
4598
+ if (value === void 0) continue;
4599
+ if (value !== base) return NaN;
4600
+ }
4601
+ return base;
4602
+ }
4603
+
4604
+ // ../core/src/preagg/PreAggregator.js
3954
4605
  var Skip = { skip: true, result: null };
3955
- var DataCubeIndexer = class {
4606
+ var PreAggregator = class {
3956
4607
  /**
3957
- * Create a new data cube index table manager.
3958
- * @param {import('./Coordinator.js').Coordinator} coordinator A Mosaic coordinator.
3959
- * @param {DataCubeIndexerOptions} [options] Data cube indexer options.
4608
+ * Create a new manager of materialized views of pre-aggregated data.
4609
+ * @param {import('../Coordinator.js').Coordinator} coordinator A Mosaic coordinator.
4610
+ * @param {PreAggregateOptions} [options] Pre-aggregation options.
3960
4611
  */
3961
4612
  constructor(coordinator2, {
3962
4613
  schema = "mosaic",
3963
4614
  enabled = true
3964
4615
  } = {}) {
3965
- this.indexes = /* @__PURE__ */ new Map();
4616
+ this.entries = /* @__PURE__ */ new Map();
3966
4617
  this.active = null;
3967
4618
  this.mc = coordinator2;
3968
4619
  this._schema = schema;
3969
4620
  this._enabled = enabled;
3970
4621
  }
3971
4622
  /**
3972
- * Set the enabled state of this indexer. If false, any local state is
3973
- * cleared and subsequent index calls will return null until re-enabled.
3974
- * This method has no effect on any index tables already in the database.
4623
+ * Set the enabled state of this manager. If false, any local state is
4624
+ * cleared and subsequent request calls will return null until re-enabled.
4625
+ * This method has no effect on any pre-aggregated tables already in the
4626
+ * database.
3975
4627
  * @param {boolean} [state] The enabled state to set.
3976
4628
  */
3977
4629
  set enabled(state) {
@@ -3981,17 +4633,17 @@ var DataCubeIndexer = class {
3981
4633
  }
3982
4634
  }
3983
4635
  /**
3984
- * Get the enabled state of this indexer.
4636
+ * Get the enabled state of this manager.
3985
4637
  * @returns {boolean} The current enabled state.
3986
4638
  */
3987
4639
  get enabled() {
3988
4640
  return this._enabled;
3989
4641
  }
3990
4642
  /**
3991
- * Set the database schema used by this indexer. Upon changes, any local
3992
- * state is cleared. This method does _not_ drop any existing data cube
3993
- * tables, use `dropIndexTables` before changing the schema to also remove
3994
- * existing index tables in the database.
4643
+ * Set the database schema used for pre-aggregated materialized view tables.
4644
+ * Upon changes, any local state is cleared. This method does _not_ drop any
4645
+ * existing materialized views, use `dropSchema` before changing the schema
4646
+ * to also remove existing materalized views in the database.
3995
4647
  * @param {string} [schema] The schema name to set.
3996
4648
  */
3997
4649
  set schema(schema) {
@@ -4001,52 +4653,52 @@ var DataCubeIndexer = class {
4001
4653
  }
4002
4654
  }
4003
4655
  /**
4004
- * Get the database schema used by this indexer.
4656
+ * Get the database schema used for pre-aggregated materialized view tables.
4005
4657
  * @returns {string} The current schema name.
4006
4658
  */
4007
4659
  get schema() {
4008
4660
  return this._schema;
4009
4661
  }
4010
4662
  /**
4011
- * Issues a query through the coordinator to drop the current index table
4012
- * schema. *All* tables in the schema will be removed and local state is
4013
- * cleared. Call this method if the underlying base tables have been updated,
4014
- * causing derived index tables to become stale and inaccurate. Use this
4015
- * method with care! Once dropped, the schema will be repopulated by future
4016
- * data cube indexer requests.
4663
+ * Issues a query through the coordinator to drop the current schema for
4664
+ * pre-aggregated materialized views. *All* materialized view tables in the
4665
+ * schema will be removed and local state is cleared. Call this method if
4666
+ * the underlying base tables have been updated, causing materialized view
4667
+ * to become stale and inaccurate. Use this method with care! Once dropped,
4668
+ * the schema will be repopulated by future pre-aggregation requests.
4017
4669
  * @returns A query result promise.
4018
4670
  */
4019
- dropIndexTables() {
4671
+ dropSchema() {
4020
4672
  this.clear();
4021
4673
  return this.mc.exec(`DROP SCHEMA IF EXISTS "${this.schema}" CASCADE`);
4022
4674
  }
4023
4675
  /**
4024
- * Clear the cache of data cube index table entries for the current active
4025
- * selection clause. This method does _not_ drop any existing data cube
4026
- * tables. Use `dropIndexTables` to remove existing index tables from the
4027
- * database.
4676
+ * Clear the cache of pre-aggregation entries for the current active
4677
+ * selection clause. This method does _not_ drop any existing materialized
4678
+ * views. Use `dropSchema` to remove existing materialized view tables from
4679
+ * the database.
4028
4680
  */
4029
4681
  clear() {
4030
- this.indexes.clear();
4682
+ this.entries.clear();
4031
4683
  this.active = null;
4032
4684
  }
4033
4685
  /**
4034
- * Return data cube index table information for the active state of a
4035
- * client-selection pair, or null if the client is not indexable. This
4036
- * method has multiple possible side effects, including data cube table
4037
- * generation and updating internal caches.
4038
- * @param {import('./MosaicClient.js').MosaicClient} client A Mosaic client.
4039
- * @param {import('./Selection.js').Selection} selection A Mosaic selection
4686
+ * Return pre-aggregation information for the active state of a
4687
+ * client-selection pair, or null if the client has unstable filters.
4688
+ * This method has multiple possible side effects, including materialized
4689
+ * view creation and updating internal caches.
4690
+ * @param {import('../MosaicClient.js').MosaicClient} client A Mosaic client.
4691
+ * @param {import('../Selection.js').Selection} selection A Mosaic selection
4040
4692
  * to filter the client by.
4041
- * @param {import('./util/selection-types.js').SelectionClause} activeClause
4693
+ * @param {import('../util/selection-types.js').SelectionClause} activeClause
4042
4694
  * A representative active selection clause for which to (possibly) generate
4043
- * data cube index tables.
4044
- * @returns {DataCubeInfo | Skip | null} Data cube index table
4045
- * information and query generator, or null if the client is not indexable.
4695
+ * materialized views of pre-aggregates.
4696
+ * @returns {PreAggregateInfo | Skip | null} Information and query generator
4697
+ * for pre-aggregated tables, or null if the client has unstable filters.
4046
4698
  */
4047
- index(client, selection, activeClause) {
4699
+ request(client, selection, activeClause) {
4048
4700
  if (!this.enabled) return null;
4049
- const { indexes, mc, schema } = this;
4701
+ const { entries, mc, schema } = this;
4050
4702
  const { source } = activeClause;
4051
4703
  if (!source) return null;
4052
4704
  if (this.active) {
@@ -4058,32 +4710,32 @@ var DataCubeIndexer = class {
4058
4710
  this.active = active = activeColumns(activeClause);
4059
4711
  if (active.source === null) return null;
4060
4712
  }
4061
- if (indexes.has(client)) {
4062
- return indexes.get(client);
4713
+ if (entries.has(client)) {
4714
+ return entries.get(client);
4063
4715
  }
4064
- const indexCols = indexColumns(client);
4716
+ const preaggCols = preaggColumns(client);
4065
4717
  let info;
4066
- if (!indexCols) {
4718
+ if (!preaggCols) {
4067
4719
  info = null;
4068
4720
  } else if (selection.skip(client, activeClause)) {
4069
4721
  info = Skip;
4070
4722
  } else {
4071
4723
  const filter = selection.remove(source).predicate(client);
4072
- info = dataCubeInfo(client.query(filter), active, indexCols, schema);
4724
+ info = preaggregateInfo(client.query(filter), active, preaggCols, schema);
4073
4725
  info.result = mc.exec([
4074
4726
  `CREATE SCHEMA IF NOT EXISTS ${schema}`,
4075
- create(info.table, info.create, { temp: false })
4727
+ createTable2(info.table, info.create, { temp: false })
4076
4728
  ]);
4077
4729
  info.result.catch((e) => mc.logger().error(e));
4078
4730
  }
4079
- indexes.set(client, info);
4731
+ entries.set(client, info);
4080
4732
  return info;
4081
4733
  }
4082
4734
  };
4083
4735
  function activeColumns(clause) {
4084
4736
  const { source, meta } = clause;
4085
4737
  const clausePred = clause.predicate;
4086
- const clauseCols = clausePred?.columns;
4738
+ const clauseCols = collectColumns(clausePred).map((c) => c.column);
4087
4739
  let predicate;
4088
4740
  let columns;
4089
4741
  if (!meta || !clauseCols) {
@@ -4093,92 +4745,206 @@ function activeColumns(clause) {
4093
4745
  if (type === "point") {
4094
4746
  predicate = (x2) => x2;
4095
4747
  columns = Object.fromEntries(
4096
- clauseCols.map((col) => [`${col}`, asColumn(col)])
4748
+ clauseCols.map((col) => [`${col}`, asNode(col)])
4097
4749
  );
4098
4750
  } else if (type === "interval" && scales2) {
4099
4751
  const bins = scales2.map((s) => binInterval(s, pixelSize, bin));
4100
4752
  if (bins.some((b) => !b)) {
4101
4753
  } else if (bins.length === 1) {
4102
- predicate = (p) => p ? isBetween("active0", p.range.map(bins[0])) : [];
4103
- columns = { active0: bins[0](clausePred.field) };
4754
+ predicate = (p) => p ? isBetween("active0", p.extent.map(bins[0])) : [];
4755
+ columns = { active0: bins[0](clausePred.expr) };
4104
4756
  } else {
4105
- predicate = (p) => p ? and(p.children.map(
4106
- ({ range }, i) => isBetween(`active${i}`, range.map(bins[i]))
4757
+ predicate = (p) => p ? and(p.clauses.map(
4758
+ (c, i) => isBetween(`active${i}`, c.extent.map(bins[i]))
4107
4759
  )) : [];
4108
4760
  columns = Object.fromEntries(
4109
4761
  // @ts-ignore
4110
- clausePred.children.map((p, i) => [`active${i}`, bins[i](p.field)])
4762
+ clausePred.clauses.map((p, i) => [`active${i}`, bins[i](p.expr)])
4111
4763
  );
4112
4764
  }
4113
4765
  }
4114
4766
  return { source: columns ? source : null, columns, predicate };
4115
4767
  }
4116
- var BIN = { ceil: "CEIL", round: "ROUND" };
4768
+ var BIN = { ceil, round };
4117
4769
  function binInterval(scale, pixelSize, bin) {
4118
4770
  const { type, domain, range, apply, sqlApply } = scaleTransform(scale);
4119
4771
  if (!apply) return;
4120
- const fn = BIN[`${bin}`.toLowerCase()] || "FLOOR";
4772
+ const binFn = BIN[`${bin}`.toLowerCase()] || floor;
4121
4773
  const lo = apply(Math.min(...domain));
4122
4774
  const hi = apply(Math.max(...domain));
4123
- const a = type === "identity" ? 1 : Math.abs(range[1] - range[0]) / (hi - lo);
4124
- const s = a / pixelSize === 1 ? "" : `${a / pixelSize}::DOUBLE * `;
4125
- const d = lo === 0 ? "" : ` - ${lo}::DOUBLE`;
4126
- return (value) => sql`${fn}(${s}(${sqlApply(value)}${d}))::INTEGER`;
4775
+ const s = (type === "identity" ? 1 : Math.abs(range[1] - range[0]) / (hi - lo)) / pixelSize;
4776
+ const scalar = s === 1 ? (x2) => x2 : (x2) => mul(float642(s), x2);
4777
+ const diff = lo === 0 ? (x2) => x2 : (x2) => sub(x2, float642(lo));
4778
+ return (value) => int322(binFn(scalar(diff(sqlApply(value)))));
4779
+ }
4780
+ function preaggregateInfo(clientQuery, active, preaggCols, schema) {
4781
+ const { group, output, preagg } = preaggCols;
4782
+ const { columns } = active;
4783
+ const query = clientQuery.setSelect({ ...preagg, ...columns }).groupby(Object.keys(columns));
4784
+ const [subq] = query.subqueries;
4785
+ if (subq) {
4786
+ const cols = Object.values(columns).flatMap((c) => collectColumns(c).map((c2) => c2.column));
4787
+ subqueryPushdown(subq, cols);
4788
+ }
4789
+ const having = query._having;
4790
+ const order = query._orderby;
4791
+ query._having = [];
4792
+ query._orderby = [];
4793
+ const create2 = query.toString();
4794
+ const id = (fnv_hash(create2) >>> 0).toString(16);
4795
+ const table2 = `${schema}.preagg_${id}`;
4796
+ const select = Query.select(group, output).from(table2).groupby(group).having(having).orderby(order);
4797
+ return new PreAggregateInfo({ table: table2, create: create2, active, select });
4798
+ }
4799
+ function subqueryPushdown(query, cols) {
4800
+ const memo = /* @__PURE__ */ new Set();
4801
+ const pushdown = (q) => {
4802
+ if (memo.has(q)) return;
4803
+ memo.add(q);
4804
+ if (isSelectQuery(q) && q._from.length) {
4805
+ q.select(cols);
4806
+ }
4807
+ q.subqueries.forEach(pushdown);
4808
+ };
4809
+ pushdown(query);
4810
+ }
4811
+ var PreAggregateInfo = class {
4812
+ /**
4813
+ * Create a new pre-aggregation information instance.
4814
+ * @param {object} options Options object.
4815
+ * @param {string} options.table The materialized view table name.
4816
+ * @param {string} options.create The table creation query.
4817
+ * @param {*} options.active Active column information.
4818
+ * @param {SelectQuery} options.select Base query for requesting updates
4819
+ * using a pre-aggregated materialized view.
4820
+ */
4821
+ constructor({ table: table2, create: create2, active, select }) {
4822
+ this.table = table2;
4823
+ this.create = create2;
4824
+ this.result = null;
4825
+ this.active = active;
4826
+ this.select = select;
4827
+ this.skip = false;
4828
+ }
4829
+ /**
4830
+ * Generate a materialized view query for the given predicate.
4831
+ * @param {import('@uwdata/mosaic-sql').ExprNode} predicate The current
4832
+ * active clause predicate.
4833
+ * @returns {SelectQuery} A materialized view query.
4834
+ */
4835
+ query(predicate) {
4836
+ return this.select.clone().where(this.active.predicate(predicate));
4837
+ }
4838
+ };
4839
+
4840
+ // ../core/src/util/js-type.js
4841
+ function jsType(type) {
4842
+ switch (type) {
4843
+ case "BIGINT":
4844
+ case "HUGEINT":
4845
+ case "INTEGER":
4846
+ case "SMALLINT":
4847
+ case "TINYINT":
4848
+ case "UBIGINT":
4849
+ case "UINTEGER":
4850
+ case "USMALLINT":
4851
+ case "UTINYINT":
4852
+ // integers
4853
+ case "DOUBLE":
4854
+ case "FLOAT":
4855
+ case "REAL":
4856
+ return "number";
4857
+ case "DATE":
4858
+ case "TIMESTAMP":
4859
+ case "TIMESTAMPTZ":
4860
+ case "TIMESTAMP WITH TIME ZONE":
4861
+ case "TIME":
4862
+ case "TIMESTAMP_NS":
4863
+ return "date";
4864
+ case "BOOLEAN":
4865
+ return "boolean";
4866
+ case "VARCHAR":
4867
+ case "UUID":
4868
+ case "JSON":
4869
+ return "string";
4870
+ case "ARRAY":
4871
+ case "LIST":
4872
+ return "array";
4873
+ case "BLOB":
4874
+ case "STRUCT":
4875
+ case "MAP":
4876
+ case "GEOMETRY":
4877
+ return "object";
4878
+ default:
4879
+ if (type.startsWith("DECIMAL")) {
4880
+ return "number";
4881
+ } else if (type.startsWith("STRUCT") || type.startsWith("MAP")) {
4882
+ return "object";
4883
+ } else if (type.endsWith("]")) {
4884
+ return "array";
4885
+ }
4886
+ throw new Error(`Unsupported type: ${type}`);
4887
+ }
4888
+ }
4889
+
4890
+ // ../core/src/util/field-info.js
4891
+ var Count = "count";
4892
+ var Nulls = "nulls";
4893
+ var Max = "max";
4894
+ var Min = "min";
4895
+ var Distinct = "distinct";
4896
+ var statMap = {
4897
+ [Count]: count,
4898
+ [Distinct]: (column2) => count(column2).distinct(),
4899
+ [Max]: max,
4900
+ [Min]: min,
4901
+ [Nulls]: (column2) => count().where(isNull(column2))
4902
+ };
4903
+ function summarize(table2, column2, stats) {
4904
+ return Query.from(table2).select(Array.from(stats, (s) => ({ [s]: statMap[s](column2) })));
4127
4905
  }
4128
- function dataCubeInfo(clientQuery, active, indexCols, schema) {
4129
- const { dims, aggr, aux } = indexCols;
4130
- const { columns } = active;
4131
- const query = clientQuery.select({ ...columns, ...aux }).groupby(Object.keys(columns));
4132
- const [subq] = query.subqueries;
4133
- if (subq) {
4134
- const cols = Object.values(columns).flatMap((c) => c.columns);
4135
- subqueryPushdown(subq, cols);
4906
+ async function queryFieldInfo(mc, fields) {
4907
+ if (fields.length === 1 && fields[0].column === "*") {
4908
+ return getTableInfo(mc, fields[0].table);
4909
+ } else {
4910
+ return (await Promise.all(fields.map((f) => getFieldInfo(mc, f)))).filter((x2) => x2);
4136
4911
  }
4137
- const order = query.orderby();
4138
- query.query.orderby = [];
4139
- const create3 = query.toString();
4140
- const id = (fnv_hash(create3) >>> 0).toString(16);
4141
- const table2 = `${schema}.cube_${id}`;
4142
- const select = Query.select(dims, aggr).from(table2).groupby(dims).orderby(order);
4143
- return new DataCubeInfo({ id, table: table2, create: create3, active, select });
4144
4912
  }
4145
- function subqueryPushdown(query, cols) {
4146
- const memo = /* @__PURE__ */ new Set();
4147
- const pushdown = (q) => {
4148
- if (memo.has(q)) return;
4149
- memo.add(q);
4150
- if (q.select && q.from().length) {
4151
- q.select(cols);
4152
- }
4153
- q.subqueries.forEach(pushdown);
4913
+ async function getFieldInfo(mc, { table: table2, column: column2, stats }) {
4914
+ const q = Query.from({ source: table2 }).select({ column: column2 }).groupby(column2.aggregate ? sql`ALL` : []);
4915
+ const [desc2] = Array.from(await mc.query(Query.describe(q)));
4916
+ const info = {
4917
+ table: table2,
4918
+ column: `${column2}`,
4919
+ sqlType: desc2.column_type,
4920
+ type: jsType(desc2.column_type),
4921
+ nullable: desc2.null === "YES"
4154
4922
  };
4155
- pushdown(query);
4923
+ if (!(stats?.length || stats?.size)) return info;
4924
+ const [result] = await mc.query(
4925
+ summarize(table2, column2, stats),
4926
+ { persist: true }
4927
+ );
4928
+ return Object.assign(info, result);
4929
+ }
4930
+ async function getTableInfo(mc, table2) {
4931
+ const result = await mc.query(`DESCRIBE ${asTableRef(table2)}`);
4932
+ return Array.from(result).map((desc2) => ({
4933
+ table: table2,
4934
+ column: desc2.column_name,
4935
+ sqlType: desc2.column_type,
4936
+ type: jsType(desc2.column_type),
4937
+ nullable: desc2.null === "YES"
4938
+ }));
4156
4939
  }
4157
- var DataCubeInfo = class {
4158
- /**
4159
- * Create a new DataCubeInfo instance.
4160
- * @param {object} options
4161
- */
4162
- constructor({ table: table2, create: create3, active, select } = {}) {
4163
- this.table = table2;
4164
- this.create = create3;
4165
- this.result = null;
4166
- this.active = active;
4167
- this.select = select;
4168
- this.skip = false;
4169
- }
4170
- /**
4171
- * Generate a data cube index table query for the given predicate.
4172
- * @param {import('@uwdata/mosaic-sql').SQLExpression} predicate The current
4173
- * active clause predicate.
4174
- * @returns {Query} A data cube index table query.
4175
- */
4176
- query(predicate) {
4177
- return this.select.clone().where(this.active.predicate(predicate));
4178
- }
4179
- };
4180
4940
 
4181
4941
  // ../core/src/util/query-result.js
4942
+ var QueryState = Object.freeze({
4943
+ pending: Symbol("pending"),
4944
+ ready: Symbol("ready"),
4945
+ error: Symbol("error"),
4946
+ done: Symbol("done")
4947
+ });
4182
4948
  var QueryResult = class extends Promise {
4183
4949
  /**
4184
4950
  * Create a new query result Promise.
@@ -4192,14 +4958,37 @@ var QueryResult = class extends Promise {
4192
4958
  });
4193
4959
  this._resolve = resolve;
4194
4960
  this._reject = reject;
4961
+ this._state = QueryState.pending;
4962
+ this._value = void 0;
4195
4963
  }
4196
4964
  /**
4197
- * Resolve the result Promise with the provided value.
4965
+ * Resolve the result Promise with a prepared value or the provided value.
4966
+ * This method will only succeed if either a value is provided or the promise is ready.
4198
4967
  * @param {*} value The result value.
4199
4968
  * @returns {this}
4200
4969
  */
4201
4970
  fulfill(value) {
4202
- this._resolve(value);
4971
+ if (this._value !== void 0) {
4972
+ if (value !== void 0) {
4973
+ throw Error("Promise is ready and fulfill has a provided value");
4974
+ }
4975
+ this._resolve(this._value);
4976
+ } else if (value === void 0) {
4977
+ throw Error("Promise is neither ready nor has provided value");
4978
+ } else {
4979
+ this._resolve(value);
4980
+ }
4981
+ this._state = QueryState.done;
4982
+ return this;
4983
+ }
4984
+ /**
4985
+ * Prepare to resolve with the provided value.
4986
+ * @param {*} value The result value.
4987
+ * @returns {this}
4988
+ */
4989
+ ready(value) {
4990
+ this._state = QueryState.ready;
4991
+ this._value = value;
4203
4992
  return this;
4204
4993
  }
4205
4994
  /**
@@ -4208,18 +4997,42 @@ var QueryResult = class extends Promise {
4208
4997
  * @returns {this}
4209
4998
  */
4210
4999
  reject(error) {
5000
+ this._state = QueryState.error;
4211
5001
  this._reject(error);
4212
5002
  return this;
4213
5003
  }
5004
+ /**
5005
+ * Returns the state of this query result.
5006
+ * @returns {symbol}
5007
+ */
5008
+ get state() {
5009
+ return this._state;
5010
+ }
4214
5011
  };
4215
5012
  QueryResult.prototype.constructor = Promise;
4216
5013
 
5014
+ // ../core/src/util/void-logger.js
5015
+ function voidLogger() {
5016
+ return {
5017
+ debug(..._) {
5018
+ },
5019
+ info(..._) {
5020
+ },
5021
+ log(..._) {
5022
+ },
5023
+ warn(..._) {
5024
+ },
5025
+ error(..._) {
5026
+ }
5027
+ };
5028
+ }
5029
+
4217
5030
  // ../core/src/QueryConsolidator.js
4218
5031
  function wait(callback) {
4219
5032
  const method = typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : typeof setImmediate !== "undefined" ? setImmediate : setTimeout;
4220
5033
  return method(callback);
4221
5034
  }
4222
- function consolidator(enqueue, cache, record) {
5035
+ function consolidator(enqueue, cache) {
4223
5036
  let pending = [];
4224
5037
  let id = 0;
4225
5038
  function run() {
@@ -4227,7 +5040,7 @@ function consolidator(enqueue, cache, record) {
4227
5040
  pending = [];
4228
5041
  id = 0;
4229
5042
  for (const group of groups) {
4230
- consolidate(group, enqueue, record);
5043
+ consolidate(group, enqueue);
4231
5044
  processResults(group, cache);
4232
5045
  }
4233
5046
  }
@@ -4259,36 +5072,31 @@ function entryGroups(entries, cache) {
4259
5072
  }
4260
5073
  function consolidationKey(query, cache) {
4261
5074
  const sql2 = `${query}`;
4262
- if (query instanceof Query && !cache.get(sql2)) {
4263
- if (
4264
- // @ts-ignore
4265
- query.orderby().length || query.where().length || // @ts-ignore
4266
- query.qualify().length || query.having().length
4267
- ) {
5075
+ if (isSelectQuery(query) && !cache.get(sql2)) {
5076
+ if (query._orderby.length || query._where.length || query._qualify.length || query._having.length) {
4268
5077
  return sql2;
4269
5078
  }
4270
- const q = query.clone().$select("*");
4271
- const groupby = query.groupby();
5079
+ const q = query.clone().setSelect("*");
5080
+ const groupby = query._groupby;
4272
5081
  if (groupby.length) {
4273
5082
  const map2 = {};
4274
- query.select().forEach(({ as, expr }) => map2[as] = expr);
4275
- q.$groupby(groupby.map((e) => e instanceof Ref && map2[e.column] || e));
4276
- } else if (query.select().some(({ expr }) => expr.aggregate)) {
4277
- q.$groupby("ALL");
5083
+ query._select.forEach(({ alias, expr }) => map2[alias] = expr);
5084
+ q.setGroupby(groupby.map((e) => isColumnRef(e) && map2[e.column] || e));
5085
+ } else if (query._select.some((e) => isAggregateExpression(e.expr))) {
5086
+ q.setGroupby("ALL");
4278
5087
  }
4279
5088
  return `${q}`;
4280
5089
  } else {
4281
5090
  return sql2;
4282
5091
  }
4283
5092
  }
4284
- function consolidate(group, enqueue, record) {
5093
+ function consolidate(group, enqueue) {
4285
5094
  if (shouldConsolidate(group)) {
4286
5095
  enqueue({
4287
5096
  request: {
4288
5097
  type: "arrow",
4289
5098
  cache: false,
4290
- record: false,
4291
- query: group.query = consolidatedQuery(group, record)
5099
+ query: group.query = consolidatedQuery(group)
4292
5100
  },
4293
5101
  result: group.result = new QueryResult()
4294
5102
  });
@@ -4309,31 +5117,30 @@ function shouldConsolidate(group) {
4309
5117
  }
4310
5118
  return false;
4311
5119
  }
4312
- function consolidatedQuery(group, record) {
5120
+ function consolidatedQuery(group) {
4313
5121
  const maps = group.maps = [];
4314
5122
  const fields = /* @__PURE__ */ new Map();
4315
5123
  for (const item of group) {
4316
5124
  const { query: query2 } = item.entry.request;
4317
5125
  const fieldMap = [];
4318
5126
  maps.push(fieldMap);
4319
- for (const { as, expr } of query2.select()) {
5127
+ for (const { alias, expr } of query2._select) {
4320
5128
  const e = `${expr}`;
4321
5129
  if (!fields.has(e)) {
4322
5130
  fields.set(e, [`col${fields.size}`, expr]);
4323
5131
  }
4324
5132
  const [name] = fields.get(e);
4325
- fieldMap.push([name, as]);
5133
+ fieldMap.push([name, alias]);
4326
5134
  }
4327
- record(`${query2}`);
4328
5135
  }
4329
5136
  const query = group[0].entry.request.query.clone();
4330
- const groupby = query.groupby();
5137
+ const groupby = query._groupby;
4331
5138
  if (groupby.length) {
4332
5139
  const map2 = {};
4333
5140
  group.maps[0].forEach(([name, as]) => map2[as] = name);
4334
- query.$groupby(groupby.map((e) => e instanceof Ref && map2[e.column] || e));
5141
+ query.setGroupby(groupby.map((e) => isColumnRef(e) && map2[e.column] || e));
4335
5142
  }
4336
- return query.$select(Array.from(fields.values()));
5143
+ return query.setSelect(Array.from(fields.values()));
4337
5144
  }
4338
5145
  async function processResults(group, cache) {
4339
5146
  const { maps, query, result } = group;
@@ -4505,48 +5312,65 @@ var PriorityQueue = class {
4505
5312
  };
4506
5313
 
4507
5314
  // ../core/src/QueryManager.js
4508
- var Priority = { High: 0, Normal: 1, Low: 2 };
5315
+ var Priority = Object.freeze({ High: 0, Normal: 1, Low: 2 });
4509
5316
  var QueryManager = class {
4510
- constructor() {
5317
+ constructor(maxConcurrentRequests = 32) {
4511
5318
  this.queue = new PriorityQueue(3);
4512
5319
  this.db = null;
4513
5320
  this.clientCache = null;
4514
- this._logger = null;
5321
+ this._logger = voidLogger();
4515
5322
  this._logQueries = false;
4516
- this.recorders = [];
4517
- this.pending = null;
4518
5323
  this._consolidate = null;
5324
+ this.pendingResults = [];
5325
+ this.maxConcurrentRequests = maxConcurrentRequests;
5326
+ this.pendingExec = false;
4519
5327
  }
4520
5328
  next() {
4521
- if (this.pending || this.queue.isEmpty()) return;
5329
+ if (this.queue.isEmpty() || this.pendingResults.length > this.maxConcurrentRequests || this.pendingExec) {
5330
+ return;
5331
+ }
4522
5332
  const { request, result } = this.queue.next();
4523
- this.pending = this.submit(request, result);
4524
- this.pending.finally(() => {
4525
- this.pending = null;
5333
+ this.pendingResults.push(result);
5334
+ if (request.type === "exec") this.pendingExec = true;
5335
+ this.submit(request, result).finally(() => {
5336
+ while (this.pendingResults.length && this.pendingResults[0].state !== QueryState.pending) {
5337
+ const result2 = this.pendingResults.shift();
5338
+ if (result2.state === QueryState.ready) {
5339
+ result2.fulfill();
5340
+ } else if (result2.state === QueryState.done) {
5341
+ this._logger.warn("Found resolved query in pending results.");
5342
+ }
5343
+ }
5344
+ if (request.type === "exec") this.pendingExec = false;
4526
5345
  this.next();
4527
5346
  });
4528
5347
  }
5348
+ /**
5349
+ * Add an entry to the query queue with a priority.
5350
+ * @param {object} entry The entry to add.
5351
+ * @param {*} [entry.request] The query request.
5352
+ * @param {QueryResult} [entry.result] The query result.
5353
+ * @param {number} priority The query priority, defaults to `Priority.Normal`.
5354
+ */
4529
5355
  enqueue(entry, priority = Priority.Normal) {
4530
5356
  this.queue.insert(entry, priority);
4531
5357
  this.next();
4532
5358
  }
4533
- recordQuery(sql2) {
4534
- if (this.recorders.length && sql2) {
4535
- this.recorders.forEach((rec) => rec.add(sql2));
4536
- }
4537
- }
5359
+ /**
5360
+ * Submit the query to the connector.
5361
+ * @param {*} request The request.
5362
+ * @param {QueryResult} result The query result.
5363
+ */
4538
5364
  async submit(request, result) {
4539
5365
  try {
4540
- const { query, type, cache = false, record = true, options } = request;
5366
+ const { query, type, cache = false, options } = request;
4541
5367
  const sql2 = query ? `${query}` : null;
4542
- if (record) {
4543
- this.recordQuery(sql2);
4544
- }
4545
5368
  if (cache) {
4546
5369
  const cached = this.clientCache.get(sql2);
4547
5370
  if (cached) {
5371
+ const data2 = await cached;
4548
5372
  this._logger.debug("Cache");
4549
- result.fulfill(cached);
5373
+ result.ready(data2);
4550
5374
  return;
4551
5375
  }
4552
5376
  }
@@ -4554,10 +5378,12 @@ var QueryManager = class {
4554
5378
  if (this._logQueries) {
4555
5379
  this._logger.debug("Query", { type, sql: sql2, ...options });
4556
5380
  }
4557
- const data = await this.db.query({ type, sql: sql2, ...options });
5381
+ const promise = this.db.query({ type, sql: sql2, ...options });
5382
+ if (cache) this.clientCache.set(sql2, promise);
5383
+ const data = await promise;
4558
5384
  if (cache) this.clientCache.set(sql2, data);
4559
5385
  this._logger.debug(`Request: ${(performance.now() - t0).toFixed(1)}`);
4560
- result.fulfill(data);
5386
+ result.ready(type === "exec" ? null : data);
4561
5387
  } catch (err) {
4562
5388
  result.reject(err);
4563
5389
  }
@@ -4576,11 +5402,17 @@ var QueryManager = class {
4576
5402
  }
4577
5403
  consolidate(flag) {
4578
5404
  if (flag && !this._consolidate) {
4579
- this._consolidate = consolidator(this.enqueue.bind(this), this.clientCache, this.recordQuery.bind(this));
5405
+ this._consolidate = consolidator(this.enqueue.bind(this), this.clientCache);
4580
5406
  } else if (!flag && this._consolidate) {
4581
5407
  this._consolidate = null;
4582
5408
  }
4583
5409
  }
5410
+ /**
5411
+ * Request a query result.
5412
+ * @param {*} request The request.
5413
+ * @param {number} priority The query priority, defaults to `Priority.Normal`.
5414
+ * @returns {QueryResult} A query result promise.
5415
+ */
4584
5416
  request(request, priority = Priority.Normal) {
4585
5417
  const result = new QueryResult();
4586
5418
  const entry = { request, result };
@@ -4601,6 +5433,11 @@ var QueryManager = class {
4601
5433
  }
4602
5434
  return false;
4603
5435
  });
5436
+ for (const result of this.pendingResults) {
5437
+ if (set.has(result)) {
5438
+ result.reject("Canceled");
5439
+ }
5440
+ }
4604
5441
  }
4605
5442
  }
4606
5443
  clear() {
@@ -4608,145 +5445,12 @@ var QueryManager = class {
4608
5445
  result.reject("Cleared");
4609
5446
  return true;
4610
5447
  });
5448
+ for (const result of this.pendingResults) {
5449
+ result.reject("Cleared");
5450
+ }
5451
+ this.pendingResults = [];
4611
5452
  }
4612
- record() {
4613
- let state = [];
4614
- const recorder = {
4615
- add(query) {
4616
- state.push(query);
4617
- },
4618
- reset() {
4619
- state = [];
4620
- },
4621
- snapshot() {
4622
- return state.slice();
4623
- },
4624
- stop() {
4625
- this.recorders = this.recorders.filter((x2) => x2 !== recorder);
4626
- return state;
4627
- }
4628
- };
4629
- this.recorders.push(recorder);
4630
- return recorder;
4631
- }
4632
- };
4633
-
4634
- // ../core/src/util/js-type.js
4635
- function jsType(type) {
4636
- switch (type) {
4637
- case "BIGINT":
4638
- case "HUGEINT":
4639
- case "INTEGER":
4640
- case "SMALLINT":
4641
- case "TINYINT":
4642
- case "UBIGINT":
4643
- case "UINTEGER":
4644
- case "USMALLINT":
4645
- case "UTINYINT":
4646
- // integers
4647
- case "DOUBLE":
4648
- case "FLOAT":
4649
- case "REAL":
4650
- return "number";
4651
- case "DATE":
4652
- case "TIMESTAMP":
4653
- case "TIMESTAMPTZ":
4654
- case "TIMESTAMP WITH TIME ZONE":
4655
- case "TIME":
4656
- case "TIMESTAMP_NS":
4657
- return "date";
4658
- case "BOOLEAN":
4659
- return "boolean";
4660
- case "VARCHAR":
4661
- case "UUID":
4662
- case "JSON":
4663
- return "string";
4664
- case "ARRAY":
4665
- case "LIST":
4666
- return "array";
4667
- case "BLOB":
4668
- case "STRUCT":
4669
- case "MAP":
4670
- case "GEOMETRY":
4671
- return "object";
4672
- default:
4673
- if (type.startsWith("DECIMAL")) {
4674
- return "number";
4675
- } else if (type.startsWith("STRUCT") || type.startsWith("MAP")) {
4676
- return "object";
4677
- } else if (type.endsWith("]")) {
4678
- return "array";
4679
- }
4680
- throw new Error(`Unsupported type: ${type}`);
4681
- }
4682
- }
4683
-
4684
- // ../core/src/util/field-info.js
4685
- var Count = "count";
4686
- var Nulls = "nulls";
4687
- var Max = "max";
4688
- var Min = "min";
4689
- var Distinct = "distinct";
4690
- var statMap = {
4691
- [Count]: count,
4692
- [Distinct]: (column2) => count(column2).distinct(),
4693
- [Max]: max,
4694
- [Min]: min,
4695
- [Nulls]: (column2) => count().where(isNull(column2))
4696
5453
  };
4697
- function summarize(table2, column2, stats) {
4698
- return Query.from(table2).select(Array.from(stats, (s) => [s, statMap[s](column2)]));
4699
- }
4700
- async function queryFieldInfo(mc, fields) {
4701
- if (fields.length === 1 && `${fields[0].column}` === "*") {
4702
- return getTableInfo(mc, fields[0].table);
4703
- } else {
4704
- return (await Promise.all(fields.map((f) => getFieldInfo(mc, f)))).filter((x2) => x2);
4705
- }
4706
- }
4707
- async function getFieldInfo(mc, { table: table2, column: column2, stats }) {
4708
- const q = Query.from({ source: table2 }).select({ column: column2 }).groupby(column2.aggregate ? sql`ALL` : []);
4709
- const [desc2] = Array.from(await mc.query(Query.describe(q)));
4710
- const info = {
4711
- table: table2,
4712
- column: `${column2}`,
4713
- sqlType: desc2.column_type,
4714
- type: jsType(desc2.column_type),
4715
- nullable: desc2.null === "YES"
4716
- };
4717
- if (!(stats?.length || stats?.size)) return info;
4718
- const [result] = await mc.query(
4719
- summarize(table2, column2, stats),
4720
- { persist: true }
4721
- );
4722
- return Object.assign(info, result);
4723
- }
4724
- async function getTableInfo(mc, table2) {
4725
- const result = await mc.query(`DESCRIBE ${asRelation(table2)}`);
4726
- return Array.from(result).map((desc2) => ({
4727
- table: table2,
4728
- column: desc2.column_name,
4729
- sqlType: desc2.column_type,
4730
- type: jsType(desc2.column_type),
4731
- nullable: desc2.null === "YES"
4732
- }));
4733
- }
4734
-
4735
- // ../core/src/util/void-logger.js
4736
- function voidLogger() {
4737
- return {
4738
- debug() {
4739
- },
4740
- info() {
4741
- },
4742
- log() {
4743
- },
4744
- warn() {
4745
- },
4746
- error() {
4747
- }
4748
- };
4749
- }
4750
5454
 
4751
5455
  // ../core/src/Coordinator.js
4752
5456
  var _instance;
@@ -4764,7 +5468,7 @@ var Coordinator = class {
4764
5468
  manager = new QueryManager(),
4765
5469
  cache = true,
4766
5470
  consolidate: consolidate2 = true,
4767
- indexes = {}
5471
+ preagg = {}
4768
5472
  } = {}) {
4769
5473
  this.manager = manager;
4770
5474
  this.manager.cache(cache);
@@ -4772,7 +5476,7 @@ var Coordinator = class {
4772
5476
  this.databaseConnector(db);
4773
5477
  this.logger(logger);
4774
5478
  this.clear();
4775
- this.dataCubeIndexer = new DataCubeIndexer(this, indexes);
5479
+ this.preaggregator = new PreAggregator(this, preagg);
4776
5480
  }
4777
5481
  /**
4778
5482
  * Clear the coordinator state.
@@ -4910,12 +5614,12 @@ var Coordinator = class {
4910
5614
  /**
4911
5615
  * Issue a query request for a client. If the query is null or undefined,
4912
5616
  * the client is simply updated. Otherwise `updateClient` is called. As a
4913
- * side effect, this method clears the current data cube indexer state.
5617
+ * side effect, this method clears the current preaggregator state.
4914
5618
  * @param {MosaicClient} client The client to update.
4915
5619
  * @param {QueryType | null} [query] The query to issue.
4916
5620
  */
4917
5621
  requestQuery(client, query) {
4918
- this.dataCubeIndexer.clear();
5622
+ this.preaggregator.clear();
4919
5623
  return query ? this.updateClient(client, query) : Promise.resolve(client.update());
4920
5624
  }
4921
5625
  /**
@@ -4975,18 +5679,18 @@ function connectSelection(mc, selection, client) {
4975
5679
  entry.clients.add(client);
4976
5680
  }
4977
5681
  function activateSelection(mc, selection, clause) {
4978
- const { dataCubeIndexer, filterGroups } = mc;
5682
+ const { preaggregator, filterGroups } = mc;
4979
5683
  const { clients } = filterGroups.get(selection);
4980
5684
  for (const client of clients) {
4981
- dataCubeIndexer.index(client, selection, clause);
5685
+ preaggregator.request(client, selection, clause);
4982
5686
  }
4983
5687
  }
4984
5688
  function updateSelection(mc, selection) {
4985
- const { dataCubeIndexer, filterGroups } = mc;
5689
+ const { preaggregator, filterGroups } = mc;
4986
5690
  const { clients } = filterGroups.get(selection);
4987
5691
  const { active } = selection;
4988
5692
  return Promise.allSettled(Array.from(clients, (client) => {
4989
- const info = dataCubeIndexer.index(client, selection, active);
5693
+ const info = preaggregator.request(client, selection, active);
4990
5694
  const filter = info ? null : selection.predicate(client);
4991
5695
  if (info?.skip || !info && !filter) return;
4992
5696
  const query = info?.query(active.predicate) ?? client.query(filter);
@@ -5204,11 +5908,11 @@ var Param = class _Param extends AsyncDispatch {
5204
5908
  static array(values) {
5205
5909
  if (values.some((v) => isParam(v))) {
5206
5910
  const p = new _Param();
5207
- const update2 = () => {
5911
+ const update = () => {
5208
5912
  p.update(values.map((v) => isParam(v) ? v.value : v));
5209
5913
  };
5210
- update2();
5211
- values.forEach((v) => isParam(v) ? v.addEventListener("value", update2) : 0);
5914
+ update();
5915
+ values.forEach((v) => isParam(v) ? v.addEventListener("value", update) : 0);
5212
5916
  return p;
5213
5917
  }
5214
5918
  return new _Param(values);
@@ -5255,7 +5959,7 @@ var Param = class _Param extends AsyncDispatch {
5255
5959
  function isSelection(x2) {
5256
5960
  return x2 instanceof Selection;
5257
5961
  }
5258
- function create2(options, include) {
5962
+ function create(options, include) {
5259
5963
  return new Selection(
5260
5964
  new SelectionResolver(options),
5261
5965
  include ? [include].flat() : include
@@ -5278,7 +5982,7 @@ var Selection = class _Selection extends Param {
5278
5982
  * @returns {Selection} The new Selection instance.
5279
5983
  */
5280
5984
  static intersect({ cross = false, empty = false, include = [] } = {}) {
5281
- return create2({ cross, empty }, include);
5985
+ return create({ cross, empty }, include);
5282
5986
  }
5283
5987
  /**
5284
5988
  * Create a new Selection instance with a
@@ -5296,7 +6000,7 @@ var Selection = class _Selection extends Param {
5296
6000
  * @returns {Selection} The new Selection instance.
5297
6001
  */
5298
6002
  static union({ cross = false, empty = false, include = [] } = {}) {
5299
- return create2({ cross, empty, union: true }, include);
6003
+ return create({ cross, empty, union: true }, include);
5300
6004
  }
5301
6005
  /**
5302
6006
  * Create a new Selection instance with a singular resolution strategy
@@ -5314,7 +6018,7 @@ var Selection = class _Selection extends Param {
5314
6018
  * @returns {Selection} The new Selection instance.
5315
6019
  */
5316
6020
  static single({ cross = false, empty = false, include = [] } = {}) {
5317
- return create2({ cross, empty, single: true }, include);
6021
+ return create({ cross, empty, single: true }, include);
5318
6022
  }
5319
6023
  /**
5320
6024
  * Create a new Selection instance with a
@@ -5329,7 +6033,7 @@ var Selection = class _Selection extends Param {
5329
6033
  * @returns {Selection} The new Selection instance.
5330
6034
  */
5331
6035
  static crossfilter({ empty = false, include = [] } = {}) {
5332
- return create2({ cross: true, empty }, include);
6036
+ return create({ cross: true, empty }, include);
5333
6037
  }
5334
6038
  /**
5335
6039
  * Create a new Selection instance.
@@ -5524,16 +6228,18 @@ var SelectionResolver = class {
5524
6228
  }
5525
6229
  /**
5526
6230
  * Return a selection query predicate for the given client.
5527
- * @param {*[]} clauseList An array of selection clauses.
5528
- * @param {*} active The current active selection clause.
5529
- * @param {*} client The client whose data may be filtered.
6231
+ * @param {import('./util/selection-types.js').SelectionClause[]} clauseList
6232
+ * An array of selection clauses.
6233
+ * @param {import('./util/selection-types.js').SelectionClause} active
6234
+ * The current active selection clause.
6235
+ * @param {MosaicClient} client The client whose data may be filtered.
5530
6236
  * @returns {*} The query predicate for filtering client data,
5531
6237
  * based on the current state of this selection.
5532
6238
  */
5533
6239
  predicate(clauseList, active, client) {
5534
6240
  const { empty, union: union2 } = this;
5535
6241
  if (empty && !clauseList.length) {
5536
- return ["FALSE"];
6242
+ return [literal(false)];
5537
6243
  }
5538
6244
  if (this.skip(client, active)) return void 0;
5539
6245
  const predicates = clauseList.filter((clause) => !this.skip(client, clause)).map((clause) => clause.predicate);
@@ -5559,7 +6265,7 @@ function clausePoint(field2, value, {
5559
6265
  source,
5560
6266
  clients = source ? /* @__PURE__ */ new Set([source]) : void 0
5561
6267
  }) {
5562
- const predicate = value !== void 0 ? isNotDistinct(field2, literal(value)) : null;
6268
+ const predicate = value !== void 0 ? isIn(field2, [literal(value)]) : null;
5563
6269
  return {
5564
6270
  meta: { type: "point" },
5565
6271
  source,
@@ -5574,11 +6280,8 @@ function clausePoints(fields, value, {
5574
6280
  }) {
5575
6281
  let predicate = null;
5576
6282
  if (value) {
5577
- const clauses = value.map((vals) => {
5578
- const list2 = vals.map((v, i) => isNotDistinct(fields[i], literal(v)));
5579
- return list2.length > 1 ? and(list2) : list2[0];
5580
- });
5581
- predicate = clauses.length > 1 ? or(clauses) : clauses[0];
6283
+ const clauses = value.length && fields.length === 1 ? [isIn(fields[0], value.map((v) => literal(v[0])))] : value.map((v) => and(v.map((_, i) => isNotDistinct(fields[i], literal(_)))));
6284
+ predicate = value.length === 0 ? literal(false) : clauses.length > 1 ? or(clauses) : clauses[0];
5582
6285
  }
5583
6286
  return {
5584
6287
  meta: { type: "point" },
@@ -5605,8 +6308,8 @@ function clauseMatch(field2, value, {
5605
6308
  clients = void 0,
5606
6309
  method = "contains"
5607
6310
  }) {
5608
- let fn = MATCH_METHODS[method];
5609
- const predicate = value ? fn(field2, literal(value)) : null;
6311
+ let fn2 = MATCH_METHODS[method];
6312
+ const predicate = value ? fn2(field2, literal(value)) : null;
5610
6313
  const meta = { type: "match", method };
5611
6314
  return { meta, source, clients, value, predicate };
5612
6315
  }
@@ -5726,6 +6429,11 @@ var Menu = class extends MosaicClient {
5726
6429
  this.selectedValue(value2);
5727
6430
  }
5728
6431
  });
6432
+ } else {
6433
+ this.select.addEventListener("pointerenter", (evt) => {
6434
+ if (!evt.buttons) this.activate();
6435
+ });
6436
+ this.select.addEventListener("focus", () => this.activate());
5729
6437
  }
5730
6438
  }
5731
6439
  }
@@ -5745,6 +6453,9 @@ var Menu = class extends MosaicClient {
5745
6453
  reset() {
5746
6454
  this.select.selectedIndex = this.from ? 0 : -1;
5747
6455
  }
6456
+ activate() {
6457
+ this.selection.activate(clausePoint(this.field, 0, { source: this }));
6458
+ }
5748
6459
  publish(value) {
5749
6460
  const { selection, field: field2 } = this;
5750
6461
  if (isSelection(selection)) {
@@ -5851,17 +6562,28 @@ var Search = class extends MosaicClient {
5851
6562
  this.searchbox.value = value;
5852
6563
  }
5853
6564
  });
6565
+ } else {
6566
+ this.searchbox.addEventListener("pointerenter", (evt) => {
6567
+ if (!evt.buttons) this.activate();
6568
+ });
6569
+ this.searchbox.addEventListener("focus", () => this.activate());
5854
6570
  }
5855
6571
  }
5856
6572
  }
5857
6573
  reset() {
5858
6574
  this.searchbox.value = "";
5859
6575
  }
6576
+ clause(value) {
6577
+ const { field: field2, type } = this;
6578
+ return clauseMatch(field2, value, { source: this, method: type });
6579
+ }
6580
+ activate() {
6581
+ this.selection.activate(this.clause(""));
6582
+ }
5860
6583
  publish(value) {
5861
- const { selection, field: field2, type } = this;
6584
+ const { selection } = this;
5862
6585
  if (isSelection(selection)) {
5863
- const clause = clauseMatch(field2, value, { source: this, method: type });
5864
- selection.update(clause);
6586
+ selection.update(this.clause(value));
5865
6587
  } else if (isParam(selection)) {
5866
6588
  selection.update(value);
5867
6589
  }
@@ -5981,13 +6703,20 @@ var Slider = class extends MosaicClient {
5981
6703
  this.curval.innerText = value2;
5982
6704
  if (this.selection) this.publish(+value2);
5983
6705
  });
5984
- if (this.selection && !isSelection(this.selection)) {
5985
- this.selection.addEventListener("value", (value2) => {
5986
- if (value2 !== +this.slider.value) {
5987
- this.slider.value = value2;
5988
- this.curval.innerText = value2;
5989
- }
5990
- });
6706
+ if (this.selection) {
6707
+ if (!isSelection(this.selection)) {
6708
+ this.selection.addEventListener("value", (value2) => {
6709
+ if (value2 !== +this.slider.value) {
6710
+ this.slider.value = value2;
6711
+ this.curval.innerText = value2;
6712
+ }
6713
+ });
6714
+ } else {
6715
+ this.slider.addEventListener("pointerenter", (evt) => {
6716
+ if (!evt.buttons) this.activate();
6717
+ });
6718
+ this.slider.addEventListener("focus", () => this.activate());
6719
+ }
5991
6720
  }
5992
6721
  }
5993
6722
  query(filter = []) {
@@ -6011,20 +6740,27 @@ var Slider = class extends MosaicClient {
6011
6740
  }
6012
6741
  return this;
6013
6742
  }
6743
+ clause(value) {
6744
+ const { field: field2, selectionType } = this;
6745
+ if (selectionType === "interval") {
6746
+ const domain = [this.min ?? 0, value];
6747
+ return clauseInterval(field2, domain, {
6748
+ source: this,
6749
+ bin: "ceil",
6750
+ scale: { type: "identity", domain },
6751
+ pixelSize: this.step
6752
+ });
6753
+ } else {
6754
+ return clausePoint(field2, value, { source: this });
6755
+ }
6756
+ }
6757
+ activate() {
6758
+ this.selection.activate(this.clause(0));
6759
+ }
6014
6760
  publish(value) {
6015
- const { field: field2, selectionType, selection } = this;
6761
+ const { selection } = this;
6016
6762
  if (isSelection(selection)) {
6017
- if (selectionType === "interval") {
6018
- const domain = [this.min ?? 0, value];
6019
- selection.update(clauseInterval(field2, domain, {
6020
- source: this,
6021
- bin: "ceil",
6022
- scale: { type: "identity", domain },
6023
- pixelSize: this.step
6024
- }));
6025
- } else {
6026
- selection.update(clausePoint(field2, value, { source: this }));
6027
- }
6763
+ selection.update(this.clause(value));
6028
6764
  } else if (isParam(this.selection)) {
6029
6765
  selection.update(value);
6030
6766
  }
@@ -6095,6 +6831,9 @@ var Table2 = class extends MosaicClient {
6095
6831
  this.format = format2;
6096
6832
  this.align = align2;
6097
6833
  this.widths = typeof width === "object" ? width : {};
6834
+ if (isParam(from)) {
6835
+ from.addEventListener("value", () => this.initialize());
6836
+ }
6098
6837
  this.offset = 0;
6099
6838
  this.limit = +rowBatch;
6100
6839
  this.pending = false;
@@ -6144,6 +6883,9 @@ var Table2 = class extends MosaicClient {
6144
6883
  this.style = document.createElement("style");
6145
6884
  this.element.appendChild(this.style);
6146
6885
  }
6886
+ sourceTable() {
6887
+ return isParam(this.from) ? this.from.value : this.from;
6888
+ }
6147
6889
  clause(rows = []) {
6148
6890
  const { data, limit, schema } = this;
6149
6891
  const fields = schema.map((s) => s.column);
@@ -6160,7 +6902,8 @@ var Table2 = class extends MosaicClient {
6160
6902
  coordinator().prefetch(query.clone().offset(offset + this.limit));
6161
6903
  }
6162
6904
  fields() {
6163
- return this.columns.map((name) => column(this.from, name));
6905
+ const from = this.sourceTable();
6906
+ return this.columns.map((name) => column(name, from));
6164
6907
  }
6165
6908
  fieldInfo(info) {
6166
6909
  this.schema = info;
@@ -6184,8 +6927,8 @@ var Table2 = class extends MosaicClient {
6184
6927
  return this;
6185
6928
  }
6186
6929
  query(filter = []) {
6187
- const { from, limit, offset, schema, sortColumn, sortDesc } = this;
6188
- return Query.from(from).select(schema.map((s) => s.column)).where(filter).orderby(sortColumn ? sortDesc ? desc(sortColumn) : sortColumn : []).limit(limit).offset(offset);
6930
+ const { limit, offset, schema, sortColumn, sortDesc } = this;
6931
+ return Query.from(this.sourceTable()).select(schema.map((s) => s.column)).where(filter).orderby(sortColumn ? sortDesc ? desc(sortColumn) : sortColumn : []).limit(limit).offset(offset);
6189
6932
  }
6190
6933
  queryResult(data) {
6191
6934
  if (!this.pending) {