@uwdata/mosaic-sql 0.18.0 → 0.20.0

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.
Files changed (212) hide show
  1. package/dist/src/ast/aggregate.d.ts +0 -4
  2. package/dist/src/ast/aggregate.d.ts.map +1 -1
  3. package/dist/src/ast/aggregate.js +0 -15
  4. package/dist/src/ast/aggregate.js.map +1 -1
  5. package/dist/src/ast/between-op.d.ts +0 -8
  6. package/dist/src/ast/between-op.d.ts.map +1 -1
  7. package/dist/src/ast/between-op.js +0 -12
  8. package/dist/src/ast/between-op.js.map +1 -1
  9. package/dist/src/ast/binary-op.d.ts +0 -4
  10. package/dist/src/ast/binary-op.d.ts.map +1 -1
  11. package/dist/src/ast/binary-op.js +0 -6
  12. package/dist/src/ast/binary-op.js.map +1 -1
  13. package/dist/src/ast/case.d.ts +0 -8
  14. package/dist/src/ast/case.d.ts.map +1 -1
  15. package/dist/src/ast/case.js +0 -16
  16. package/dist/src/ast/case.js.map +1 -1
  17. package/dist/src/ast/cast.d.ts +0 -4
  18. package/dist/src/ast/cast.d.ts.map +1 -1
  19. package/dist/src/ast/cast.js +0 -7
  20. package/dist/src/ast/cast.js.map +1 -1
  21. package/dist/src/ast/collate.d.ts +0 -4
  22. package/dist/src/ast/collate.d.ts.map +1 -1
  23. package/dist/src/ast/collate.js +0 -6
  24. package/dist/src/ast/collate.js.map +1 -1
  25. package/dist/src/ast/column-ref.d.ts +0 -4
  26. package/dist/src/ast/column-ref.d.ts.map +1 -1
  27. package/dist/src/ast/column-ref.js +0 -10
  28. package/dist/src/ast/column-ref.js.map +1 -1
  29. package/dist/src/ast/fragment.d.ts +0 -4
  30. package/dist/src/ast/fragment.d.ts.map +1 -1
  31. package/dist/src/ast/fragment.js +0 -6
  32. package/dist/src/ast/fragment.js.map +1 -1
  33. package/dist/src/ast/from.d.ts +10 -3
  34. package/dist/src/ast/from.d.ts.map +1 -1
  35. package/dist/src/ast/from.js +11 -12
  36. package/dist/src/ast/from.js.map +1 -1
  37. package/dist/src/ast/function.d.ts +0 -4
  38. package/dist/src/ast/function.d.ts.map +1 -1
  39. package/dist/src/ast/function.js +0 -7
  40. package/dist/src/ast/function.js.map +1 -1
  41. package/dist/src/ast/in-op.d.ts +0 -4
  42. package/dist/src/ast/in-op.d.ts.map +1 -1
  43. package/dist/src/ast/in-op.js +0 -6
  44. package/dist/src/ast/in-op.js.map +1 -1
  45. package/dist/src/ast/interval.d.ts +0 -4
  46. package/dist/src/ast/interval.d.ts.map +1 -1
  47. package/dist/src/ast/interval.js +0 -6
  48. package/dist/src/ast/interval.js.map +1 -1
  49. package/dist/src/ast/join.d.ts +45 -0
  50. package/dist/src/ast/join.d.ts.map +1 -0
  51. package/dist/src/ast/join.js +47 -0
  52. package/dist/src/ast/join.js.map +1 -0
  53. package/dist/src/ast/list.d.ts +11 -0
  54. package/dist/src/ast/list.d.ts.map +1 -0
  55. package/dist/src/ast/list.js +15 -0
  56. package/dist/src/ast/list.js.map +1 -0
  57. package/dist/src/ast/literal.d.ts +0 -4
  58. package/dist/src/ast/literal.d.ts.map +1 -1
  59. package/dist/src/ast/literal.js +0 -6
  60. package/dist/src/ast/literal.js.map +1 -1
  61. package/dist/src/ast/logical-op.d.ts +0 -4
  62. package/dist/src/ast/logical-op.d.ts.map +1 -1
  63. package/dist/src/ast/logical-op.js +0 -9
  64. package/dist/src/ast/logical-op.js.map +1 -1
  65. package/dist/src/ast/node.d.ts +13 -0
  66. package/dist/src/ast/node.d.ts.map +1 -1
  67. package/dist/src/ast/node.js +25 -3
  68. package/dist/src/ast/node.js.map +1 -1
  69. package/dist/src/ast/order-by.d.ts +0 -4
  70. package/dist/src/ast/order-by.d.ts.map +1 -1
  71. package/dist/src/ast/order-by.js +0 -13
  72. package/dist/src/ast/order-by.js.map +1 -1
  73. package/dist/src/ast/param.d.ts +0 -4
  74. package/dist/src/ast/param.d.ts.map +1 -1
  75. package/dist/src/ast/param.js +0 -7
  76. package/dist/src/ast/param.js.map +1 -1
  77. package/dist/src/ast/query.d.ts +43 -15
  78. package/dist/src/ast/query.d.ts.map +1 -1
  79. package/dist/src/ast/query.js +71 -92
  80. package/dist/src/ast/query.js.map +1 -1
  81. package/dist/src/ast/sample.d.ts +0 -4
  82. package/dist/src/ast/sample.d.ts.map +1 -1
  83. package/dist/src/ast/sample.js +0 -9
  84. package/dist/src/ast/sample.js.map +1 -1
  85. package/dist/src/ast/select.d.ts +0 -4
  86. package/dist/src/ast/select.d.ts.map +1 -1
  87. package/dist/src/ast/select.js +0 -16
  88. package/dist/src/ast/select.js.map +1 -1
  89. package/dist/src/ast/subquery.d.ts +0 -4
  90. package/dist/src/ast/subquery.d.ts.map +1 -1
  91. package/dist/src/ast/subquery.js +0 -6
  92. package/dist/src/ast/subquery.js.map +1 -1
  93. package/dist/src/ast/table-ref.d.ts +0 -4
  94. package/dist/src/ast/table-ref.d.ts.map +1 -1
  95. package/dist/src/ast/table-ref.js +0 -7
  96. package/dist/src/ast/table-ref.js.map +1 -1
  97. package/dist/src/ast/unary-op.d.ts +0 -8
  98. package/dist/src/ast/unary-op.d.ts.map +1 -1
  99. package/dist/src/ast/unary-op.js +0 -12
  100. package/dist/src/ast/unary-op.js.map +1 -1
  101. package/dist/src/ast/unnest.d.ts +15 -0
  102. package/dist/src/ast/unnest.d.ts.map +1 -0
  103. package/dist/src/ast/unnest.js +21 -0
  104. package/dist/src/ast/unnest.js.map +1 -0
  105. package/dist/src/ast/verbatim.d.ts +0 -4
  106. package/dist/src/ast/verbatim.d.ts.map +1 -1
  107. package/dist/src/ast/verbatim.js +0 -6
  108. package/dist/src/ast/verbatim.js.map +1 -1
  109. package/dist/src/ast/window-frame.d.ts +0 -8
  110. package/dist/src/ast/window-frame.d.ts.map +1 -1
  111. package/dist/src/ast/window-frame.js +1 -29
  112. package/dist/src/ast/window-frame.js.map +1 -1
  113. package/dist/src/ast/window.d.ts +0 -16
  114. package/dist/src/ast/window.d.ts.map +1 -1
  115. package/dist/src/ast/window.js +0 -39
  116. package/dist/src/ast/window.js.map +1 -1
  117. package/dist/src/ast/with.d.ts +0 -4
  118. package/dist/src/ast/with.d.ts.map +1 -1
  119. package/dist/src/ast/with.js +0 -10
  120. package/dist/src/ast/with.js.map +1 -1
  121. package/dist/src/constants.d.ts +4 -0
  122. package/dist/src/constants.d.ts.map +1 -1
  123. package/dist/src/constants.js +4 -0
  124. package/dist/src/constants.js.map +1 -1
  125. package/dist/src/functions/from.d.ts +11 -0
  126. package/dist/src/functions/from.d.ts.map +1 -0
  127. package/dist/src/functions/from.js +12 -0
  128. package/dist/src/functions/from.js.map +1 -0
  129. package/dist/src/functions/join.d.ts +49 -0
  130. package/dist/src/functions/join.d.ts.map +1 -0
  131. package/dist/src/functions/join.js +50 -0
  132. package/dist/src/functions/join.js.map +1 -0
  133. package/dist/src/functions/list.d.ts +31 -0
  134. package/dist/src/functions/list.d.ts.map +1 -0
  135. package/dist/src/functions/list.js +49 -0
  136. package/dist/src/functions/list.js.map +1 -0
  137. package/dist/src/functions/unnest.d.ts +10 -0
  138. package/dist/src/functions/unnest.d.ts.map +1 -0
  139. package/dist/src/functions/unnest.js +12 -0
  140. package/dist/src/functions/unnest.js.map +1 -0
  141. package/dist/src/index.d.ts +11 -1
  142. package/dist/src/index.d.ts.map +1 -1
  143. package/dist/src/index.js +12 -1
  144. package/dist/src/index.js.map +1 -1
  145. package/dist/src/init.d.ts +2 -0
  146. package/dist/src/init.d.ts.map +1 -0
  147. package/dist/src/init.js +5 -0
  148. package/dist/src/init.js.map +1 -0
  149. package/dist/src/transforms/filter-query.d.ts.map +1 -1
  150. package/dist/src/transforms/filter-query.js +2 -0
  151. package/dist/src/transforms/filter-query.js.map +1 -1
  152. package/dist/src/visit/codegen/duckdb.d.ts +49 -0
  153. package/dist/src/visit/codegen/duckdb.d.ts.map +1 -0
  154. package/dist/src/visit/codegen/duckdb.js +332 -0
  155. package/dist/src/visit/codegen/duckdb.js.map +1 -0
  156. package/dist/src/visit/codegen/sql.d.ts +60 -0
  157. package/dist/src/visit/codegen/sql.d.ts.map +1 -0
  158. package/dist/src/visit/codegen/sql.js +85 -0
  159. package/dist/src/visit/codegen/sql.js.map +1 -0
  160. package/dist/src/visit/duckdb-visitor.d.ts +50 -0
  161. package/dist/src/visit/duckdb-visitor.d.ts.map +1 -0
  162. package/dist/src/visit/duckdb-visitor.js +350 -0
  163. package/dist/src/visit/duckdb-visitor.js.map +1 -0
  164. package/dist/src/visit/recurse.d.ts.map +1 -1
  165. package/dist/src/visit/recurse.js +3 -1
  166. package/dist/src/visit/recurse.js.map +1 -1
  167. package/dist/src/visit/to-string-visitor.d.ts +60 -0
  168. package/dist/src/visit/to-string-visitor.d.ts.map +1 -0
  169. package/dist/src/visit/to-string-visitor.js +80 -0
  170. package/dist/src/visit/to-string-visitor.js.map +1 -0
  171. package/package.json +2 -2
  172. package/src/ast/aggregate.ts +0 -16
  173. package/src/ast/between-op.ts +0 -14
  174. package/src/ast/binary-op.ts +0 -7
  175. package/src/ast/case.ts +0 -18
  176. package/src/ast/cast.ts +0 -8
  177. package/src/ast/collate.ts +0 -7
  178. package/src/ast/column-ref.ts +0 -11
  179. package/src/ast/fragment.ts +0 -7
  180. package/src/ast/from.ts +12 -12
  181. package/src/ast/function.ts +0 -8
  182. package/src/ast/in-op.ts +0 -7
  183. package/src/ast/interval.ts +0 -7
  184. package/src/ast/join.ts +66 -0
  185. package/src/ast/list.ts +16 -0
  186. package/src/ast/literal.ts +0 -7
  187. package/src/ast/logical-op.ts +0 -10
  188. package/src/ast/node.ts +30 -3
  189. package/src/ast/order-by.ts +0 -14
  190. package/src/ast/param.ts +0 -8
  191. package/src/ast/query.ts +80 -104
  192. package/src/ast/sample.ts +0 -10
  193. package/src/ast/select.ts +0 -18
  194. package/src/ast/subquery.ts +0 -7
  195. package/src/ast/table-ref.ts +0 -8
  196. package/src/ast/unary-op.ts +0 -14
  197. package/src/ast/unnest.ts +22 -0
  198. package/src/ast/verbatim.ts +0 -7
  199. package/src/ast/window-frame.ts +1 -32
  200. package/src/ast/window.ts +0 -43
  201. package/src/ast/with.ts +0 -11
  202. package/src/constants.ts +4 -0
  203. package/src/functions/from.ts +18 -0
  204. package/src/functions/join.ts +101 -0
  205. package/src/functions/list.ts +63 -0
  206. package/src/functions/unnest.ts +13 -0
  207. package/src/index.ts +13 -1
  208. package/src/init.ts +5 -0
  209. package/src/transforms/filter-query.ts +2 -0
  210. package/src/visit/codegen/duckdb.ts +444 -0
  211. package/src/visit/codegen/sql.ts +213 -0
  212. package/src/visit/recurse.ts +4 -0
package/src/ast/query.ts CHANGED
@@ -6,7 +6,7 @@ import { exprList, nodeList } from '../util/function.js';
6
6
  import { unquote } from '../util/string.js';
7
7
  import { isArray, isString } from '../util/type-check.js';
8
8
  import { isColumnRef } from './column-ref.js';
9
- import { FromClauseNode } from './from.js';
9
+ import { FromClauseNode, FromNode } from './from.js';
10
10
  import { ExprNode, SQLNode, isNode } from './node.js';
11
11
  import { SampleClauseNode } from './sample.js';
12
12
  import { SelectClauseNode } from './select.js';
@@ -71,6 +71,14 @@ export class Query extends ExprNode {
71
71
  return new SetOperation('UNION', queries.flat());
72
72
  }
73
73
 
74
+ /**
75
+ * Create a new UNION BY NAME set operation over the given queries.
76
+ * @param queries The queries.
77
+ */
78
+ static unionByName(...queries: MaybeArray<Query>[]) {
79
+ return new SetOperation('UNION BY NAME', queries.flat());
80
+ }
81
+
74
82
  /**
75
83
  * Create a new UNION ALL set operation over the given queries.
76
84
  * @param queries The queries.
@@ -79,6 +87,14 @@ export class Query extends ExprNode {
79
87
  return new SetOperation('UNION ALL', queries.flat());
80
88
  }
81
89
 
90
+ /**
91
+ * Create a new UNION ALL BY NAME set operation over the given queries.
92
+ * @param queries The queries.
93
+ */
94
+ static unionAllByName(...queries: MaybeArray<Query>[]) {
95
+ return new SetOperation('UNION ALL BY NAME', queries.flat());
96
+ }
97
+
82
98
  /**
83
99
  * Create a new INTERSECT set operation over the given queries.
84
100
  * @param queries The queries.
@@ -87,6 +103,14 @@ export class Query extends ExprNode {
87
103
  return new SetOperation('INTERSECT', queries.flat());
88
104
  }
89
105
 
106
+ /**
107
+ * Create a new INTERSECT ALL set operation over the given queries.
108
+ * @param queries The queries.
109
+ */
110
+ static intersectAll(...queries: MaybeArray<Query>[]) {
111
+ return new SetOperation('INTERSECT ALL', queries.flat());
112
+ }
113
+
90
114
  /**
91
115
  * Create a new EXCEPT set operation over the given queries.
92
116
  * @param queries The queries.
@@ -95,6 +119,14 @@ export class Query extends ExprNode {
95
119
  return new SetOperation('EXCEPT', queries.flat());
96
120
  }
97
121
 
122
+ /**
123
+ * Create a new EXCEPT ALL set operation over the given queries.
124
+ * @param queries The queries.
125
+ */
126
+ static exceptAll(...queries: MaybeArray<Query>[]) {
127
+ return new SetOperation('EXCEPT ALL', queries.flat());
128
+ }
129
+
98
130
  /**
99
131
  * Create a new describe query for the given input query.
100
132
  * @param query The query to describe.
@@ -199,7 +231,7 @@ export class Query extends ExprNode {
199
231
 
200
232
  export class SelectQuery extends Query {
201
233
  _select: SelectClauseNode[] = [];
202
- _from: FromClauseNode[] = [];
234
+ _from: FromNode[] = [];
203
235
  _where: ExprNode[] = [];
204
236
  _sample?: SampleClauseNode;
205
237
  _groupby: ExprNode[] = [];
@@ -229,13 +261,17 @@ export class SelectQuery extends Query {
229
261
 
230
262
  // extract subqueries in FROM clause
231
263
  // unused CTEs will be ignored
264
+ // WARNING: does not recurse into join inputs!
232
265
  const queries: Query[] = [];
233
- this._from.forEach(({ expr }) => {
234
- if (isQuery(expr)) {
235
- queries.push(expr);
236
- } else if (isTableRef(expr)) {
237
- const subq = cte[expr.name];
238
- if (subq) queries.push(subq);
266
+ this._from.forEach(node => {
267
+ if (node instanceof FromClauseNode) {
268
+ const { expr } = node;
269
+ if (isQuery(expr)) {
270
+ queries.push(expr);
271
+ } else if (isTableRef(expr)) {
272
+ const subq = cte[expr.name];
273
+ if (subq) queries.push(subq);
274
+ }
239
275
  }
240
276
  });
241
277
  return queries;
@@ -298,7 +334,7 @@ export class SelectQuery extends Query {
298
334
  * @param expr Expressions to add.
299
335
  */
300
336
  from(...expr: FromExpr[]): this {
301
- const list: FromClauseNode[] = [];
337
+ const list: FromNode[] = [];
302
338
 
303
339
  const add = (v: string | string[] | SQLNode, as?: string) => {
304
340
  list.push(new FromClauseNode(maybeTableRef(v), unquote(as)));
@@ -306,7 +342,7 @@ export class SelectQuery extends Query {
306
342
 
307
343
  expr.flat().forEach(e => {
308
344
  if (e == null) return;
309
- else if (e instanceof FromClauseNode) list.push(e);
345
+ else if (e instanceof FromNode) list.push(e);
310
346
  else if (isString(e)) add(e, e);
311
347
  else if (isTableRef(e)) add(e, e.name);
312
348
  else if (isNode(e)) add(e);
@@ -334,7 +370,7 @@ export class SelectQuery extends Query {
334
370
  * @param seed The random seed.
335
371
  */
336
372
  sample(
337
- value: number | SampleClauseNode,
373
+ value?: number | SampleClauseNode | null,
338
374
  method?: SampleMethod,
339
375
  seed?: number
340
376
  ): this {
@@ -346,7 +382,7 @@ export class SelectQuery extends Query {
346
382
  } else {
347
383
  clause = value;
348
384
  }
349
- this._sample = clause;
385
+ this._sample = clause ?? undefined;
350
386
  return this;
351
387
  }
352
388
 
@@ -418,66 +454,6 @@ export class SelectQuery extends Query {
418
454
  this._qualify = this._qualify.concat(exprList(expr, asVerbatim));
419
455
  return this;
420
456
  }
421
-
422
- /**
423
- * Generate a SQL query string.
424
- */
425
- toString() {
426
- const {
427
- _with, _select, _distinct, _from, _sample, _where, _groupby,
428
- _having, _window, _qualify, _orderby, _limitPerc, _limit, _offset
429
- } = this;
430
- const sql = [];
431
-
432
- // WITH
433
- if (_with.length) sql.push(`WITH ${_with.join(', ')}`);
434
-
435
- // SELECT
436
- sql.push(`SELECT${_distinct ? ' DISTINCT' : ''} ${_select.join(', ')}`);
437
-
438
- // FROM
439
- if (_from.length) sql.push(`FROM ${_from.join(', ')}`);
440
-
441
- // WHERE
442
- if (_where.length) {
443
- const clauses = _where.map(String).filter(x => x).join(' AND ');
444
- if (clauses) sql.push(`WHERE ${clauses}`);
445
- }
446
-
447
- // SAMPLE
448
- if (_sample) sql.push(`USING SAMPLE ${_sample}`);
449
-
450
- // GROUP BY
451
- if (_groupby.length) {
452
- sql.push(`GROUP BY ${_groupby.join(', ')}`);
453
- }
454
-
455
- // HAVING
456
- if (_having.length) {
457
- const clauses = _having.map(String).filter(x => x).join(' AND ');
458
- if (clauses) sql.push(`HAVING ${clauses}`);
459
- }
460
-
461
- // WINDOW
462
- if (_window.length) sql.push(`WINDOW ${_window.join(', ')}`);
463
-
464
- // QUALIFY
465
- if (_qualify.length) {
466
- const clauses = _qualify.map(String).filter(x => x).join(' AND ');
467
- if (clauses) sql.push(`QUALIFY ${clauses}`);
468
- }
469
-
470
- // ORDER BY
471
- if (_orderby.length) sql.push(`ORDER BY ${_orderby.join(', ')}`);
472
-
473
- // LIMIT
474
- if (_limit) sql.push(`LIMIT ${_limit}${_limitPerc ? '%' : ''}`);
475
-
476
- // OFFSET
477
- if (_offset) sql.push(`OFFSET ${_offset}`);
478
-
479
- return sql.join(' ');
480
- }
481
457
  }
482
458
 
483
459
  export class DescribeQuery extends SQLNode {
@@ -499,13 +475,6 @@ export class DescribeQuery extends SQLNode {
499
475
  // @ts-expect-error creates describe query
500
476
  return new DescribeQuery(this.query.clone());
501
477
  }
502
-
503
- /**
504
- * Generate a SQL query string.
505
- */
506
- toString() {
507
- return `DESCRIBE ${this.query}`;
508
- }
509
478
  }
510
479
 
511
480
  export class SetOperation extends Query {
@@ -550,31 +519,6 @@ export class SetOperation extends Query {
550
519
  // @ts-expect-error creates set operation
551
520
  return Object.assign(new SetOperation(op, queries), rest);
552
521
  }
553
-
554
- /**
555
- * Generate a SQL query string.
556
- */
557
- toString() {
558
- const { op, queries, _with, _orderby, _limitPerc, _limit, _offset } = this;
559
- const sql = [];
560
-
561
- // WITH
562
- if (_with.length) sql.push(`WITH ${_with.join(', ')}`);
563
-
564
- // SUBQUERIES
565
- sql.push(queries.join(` ${op} `));
566
-
567
- // ORDER BY
568
- if (_orderby.length) sql.push(`ORDER BY ${_orderby.join(', ')}`);
569
-
570
- // LIMIT
571
- if (_limit) sql.push(`LIMIT ${_limit}${_limitPerc ? '%' : ''}`);
572
-
573
- // OFFSET
574
- if (_offset) sql.push(`OFFSET ${_offset}`);
575
-
576
- return sql.join(' ');
577
- }
578
522
  }
579
523
 
580
524
  class WithClause {
@@ -613,6 +557,14 @@ class WithClause {
613
557
  return Query.union(...queries).with(...this._with);
614
558
  }
615
559
 
560
+ /**
561
+ * Create a new UNION BY NAME set operation over the given queries.
562
+ * @param queries The queries.
563
+ */
564
+ unionByName(...queries: Query[]) {
565
+ return Query.unionByName(...queries).with(...this._with);
566
+ }
567
+
616
568
  /**
617
569
  * Create a new UNION ALL set operation over the given queries.
618
570
  * @param queries The queries.
@@ -621,6 +573,14 @@ class WithClause {
621
573
  return Query.unionAll(...queries).with(...this._with);
622
574
  }
623
575
 
576
+ /**
577
+ * Create a new UNION ALL BY NAME set operation over the given queries.
578
+ * @param queries The queries.
579
+ */
580
+ unionAllByName(...queries: Query[]) {
581
+ return Query.unionAllByName(...queries).with(...this._with);
582
+ }
583
+
624
584
  /**
625
585
  * Create a new INTERSECT set operation over the given queries.
626
586
  * @param queries The queries.
@@ -629,6 +589,14 @@ class WithClause {
629
589
  return Query.intersect(...queries).with(...this._with);
630
590
  }
631
591
 
592
+ /**
593
+ * Create a new INTERSECT ALL set operation over the given queries.
594
+ * @param queries The queries.
595
+ */
596
+ intersectAll(...queries: Query[]) {
597
+ return Query.intersectAll(...queries).with(...this._with);
598
+ }
599
+
632
600
  /**
633
601
  * Create a new EXCEPT set operation over the given queries.
634
602
  * @param queries The queries.
@@ -636,4 +604,12 @@ class WithClause {
636
604
  except(...queries: Query[]) {
637
605
  return Query.except(...queries).with(...this._with);
638
606
  }
607
+
608
+ /**
609
+ * Create a new EXCEPT ALL set operation over the given queries.
610
+ * @param queries The queries.
611
+ */
612
+ exceptAll(...queries: Query[]) {
613
+ return Query.exceptAll(...queries).with(...this._with);
614
+ }
639
615
  }
package/src/ast/sample.ts CHANGED
@@ -34,14 +34,4 @@ export class SampleClauseNode extends SQLNode {
34
34
  this.method = method;
35
35
  this.seed = seed;
36
36
  }
37
-
38
- /**
39
- * Generate a SQL query string for this node.
40
- */
41
- toString() {
42
- const { size, perc, method, seed } = this;
43
- const m = method ? `${method} ` : '';
44
- const s = seed != null ? ` REPEATABLE (${seed})` : '';
45
- return `${m}(${size}${perc ? '%' : ' ROWS'})${s}`;
46
- }
47
37
  }
package/src/ast/select.ts CHANGED
@@ -1,7 +1,5 @@
1
1
  import type { ExprNode } from './node.js';
2
2
  import { SELECT_CLAUSE } from '../constants.js';
3
- import { quoteIdentifier } from '../util/string.js';
4
- import { ColumnRefNode } from './column-ref.js';
5
3
  import { SQLNode } from './node.js';
6
4
 
7
5
  export class SelectClauseNode extends SQLNode {
@@ -20,20 +18,4 @@ export class SelectClauseNode extends SQLNode {
20
18
  this.expr = expr;
21
19
  this.alias = alias;
22
20
  }
23
-
24
- /**
25
- * Generate a SQL query string for this node.
26
- */
27
- toString() {
28
- const { expr, alias } = this;
29
- return !alias || isColumnRefFor(expr, alias)
30
- ? `${expr}`
31
- : `${expr} AS ${quoteIdentifier(alias)}`;
32
- }
33
- }
34
-
35
- function isColumnRefFor(expr: unknown, name: string): expr is ColumnRefNode {
36
- return expr instanceof ColumnRefNode
37
- && expr.table == null
38
- && expr.column === name;
39
21
  }
@@ -14,11 +14,4 @@ export class ScalarSubqueryNode extends ExprNode {
14
14
  super(SCALAR_SUBQUERY);
15
15
  this.subquery = subquery;
16
16
  }
17
-
18
- /**
19
- * Generate a SQL query string for this node.
20
- */
21
- toString() {
22
- return `(${this.subquery})`;
23
- }
24
17
  }
@@ -1,5 +1,4 @@
1
1
  import { TABLE_REF } from '../constants.js';
2
- import { quoteIdentifier } from '../util/string.js';
3
2
  import { ExprNode } from './node.js';
4
3
 
5
4
  /**
@@ -29,11 +28,4 @@ export class TableRefNode extends ExprNode {
29
28
  get name() {
30
29
  return this.table[this.table.length - 1];
31
30
  }
32
-
33
- /**
34
- * Generate a SQL query string for this node.
35
- */
36
- toString() {
37
- return this.table.map(t => quoteIdentifier(t)).join('.');
38
- }
39
31
  }
@@ -29,13 +29,6 @@ export class UnaryOpNode extends AbstractUnaryOpNode {
29
29
  constructor(op: string, expr: ExprNode) {
30
30
  super(UNARY_OPERATOR, op, expr);
31
31
  }
32
-
33
- /**
34
- * Generate a SQL query string for this node.
35
- */
36
- toString() {
37
- return `(${this.op} ${this.expr})`;
38
- }
39
32
  }
40
33
 
41
34
  export class UnaryPostfixOpNode extends AbstractUnaryOpNode {
@@ -47,11 +40,4 @@ export class UnaryPostfixOpNode extends AbstractUnaryOpNode {
47
40
  constructor(op: string, expr: ExprNode) {
48
41
  super(UNARY_POSTFIX_OPERATOR, op, expr);
49
42
  }
50
-
51
- /**
52
- * Generate a SQL query string for this node.
53
- */
54
- toString() {
55
- return `(${this.expr} ${this.op})`;
56
- }
57
43
  }
@@ -0,0 +1,22 @@
1
+ import { UNNEST } from '../constants.js';
2
+ import { ExprNode } from './node.js';
3
+
4
+ export class UnnestNode extends ExprNode {
5
+ /** An expression that resolves to a list or a struct */
6
+ readonly expr: ExprNode;
7
+ readonly recursive: boolean;
8
+ readonly maxDepth: number;
9
+
10
+ /**
11
+ * Instantiate an Unnest node.
12
+ * @param expr
13
+ * @param recursive
14
+ * @param maxDepth
15
+ */
16
+ constructor(expr: ExprNode, recursive = false, maxDepth = 0) {
17
+ super(UNNEST);
18
+ this.expr = expr;
19
+ this.recursive = recursive;
20
+ this.maxDepth = maxDepth;
21
+ }
22
+ }
@@ -17,11 +17,4 @@ export class VerbatimNode extends ExprNode {
17
17
  this.value = value;
18
18
  this.hint = hint;
19
19
  }
20
-
21
- /**
22
- * Generate a SQL query string for this node.
23
- */
24
- toString() {
25
- return this.value;
26
- }
27
20
  }
@@ -1,7 +1,7 @@
1
1
  import { WINDOW_EXTENT_EXPR, WINDOW_FRAME } from '../constants.js';
2
2
  import { type ParamLike } from '../types.js';
3
3
  import { isParamLike } from '../util/type-check.js';
4
- import { type ExprNode, isNode, SQLNode } from './node.js';
4
+ import { type ExprNode, SQLNode } from './node.js';
5
5
  import { ParamNode } from './param.js';
6
6
 
7
7
  export type FrameValue = ExprNode | number | null;
@@ -42,27 +42,6 @@ export class WindowFrameNode extends SQLNode {
42
42
  this.extent = isParamLike(extent) ? new ParamNode(extent) : extent;
43
43
  this.exclude = exclude;
44
44
  }
45
-
46
- /**
47
- * Generate a SQL query string for this node.
48
- */
49
- toString() {
50
- const { frameType, exclude, extent } = this;
51
- const [prev, next] = isNode(extent)
52
- ? extent.value as [unknown, unknown]
53
- : extent;
54
- const a = asFrameExpr(prev, PRECEDING);
55
- const b = asFrameExpr(next, FOLLOWING);
56
- return `${frameType} BETWEEN ${a} AND ${b}${exclude ? ` ${exclude}` : ''}`;
57
- }
58
- }
59
-
60
- function asFrameExpr(value: unknown, scope: string) {
61
- return value instanceof WindowFrameExprNode ? value
62
- : value != null && typeof value !== 'number' ? `${value} ${scope}`
63
- : value === 0 ? CURRENT_ROW
64
- : !(value && Number.isFinite(value)) ? `${UNBOUNDED} ${scope}`
65
- : `${Math.abs(value)} ${scope}`;
66
45
  }
67
46
 
68
47
  export class WindowFrameExprNode extends SQLNode {
@@ -84,14 +63,4 @@ export class WindowFrameExprNode extends SQLNode {
84
63
  this.scope = scope;
85
64
  this.expr = expr;
86
65
  }
87
-
88
- /**
89
- * Generate a SQL query string for this node.
90
- */
91
- toString() {
92
- const { scope, expr } = this;
93
- return scope === CURRENT_ROW
94
- ? scope
95
- : `${expr ?? UNBOUNDED} ${scope}`;
96
- }
97
66
  }
package/src/ast/window.ts CHANGED
@@ -3,7 +3,6 @@ import type { AggregateNode } from './aggregate.js';
3
3
  import type { WindowFrameNode } from './window-frame.js';
4
4
  import { WINDOW, WINDOW_CLAUSE, WINDOW_DEF, WINDOW_FUNCTION } from '../constants.js';
5
5
  import { nodeList } from '../util/function.js';
6
- import { quoteIdentifier } from '../util/string.js';
7
6
  import { ExprNode, SQLNode } from './node.js';
8
7
 
9
8
  export class WindowClauseNode extends SQLNode {
@@ -22,13 +21,6 @@ export class WindowClauseNode extends SQLNode {
22
21
  this.name = name;
23
22
  this.def = def;
24
23
  }
25
-
26
- /**
27
- * Generate a SQL query string for this node.
28
- */
29
- toString() {
30
- return `${quoteIdentifier(this.name)} AS ${this.def}`;
31
- }
32
24
  }
33
25
 
34
26
  export class WindowNode extends ExprNode {
@@ -84,13 +76,6 @@ export class WindowNode extends ExprNode {
84
76
  frame(framedef: WindowFrameNode) {
85
77
  return new WindowNode(this.func, this.def.frame(framedef));
86
78
  }
87
-
88
- /**
89
- * Generate a SQL query string for this node.
90
- */
91
- toString() {
92
- return `${this.func} OVER ${this.def}`;
93
- }
94
79
  }
95
80
 
96
81
  export class WindowFunctionNode extends ExprNode {
@@ -123,19 +108,6 @@ export class WindowFunctionNode extends ExprNode {
123
108
  this.ignoreNulls = ignoreNulls;
124
109
  this.order = nodeList([argOrder]);
125
110
  }
126
-
127
- /**
128
- * Generate a SQL query string for this node.
129
- */
130
- toString() {
131
- const { name, args, ignoreNulls, order } = this;
132
- const arg = [
133
- args.join(', '),
134
- order.length ? `ORDER BY ${order.join(', ')}` : '',
135
- ignoreNulls ? 'IGNORE NULLS' : ''
136
- ].filter(x => x).join(' ');
137
- return `${name}(${arg})`;
138
- }
139
111
  }
140
112
 
141
113
  export class WindowDefNode extends SQLNode {
@@ -203,21 +175,6 @@ export class WindowDefNode extends SQLNode {
203
175
  frame(framedef: WindowFrameNode) {
204
176
  return deriveDef(this, { framedef });
205
177
  }
206
-
207
- /**
208
- * Generate a SQL query string for this node.
209
- */
210
- toString() {
211
- const { name, partition, order, framedef } = this;
212
- const base = name && quoteIdentifier(name);
213
- const def = [
214
- base,
215
- partition?.length && `PARTITION BY ${partition.join(', ')}`,
216
- order?.length && `ORDER BY ${order.join(', ')}`,
217
- framedef
218
- ].filter(x => x);
219
- return base && def.length < 2 ? base : `(${def.join(' ')})`;
220
- }
221
178
  }
222
179
 
223
180
  interface DeriveDefOptions {
package/src/ast/with.ts CHANGED
@@ -29,15 +29,4 @@ export class WithClauseNode extends SQLNode {
29
29
  this.query = query;
30
30
  this.materialized = materialized;
31
31
  }
32
-
33
- /**
34
- * Generate a SQL query string for this node.
35
- */
36
- toString() {
37
- const flag = this.materialized;
38
- const mat = flag === true ? ' MATERIALIZED'
39
- : flag === false ? ' NOT MATERIALIZED'
40
- : '';
41
- return `"${this.name}" AS${mat} (${this.query})`;
42
- }
43
32
  }
package/src/constants.ts CHANGED
@@ -3,6 +3,8 @@ export const COLUMN_PARAM = 'COLUMN_PARAM';
3
3
  export const TABLE_REF = 'TABLE_REF';
4
4
  export const LITERAL = 'LITERAL';
5
5
  export const INTERVAL = 'INTERVAL';
6
+ export const LIST = 'LIST';
7
+ export const UNNEST = 'UNNEST';
6
8
 
7
9
  export const ORDER_BY = 'ORDER_BY';
8
10
  export const CAST = 'CAST';
@@ -25,6 +27,7 @@ export const WINDOW_FUNCTION = 'WINDOW_FUNCTION';
25
27
  export const WINDOW_DEF = 'WINDOW_DEF';
26
28
  export const WINDOW_FRAME = 'WINDOW_FRAME';
27
29
  export const WINDOW_EXTENT_EXPR = 'WINDOW_EXTENT_EXPR';
30
+ export const CUSTOM = 'CUSTOM';
28
31
 
29
32
  export const EXPRESSION = 'EXPRESSION';
30
33
  export const FRAGMENT = 'FRAGMENT';
@@ -35,6 +38,7 @@ export const WITH_CLAUSE = 'WITH_CLAUSE';
35
38
  export const WINDOW_CLAUSE = 'WINDOW_CLAUSE';
36
39
  export const SELECT_CLAUSE = 'SELECT_CLAUSE';
37
40
  export const FROM_CLAUSE = 'FROM_CLAUSE';
41
+ export const JOIN_CLAUSE = 'JOIN_CLAUSE';
38
42
  export const SAMPLE_CLAUSE = 'SAMPLE_CLAUSE';
39
43
 
40
44
  export const SELECT_QUERY = 'SELECT_QUERY';
@@ -0,0 +1,18 @@
1
+ import { FromClauseNode } from "../ast/from.js";
2
+ import { SampleClauseNode } from "../ast/sample.js";
3
+ import { TableRefNode } from "../ast/table-ref.js";
4
+ import { asTableRef } from "../util/ast.js";
5
+
6
+ /**
7
+ * Create a new table FROM reference, applicable in a query or join.
8
+ * @param table The table.
9
+ * @param alias An optional table alias.
10
+ * @param sample An optional table sample to apply.
11
+ */
12
+ export function from(
13
+ table: string | string[] | TableRefNode,
14
+ alias?: string,
15
+ sample?: SampleClauseNode
16
+ ) {
17
+ return new FromClauseNode(asTableRef(table)!, alias, sample);
18
+ }