@uwdata/mosaic-sql 0.19.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 (202) 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 +0 -4
  54. package/dist/src/ast/list.d.ts.map +1 -1
  55. package/dist/src/ast/list.js +0 -6
  56. package/dist/src/ast/list.js.map +1 -1
  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 +2 -14
  78. package/dist/src/ast/query.d.ts.map +1 -1
  79. package/dist/src/ast/query.js +14 -91
  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 +0 -4
  102. package/dist/src/ast/unnest.d.ts.map +1 -1
  103. package/dist/src/ast/unnest.js +0 -8
  104. package/dist/src/ast/unnest.js.map +1 -1
  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 +2 -0
  122. package/dist/src/constants.d.ts.map +1 -1
  123. package/dist/src/constants.js +2 -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/index.d.ts +7 -1
  134. package/dist/src/index.d.ts.map +1 -1
  135. package/dist/src/index.js +8 -1
  136. package/dist/src/index.js.map +1 -1
  137. package/dist/src/init.d.ts +2 -0
  138. package/dist/src/init.d.ts.map +1 -0
  139. package/dist/src/init.js +5 -0
  140. package/dist/src/init.js.map +1 -0
  141. package/dist/src/transforms/filter-query.d.ts.map +1 -1
  142. package/dist/src/transforms/filter-query.js +2 -0
  143. package/dist/src/transforms/filter-query.js.map +1 -1
  144. package/dist/src/visit/codegen/duckdb.d.ts +49 -0
  145. package/dist/src/visit/codegen/duckdb.d.ts.map +1 -0
  146. package/dist/src/visit/codegen/duckdb.js +332 -0
  147. package/dist/src/visit/codegen/duckdb.js.map +1 -0
  148. package/dist/src/visit/codegen/sql.d.ts +60 -0
  149. package/dist/src/visit/codegen/sql.d.ts.map +1 -0
  150. package/dist/src/visit/codegen/sql.js +85 -0
  151. package/dist/src/visit/codegen/sql.js.map +1 -0
  152. package/dist/src/visit/duckdb-visitor.d.ts +50 -0
  153. package/dist/src/visit/duckdb-visitor.d.ts.map +1 -0
  154. package/dist/src/visit/duckdb-visitor.js +350 -0
  155. package/dist/src/visit/duckdb-visitor.js.map +1 -0
  156. package/dist/src/visit/recurse.d.ts.map +1 -1
  157. package/dist/src/visit/recurse.js +2 -1
  158. package/dist/src/visit/recurse.js.map +1 -1
  159. package/dist/src/visit/to-string-visitor.d.ts +60 -0
  160. package/dist/src/visit/to-string-visitor.d.ts.map +1 -0
  161. package/dist/src/visit/to-string-visitor.js +80 -0
  162. package/dist/src/visit/to-string-visitor.js.map +1 -0
  163. package/package.json +2 -2
  164. package/src/ast/aggregate.ts +0 -16
  165. package/src/ast/between-op.ts +0 -14
  166. package/src/ast/binary-op.ts +0 -7
  167. package/src/ast/case.ts +0 -18
  168. package/src/ast/cast.ts +0 -8
  169. package/src/ast/collate.ts +0 -7
  170. package/src/ast/column-ref.ts +0 -11
  171. package/src/ast/fragment.ts +0 -7
  172. package/src/ast/from.ts +12 -12
  173. package/src/ast/function.ts +0 -8
  174. package/src/ast/in-op.ts +0 -7
  175. package/src/ast/interval.ts +0 -7
  176. package/src/ast/join.ts +66 -0
  177. package/src/ast/list.ts +0 -7
  178. package/src/ast/literal.ts +0 -7
  179. package/src/ast/logical-op.ts +0 -10
  180. package/src/ast/node.ts +30 -3
  181. package/src/ast/order-by.ts +0 -14
  182. package/src/ast/param.ts +0 -8
  183. package/src/ast/query.ts +14 -102
  184. package/src/ast/sample.ts +0 -10
  185. package/src/ast/select.ts +0 -18
  186. package/src/ast/subquery.ts +0 -7
  187. package/src/ast/table-ref.ts +0 -8
  188. package/src/ast/unary-op.ts +0 -14
  189. package/src/ast/unnest.ts +0 -9
  190. package/src/ast/verbatim.ts +0 -7
  191. package/src/ast/window-frame.ts +1 -32
  192. package/src/ast/window.ts +0 -43
  193. package/src/ast/with.ts +0 -11
  194. package/src/constants.ts +2 -0
  195. package/src/functions/from.ts +18 -0
  196. package/src/functions/join.ts +101 -0
  197. package/src/index.ts +9 -1
  198. package/src/init.ts +5 -0
  199. package/src/transforms/filter-query.ts +2 -0
  200. package/src/visit/codegen/duckdb.ts +444 -0
  201. package/src/visit/codegen/sql.ts +213 -0
  202. package/src/visit/recurse.ts +2 -0
package/src/ast/case.ts CHANGED
@@ -52,17 +52,6 @@ export class CaseNode extends ExprNode {
52
52
  else(expr: ExprValue) {
53
53
  return new CaseNode(this.expr, this._when, asNode(expr));
54
54
  }
55
-
56
- /**
57
- * Generate a SQL query string for this node.
58
- */
59
- toString() {
60
- return 'CASE '
61
- + (this.expr ? `${this.expr} ` : '')
62
- + this._when.join(' ')
63
- + (this._else ? ` ELSE ${this._else}` : '')
64
- + ' END';
65
- }
66
55
  }
67
56
 
68
57
  export class WhenNode extends SQLNode {
@@ -81,11 +70,4 @@ export class WhenNode extends SQLNode {
81
70
  this.when = when;
82
71
  this.then = then;
83
72
  }
84
-
85
- /**
86
- * Generate a SQL query string for this node.
87
- */
88
- toString() {
89
- return `WHEN ${this.when} THEN ${this.then}`;
90
- }
91
73
  }
package/src/ast/cast.ts CHANGED
@@ -17,12 +17,4 @@ export class CastNode extends ExprNode {
17
17
  this.expr = expr;
18
18
  this.cast = type;
19
19
  }
20
-
21
- /**
22
- * Generate a SQL query string for this node.
23
- */
24
- toString() {
25
- // TODO? could include check to see if parens are necessary
26
- return `(${this.expr})::${this.cast}`;
27
- }
28
20
  }
@@ -17,11 +17,4 @@ export class CollateNode extends ExprNode {
17
17
  this.expr = expr;
18
18
  this.collation = collation;
19
19
  }
20
-
21
- /**
22
- * Generate a SQL query string for this node.
23
- */
24
- toString() {
25
- return `${this.expr} ${COLLATE} ${this.collation}`;
26
- }
27
20
  }
@@ -1,6 +1,5 @@
1
1
  import type { TableRefNode } from './table-ref.js';
2
2
  import { COLUMN_REF } from '../constants.js';
3
- import { quoteIdentifier } from '../util/string.js';
4
3
  import { ExprNode } from './node.js';
5
4
 
6
5
  /**
@@ -31,16 +30,6 @@ export class ColumnRefNode extends ExprNode {
31
30
  get column() {
32
31
  return ''; // subclasses to override
33
32
  }
34
-
35
- /**
36
- * Generate a SQL query string for this node.
37
- */
38
- toString() {
39
- const { column, table } = this;
40
- const tref = `${table ?? ''}`;
41
- const id = column === '*' ? '*' : quoteIdentifier(column);
42
- return (tref ? (tref + '.') : '') + id;
43
- }
44
33
  }
45
34
 
46
35
  export class ColumnNameRefNode extends ColumnRefNode {
@@ -18,11 +18,4 @@ export class FragmentNode extends ExprNode {
18
18
  super(FRAGMENT);
19
19
  this.spans = spans;
20
20
  }
21
-
22
- /**
23
- * Generate a SQL query string for this node.
24
- */
25
- toString() {
26
- return this.spans.join('');
27
- }
28
21
  }
package/src/ast/from.ts CHANGED
@@ -1,11 +1,15 @@
1
1
  import type { SampleClauseNode } from './sample.js';
2
2
  import { FROM_CLAUSE } from '../constants.js';
3
- import { quoteIdentifier } from '../util/string.js';
4
3
  import { SQLNode } from './node.js';
5
- import { isQuery } from './query.js';
6
- import { isTableRef } from './table-ref.js';
7
4
 
8
- export class FromClauseNode extends SQLNode {
5
+ /**
6
+ * AST node corresponding to a table source which can appear
7
+ * within a SQL `FROM` clause.
8
+ */
9
+ export class FromNode extends SQLNode {
10
+ }
11
+
12
+ export class FromClauseNode extends FromNode {
9
13
  /** The from expression. */
10
14
  readonly expr: SQLNode;
11
15
  /** The output name. */
@@ -27,14 +31,10 @@ export class FromClauseNode extends SQLNode {
27
31
  }
28
32
 
29
33
  /**
30
- * Generate a SQL query string for this node.
34
+ * Create a new from clause node that uses the given alias.
35
+ * @param string alias
31
36
  */
32
- toString() {
33
- const { expr, alias, sample } = this;
34
- const ref = isQuery(expr) ? `(${expr})` : `${expr}`;
35
- const from = alias && !(isTableRef(expr) && expr.table.join('.') === alias)
36
- ? `${ref} AS ${quoteIdentifier(alias)}`
37
- : `${ref}`;
38
- return `${from}${sample ? ` TABLESAMPLE ${sample}` : ''}`;
37
+ as(alias: string) {
38
+ return new FromClauseNode(this.expr, alias, this.sample);
39
39
  }
40
40
  }
@@ -17,12 +17,4 @@ export class FunctionNode extends ExprNode {
17
17
  this.name = name;
18
18
  this.args = args;
19
19
  }
20
-
21
- /**
22
- * Generate a SQL query string for this node.
23
- */
24
- toString() {
25
- const { name, args } = this;
26
- return `${name}(${args.join(', ')})`;
27
- }
28
20
  }
package/src/ast/in-op.ts CHANGED
@@ -17,11 +17,4 @@ export class InOpNode extends ExprNode {
17
17
  this.expr = expr;
18
18
  this.values = values;
19
19
  }
20
-
21
- /**
22
- * Generate a SQL query string for this node.
23
- */
24
- toString() {
25
- return `(${this.expr} IN (${this.values.join(', ')}))`;
26
- }
27
20
  }
@@ -17,11 +17,4 @@ export class IntervalNode extends ExprNode {
17
17
  this.name = name;
18
18
  this.steps = steps;
19
19
  }
20
-
21
- /**
22
- * Generate a SQL query string for this node.
23
- */
24
- toString() {
25
- return `INTERVAL ${this.steps} ${this.name}`;
26
- }
27
20
  }
@@ -0,0 +1,66 @@
1
+ import type { SampleClauseNode } from './sample.js';
2
+ import { JOIN_CLAUSE } from '../constants.js';
3
+ import { ColumnRefNode } from './column-ref.js';
4
+ import { FromNode } from './from.js';
5
+ import { ExprNode } from './node.js';
6
+ import { TableRefNode } from './table-ref.js';
7
+
8
+ /** The join variant. Determines what kind of join is performed. */
9
+ export type JoinVariant = 'REGULAR' | 'CROSS' | 'NATURAL' | 'POSITIONAL' | 'ASOF';
10
+
11
+ /** The join type. Determines which values are included in the join output. */
12
+ export type JoinType = 'INNER' | 'LEFT' | 'RIGHT' | 'FULL' | 'SEMI' | 'ANTI';
13
+
14
+ export class JoinNode extends FromNode {
15
+ /** The left table to join. */
16
+ readonly left: FromNode | TableRefNode;
17
+ /** The right table to join. */
18
+ readonly right: FromNode | TableRefNode;
19
+ /** The join variant (REGULAR, CROSS, NATURAL, POSITIONAL, ASOF). */
20
+ readonly joinVariant: JoinVariant;
21
+ /** The join type (INNER, LEFT, RIGHT, FULL, SEMI, ANTI). */
22
+ readonly joinType: JoinType;
23
+ /**
24
+ * The join condition as a boolean expression.
25
+ * If specified, *using* should be `undefined`.
26
+ */
27
+ readonly condition?: ExprNode;
28
+ /**
29
+ * The join condition as shared columns to match on.
30
+ * If specified, *condition* should be `undefined`.
31
+ */
32
+ readonly using?: ColumnRefNode[];
33
+ /** A table sample to apply to join output. */
34
+ readonly sample?: SampleClauseNode;
35
+
36
+ /**
37
+ * Instantiate a join node.
38
+ * @param left The left table to join.
39
+ * @param right The right table to join.
40
+ * @param variant The join variant (REGULAR, CROSS, NATURAL, POSITIONAL, ASOF).
41
+ * @param type The join type (INNER, LEFT, RIGHT, FULL, SEMI, ANTI).
42
+ * @param condition The join condition as a boolean expression.
43
+ * If specified, *using* should be `undefined`.
44
+ * @param using The join condition as shared columns to match on.
45
+ * If specified, *condition* should be `undefined`.
46
+ * @param sample A table sample to apply to join output.
47
+ */
48
+ constructor(
49
+ left: FromNode | TableRefNode,
50
+ right: FromNode | TableRefNode,
51
+ variant: JoinVariant = 'NATURAL',
52
+ type: JoinType = 'INNER',
53
+ condition?: ExprNode,
54
+ using?: ColumnRefNode[],
55
+ sample?: SampleClauseNode
56
+ ) {
57
+ super(JOIN_CLAUSE);
58
+ this.left = left;
59
+ this.right = right;
60
+ this.joinVariant = variant;
61
+ this.joinType = type;
62
+ this.condition = condition;
63
+ this.using = using;
64
+ this.sample = sample;
65
+ }
66
+ }
package/src/ast/list.ts CHANGED
@@ -13,11 +13,4 @@ export class ListNode extends ExprNode {
13
13
  super(LIST);
14
14
  this.values = values;
15
15
  }
16
-
17
- /**
18
- * Generate a SQL query string for this node.
19
- */
20
- toString() {
21
- return `[${this.values.join(', ')}]`;
22
- }
23
16
  }
@@ -13,13 +13,6 @@ export class LiteralNode extends ExprNode {
13
13
  super(LITERAL);
14
14
  this.value = value;
15
15
  }
16
-
17
- /**
18
- * Generate a SQL query string for this node.
19
- */
20
- toString() {
21
- return literalToSQL(this.value);
22
- }
23
16
  }
24
17
 
25
18
  export function literalToSQL(value: unknown) {
@@ -17,16 +17,6 @@ export class LogicalOpNode<T extends ExprNode> extends ExprNode {
17
17
  this.op = op;
18
18
  this.clauses = clauses;
19
19
  }
20
-
21
- /**
22
- * Generate a SQL query string for this node.
23
- */
24
- toString() {
25
- const c = this.clauses;
26
- return c.length === 0 ? ''
27
- : c.length === 1 ? `${c[0]}`
28
- : `(${c.join(` ${this.op} `)})`;
29
- }
30
20
  }
31
21
 
32
22
  export class AndNode<T extends ExprNode> extends LogicalOpNode<T> {
package/src/ast/node.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import type { SQLCodeGenerator } from '../visit/codegen/sql.js';
2
+
1
3
  /**
2
4
  * Check if a value is a SQL AST node.
3
5
  * @param value The value to check.
@@ -6,6 +8,16 @@ export function isNode(value: unknown): value is SQLNode {
6
8
  return value instanceof SQLNode;
7
9
  }
8
10
 
11
+ let _defaultVisitor: SQLCodeGenerator | undefined;
12
+
13
+ /**
14
+ * Set the default visitor for toString operations.
15
+ * This is used when no visitor is explicitly provided.
16
+ */
17
+ export function setDefaultVisitor(visitor: SQLCodeGenerator) {
18
+ _defaultVisitor = visitor;
19
+ }
20
+
9
21
  export class SQLNode {
10
22
  /** The SQL AST node type. */
11
23
  readonly type: string;
@@ -23,13 +35,28 @@ export class SQLNode {
23
35
  * @returns The shallow clone node.
24
36
  */
25
37
  clone(): this {
26
- // @ts-expect-error use constructor
27
- const clone = new this.constructor();
38
+ // @ts-expect-error use constructor with type
39
+ const clone = new this.constructor(this.type);
28
40
  for (const key in this) {
29
- clone[key] = this[key];
41
+ if (key !== 'type') { // Skip type since it's already set by constructor
42
+ clone[key] = this[key];
43
+ }
30
44
  }
31
45
  return clone;
32
46
  }
47
+
48
+ /**
49
+ * Generate a SQL query string for this node using a specific dialect visitor.
50
+ * @param visitor Optional SQL visitor to use for string generation.
51
+ * If not provided, uses the default visitor.
52
+ * @returns The SQL string representation.
53
+ */
54
+ toString(visitor: SQLCodeGenerator | undefined = _defaultVisitor): string {
55
+ if (!visitor) {
56
+ throw new Error('No visitor provided and no default visitor set.');
57
+ }
58
+ return visitor.toString(this);
59
+ }
33
60
  }
34
61
 
35
62
  /**
@@ -21,18 +21,4 @@ export class OrderByNode extends ExprNode {
21
21
  this.desc = desc;
22
22
  this.nullsFirst = nullsFirst;
23
23
  }
24
-
25
- /**
26
- * Generate a SQL query string for this node.
27
- */
28
- toString() {
29
- const { expr, desc, nullsFirst } = this;
30
- const dir = desc ? ' DESC'
31
- : desc === false ? ' ASC'
32
- : '';
33
- const nf = nullsFirst ? ' NULLS FIRST'
34
- : nullsFirst === false ? ' NULLS LAST'
35
- : '';
36
- return `${expr}${dir}${nf}`;
37
- }
38
24
  }
package/src/ast/param.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import type { ParamLike } from '../types.js';
2
2
  import { PARAM } from '../constants.js';
3
- import { literalToSQL } from './literal.js';
4
3
  import { ExprNode } from './node.js';
5
4
 
6
5
  export class ParamNode extends ExprNode {
@@ -22,11 +21,4 @@ export class ParamNode extends ExprNode {
22
21
  get value() {
23
22
  return this.param.value;
24
23
  }
25
-
26
- /**
27
- * Generate a SQL query string for this node.
28
- */
29
- toString() {
30
- return literalToSQL(this.value);
31
- }
32
24
  }
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';
@@ -231,7 +231,7 @@ export class Query extends ExprNode {
231
231
 
232
232
  export class SelectQuery extends Query {
233
233
  _select: SelectClauseNode[] = [];
234
- _from: FromClauseNode[] = [];
234
+ _from: FromNode[] = [];
235
235
  _where: ExprNode[] = [];
236
236
  _sample?: SampleClauseNode;
237
237
  _groupby: ExprNode[] = [];
@@ -261,13 +261,17 @@ export class SelectQuery extends Query {
261
261
 
262
262
  // extract subqueries in FROM clause
263
263
  // unused CTEs will be ignored
264
+ // WARNING: does not recurse into join inputs!
264
265
  const queries: Query[] = [];
265
- this._from.forEach(({ expr }) => {
266
- if (isQuery(expr)) {
267
- queries.push(expr);
268
- } else if (isTableRef(expr)) {
269
- const subq = cte[expr.name];
270
- 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
+ }
271
275
  }
272
276
  });
273
277
  return queries;
@@ -330,7 +334,7 @@ export class SelectQuery extends Query {
330
334
  * @param expr Expressions to add.
331
335
  */
332
336
  from(...expr: FromExpr[]): this {
333
- const list: FromClauseNode[] = [];
337
+ const list: FromNode[] = [];
334
338
 
335
339
  const add = (v: string | string[] | SQLNode, as?: string) => {
336
340
  list.push(new FromClauseNode(maybeTableRef(v), unquote(as)));
@@ -338,7 +342,7 @@ export class SelectQuery extends Query {
338
342
 
339
343
  expr.flat().forEach(e => {
340
344
  if (e == null) return;
341
- else if (e instanceof FromClauseNode) list.push(e);
345
+ else if (e instanceof FromNode) list.push(e);
342
346
  else if (isString(e)) add(e, e);
343
347
  else if (isTableRef(e)) add(e, e.name);
344
348
  else if (isNode(e)) add(e);
@@ -450,66 +454,6 @@ export class SelectQuery extends Query {
450
454
  this._qualify = this._qualify.concat(exprList(expr, asVerbatim));
451
455
  return this;
452
456
  }
453
-
454
- /**
455
- * Generate a SQL query string.
456
- */
457
- toString() {
458
- const {
459
- _with, _select, _distinct, _from, _sample, _where, _groupby,
460
- _having, _window, _qualify, _orderby, _limitPerc, _limit, _offset
461
- } = this;
462
- const sql = [];
463
-
464
- // WITH
465
- if (_with.length) sql.push(`WITH ${_with.join(', ')}`);
466
-
467
- // SELECT
468
- sql.push(`SELECT${_distinct ? ' DISTINCT' : ''} ${_select.join(', ')}`);
469
-
470
- // FROM
471
- if (_from.length) sql.push(`FROM ${_from.join(', ')}`);
472
-
473
- // WHERE
474
- if (_where.length) {
475
- const clauses = _where.map(String).filter(x => x).join(' AND ');
476
- if (clauses) sql.push(`WHERE ${clauses}`);
477
- }
478
-
479
- // SAMPLE
480
- if (_sample) sql.push(`USING SAMPLE ${_sample}`);
481
-
482
- // GROUP BY
483
- if (_groupby.length) {
484
- sql.push(`GROUP BY ${_groupby.join(', ')}`);
485
- }
486
-
487
- // HAVING
488
- if (_having.length) {
489
- const clauses = _having.map(String).filter(x => x).join(' AND ');
490
- if (clauses) sql.push(`HAVING ${clauses}`);
491
- }
492
-
493
- // WINDOW
494
- if (_window.length) sql.push(`WINDOW ${_window.join(', ')}`);
495
-
496
- // QUALIFY
497
- if (_qualify.length) {
498
- const clauses = _qualify.map(String).filter(x => x).join(' AND ');
499
- if (clauses) sql.push(`QUALIFY ${clauses}`);
500
- }
501
-
502
- // ORDER BY
503
- if (_orderby.length) sql.push(`ORDER BY ${_orderby.join(', ')}`);
504
-
505
- // LIMIT
506
- if (_limit) sql.push(`LIMIT ${_limit}${_limitPerc ? '%' : ''}`);
507
-
508
- // OFFSET
509
- if (_offset) sql.push(`OFFSET ${_offset}`);
510
-
511
- return sql.join(' ');
512
- }
513
457
  }
514
458
 
515
459
  export class DescribeQuery extends SQLNode {
@@ -531,13 +475,6 @@ export class DescribeQuery extends SQLNode {
531
475
  // @ts-expect-error creates describe query
532
476
  return new DescribeQuery(this.query.clone());
533
477
  }
534
-
535
- /**
536
- * Generate a SQL query string.
537
- */
538
- toString() {
539
- return `DESCRIBE ${this.query}`;
540
- }
541
478
  }
542
479
 
543
480
  export class SetOperation extends Query {
@@ -582,31 +519,6 @@ export class SetOperation extends Query {
582
519
  // @ts-expect-error creates set operation
583
520
  return Object.assign(new SetOperation(op, queries), rest);
584
521
  }
585
-
586
- /**
587
- * Generate a SQL query string.
588
- */
589
- toString() {
590
- const { op, queries, _with, _orderby, _limitPerc, _limit, _offset } = this;
591
- const sql = [];
592
-
593
- // WITH
594
- if (_with.length) sql.push(`WITH ${_with.join(', ')}`);
595
-
596
- // SUBQUERIES
597
- sql.push(queries.join(` ${op} `));
598
-
599
- // ORDER BY
600
- if (_orderby.length) sql.push(`ORDER BY ${_orderby.join(', ')}`);
601
-
602
- // LIMIT
603
- if (_limit) sql.push(`LIMIT ${_limit}${_limitPerc ? '%' : ''}`);
604
-
605
- // OFFSET
606
- if (_offset) sql.push(`OFFSET ${_offset}`);
607
-
608
- return sql.join(' ');
609
- }
610
522
  }
611
523
 
612
524
  class WithClause {
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
  }
package/src/ast/unnest.ts CHANGED
@@ -19,13 +19,4 @@ export class UnnestNode extends ExprNode {
19
19
  this.recursive = recursive;
20
20
  this.maxDepth = maxDepth;
21
21
  }
22
-
23
- /**
24
- * Generate a SQL query string for this node.
25
- */
26
- toString() {
27
- const recursive = this.recursive ? ', recursive := true' : '';
28
- const maxDepth = this.maxDepth > 0 ? `, max_depth := ${this.maxDepth}` : '';
29
- return `UNNEST(${this.expr}${recursive}${maxDepth})`;
30
- }
31
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
  }