@uwdata/mosaic-sql 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.
Files changed (143) hide show
  1. package/README.md +2 -0
  2. package/dist/mosaic-sql.js +2242 -1064
  3. package/dist/mosaic-sql.min.js +1 -1
  4. package/dist/types/ast/aggregate.d.ts +70 -0
  5. package/dist/types/ast/between-op.d.ts +46 -0
  6. package/dist/types/ast/binary-op.d.ts +28 -0
  7. package/dist/types/ast/case.d.ts +68 -0
  8. package/dist/types/ast/cast.d.ts +21 -0
  9. package/dist/types/ast/column-param.d.ts +17 -0
  10. package/dist/types/ast/column-ref.d.ts +39 -0
  11. package/dist/types/ast/fragment.d.ts +14 -0
  12. package/dist/types/ast/from.d.ts +21 -0
  13. package/dist/types/ast/function.d.ts +21 -0
  14. package/dist/types/ast/in-op.d.ts +21 -0
  15. package/dist/types/ast/interval.d.ts +21 -0
  16. package/dist/types/ast/literal.d.ts +15 -0
  17. package/dist/types/ast/logical-op.d.ts +46 -0
  18. package/dist/types/ast/node.d.ts +24 -0
  19. package/dist/types/ast/order-by.d.ts +29 -0
  20. package/dist/types/ast/param.d.ts +19 -0
  21. package/dist/types/ast/query.d.ts +268 -0
  22. package/dist/types/ast/sample.d.ts +42 -0
  23. package/dist/types/ast/select.d.ts +22 -0
  24. package/dist/types/ast/table-ref.d.ts +25 -0
  25. package/dist/types/ast/unary-op.d.ts +39 -0
  26. package/dist/types/ast/verbatim.d.ts +9 -0
  27. package/dist/types/ast/window.d.ts +177 -0
  28. package/dist/types/ast/with.d.ts +22 -0
  29. package/dist/types/constants.d.ts +38 -0
  30. package/dist/types/functions/aggregate.d.ts +229 -0
  31. package/dist/types/functions/case.d.ts +15 -0
  32. package/dist/types/functions/cast.d.ts +26 -0
  33. package/dist/types/functions/column.d.ts +9 -0
  34. package/dist/types/functions/datetime.d.ts +44 -0
  35. package/dist/types/functions/literal.d.ts +16 -0
  36. package/dist/types/functions/numeric.d.ts +93 -0
  37. package/dist/types/functions/operators.d.ts +198 -0
  38. package/dist/types/functions/order-by.d.ts +17 -0
  39. package/dist/types/functions/spatial.d.ts +37 -0
  40. package/dist/types/functions/sql-template-tag.d.ts +16 -0
  41. package/dist/types/functions/string.d.ts +55 -0
  42. package/dist/types/functions/table-ref.d.ts +9 -0
  43. package/dist/types/functions/window.d.ts +87 -0
  44. package/dist/types/index-types.d.ts +2 -0
  45. package/dist/types/index.d.ts +53 -0
  46. package/dist/types/load/create.d.ts +8 -0
  47. package/dist/types/load/extension.d.ts +1 -0
  48. package/dist/types/load/load.d.ts +12 -0
  49. package/dist/types/load/sql-from.d.ts +11 -0
  50. package/dist/types/transforms/bin-1d.d.ts +14 -0
  51. package/dist/types/transforms/bin-2d.d.ts +18 -0
  52. package/dist/types/transforms/bin-linear-1d.d.ts +9 -0
  53. package/dist/types/transforms/bin-linear-2d.d.ts +18 -0
  54. package/dist/types/transforms/line-density.d.ts +23 -0
  55. package/dist/types/transforms/m4.d.ts +18 -0
  56. package/dist/types/transforms/scales.d.ts +1 -0
  57. package/dist/types/types.d.ts +59 -0
  58. package/dist/types/util/ast.d.ts +60 -0
  59. package/dist/types/util/function.d.ts +54 -0
  60. package/dist/types/util/string.d.ts +3 -0
  61. package/dist/types/util/type-check.d.ts +18 -0
  62. package/dist/types/visit/recurse.d.ts +28 -0
  63. package/dist/types/visit/rewrite.d.ts +10 -0
  64. package/dist/types/visit/visitors.d.ts +33 -0
  65. package/dist/types/visit/walk.d.ts +7 -0
  66. package/jsconfig.json +11 -0
  67. package/package.json +6 -4
  68. package/src/ast/aggregate.js +164 -0
  69. package/src/ast/between-op.js +75 -0
  70. package/src/ast/binary-op.js +40 -0
  71. package/src/ast/case.js +105 -0
  72. package/src/ast/cast.js +34 -0
  73. package/src/ast/column-param.js +29 -0
  74. package/src/ast/column-ref.js +72 -0
  75. package/src/ast/fragment.js +26 -0
  76. package/src/ast/from.js +40 -0
  77. package/src/ast/function.js +34 -0
  78. package/src/ast/in-op.js +33 -0
  79. package/src/ast/interval.js +33 -0
  80. package/src/ast/literal.js +55 -0
  81. package/src/ast/logical-op.js +67 -0
  82. package/src/ast/node.js +29 -0
  83. package/src/ast/order-by.js +48 -0
  84. package/src/ast/param.js +35 -0
  85. package/src/ast/query.js +578 -0
  86. package/src/ast/sample.js +53 -0
  87. package/src/ast/select.js +44 -0
  88. package/src/ast/table-ref.js +44 -0
  89. package/src/ast/unary-op.js +64 -0
  90. package/src/ast/verbatim.js +26 -0
  91. package/src/ast/window.js +290 -0
  92. package/src/ast/with.js +30 -0
  93. package/src/constants.js +44 -0
  94. package/src/functions/aggregate.js +335 -0
  95. package/src/functions/case.js +21 -0
  96. package/src/functions/cast.js +39 -0
  97. package/src/functions/column.js +20 -0
  98. package/src/functions/datetime.js +65 -0
  99. package/src/functions/literal.js +22 -0
  100. package/src/functions/numeric.js +139 -0
  101. package/src/functions/operators.js +298 -0
  102. package/src/functions/order-by.js +24 -0
  103. package/src/functions/spatial.js +56 -0
  104. package/src/functions/sql-template-tag.js +51 -0
  105. package/src/functions/string.js +82 -0
  106. package/src/functions/table-ref.js +14 -0
  107. package/src/functions/window.js +121 -0
  108. package/src/index-types.ts +2 -0
  109. package/src/index.js +57 -155
  110. package/src/load/create.js +10 -2
  111. package/src/load/load.js +4 -4
  112. package/src/load/sql-from.js +7 -6
  113. package/src/transforms/bin-1d.js +21 -0
  114. package/src/transforms/bin-2d.js +29 -0
  115. package/src/transforms/bin-linear-1d.js +26 -0
  116. package/src/transforms/bin-linear-2d.js +71 -0
  117. package/src/transforms/line-density.js +113 -0
  118. package/src/transforms/m4.js +38 -0
  119. package/src/{scales.js → transforms/scales.js} +31 -17
  120. package/src/types.ts +96 -0
  121. package/src/util/ast.js +96 -0
  122. package/src/util/function.js +78 -0
  123. package/src/util/string.js +16 -0
  124. package/src/util/type-check.js +29 -0
  125. package/src/visit/recurse.js +57 -0
  126. package/src/visit/rewrite.js +32 -0
  127. package/src/visit/visitors.js +108 -0
  128. package/src/visit/walk.js +30 -0
  129. package/tsconfig.json +12 -0
  130. package/src/Query.js +0 -593
  131. package/src/aggregates.js +0 -185
  132. package/src/cast.js +0 -19
  133. package/src/datetime.js +0 -31
  134. package/src/desc.js +0 -13
  135. package/src/expression.js +0 -170
  136. package/src/functions.js +0 -25
  137. package/src/literal.js +0 -6
  138. package/src/operators.js +0 -54
  139. package/src/ref.js +0 -109
  140. package/src/repeat.js +0 -3
  141. package/src/spatial.js +0 -10
  142. package/src/to-sql.js +0 -52
  143. package/src/windows.js +0 -239
@@ -0,0 +1,28 @@
1
+ export namespace recurse {
2
+ let AGGREGATE: string[];
3
+ let BETWEEN: string[];
4
+ let BINARY: string[];
5
+ let CASE: string[];
6
+ let CAST: string[];
7
+ let COLUMN_PARAM: string[];
8
+ let COLUMN_REF: string[];
9
+ let DESCRIBE_QUERY: string[];
10
+ let EXPRESSION: string[];
11
+ let FRAGMENT: string[];
12
+ let FROM_CLAUSE: string[];
13
+ let FUNCTION: string[];
14
+ let IN: string[];
15
+ let LOGICAL_OPERATOR: string[];
16
+ let NOT_BETWEEN: string[];
17
+ let ORDER_BY: string[];
18
+ let PARAM: string[];
19
+ let SELECT_CLAUSE: string[];
20
+ let SELECT_QUERY: string[];
21
+ let SET_OPERATION: string[];
22
+ let UNARY: string[];
23
+ let WHEN: string[];
24
+ let WINDOW: string[];
25
+ let WINDOW_CLAUSE: string[];
26
+ let WINDOW_DEF: string[];
27
+ let WINDOW_FRAME: string[];
28
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Rewrite a SQL expression, based on a map of nodes to replace.
3
+ * This method updates the expression in place.
4
+ * @param {ExprNode} node The root AST node of the expression.
5
+ * @param {Map<ExprNode, ExprNode>} map The rewrite map.
6
+ * When encountered, key nodes are replaced by value nodes.
7
+ * @returns {ExprNode}
8
+ */
9
+ export function rewrite(node: ExprNode, map: Map<ExprNode, ExprNode>): ExprNode;
10
+ import { ExprNode } from '../ast/node.js';
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Indicate if the input AST contains an aggregate expression.
3
+ * The string content of verbatim nodes is analyzed to try to identify
4
+ * unparsed aggregate functions calls within SQL strings.
5
+ * @param {SQLNode} root The root of the AST to search.
6
+ * @returns {number} Return 0 if no aggregate functions are found.
7
+ * Sets bit 1 if an AggregateFunction instance is found.
8
+ * Sets bit 2 if an aggregate embedded in verbatim text is found.
9
+ */
10
+ export function isAggregateExpression(root: SQLNode): number;
11
+ /**
12
+ * Collect all aggregate function nodes.
13
+ * @param {SQLNode} root The root of the AST to search.
14
+ * @returns {AggregateNode[]}
15
+ */
16
+ export function collectAggregates(root: SQLNode): AggregateNode[];
17
+ /**
18
+ * Collect all unique column references.
19
+ * Multiple references to the same column are de-duplicated, even if
20
+ * they are not object-equal node instances.
21
+ * @param {SQLNode} root The root of the AST to search.
22
+ * @returns {ColumnRefNode[]}
23
+ */
24
+ export function collectColumns(root: SQLNode): ColumnRefNode[];
25
+ /**
26
+ * Collect all unique dynamic parameter instances.
27
+ * @param {SQLNode} root The root of the AST to search.
28
+ * @returns {import('../types.js').ParamLike[]}
29
+ */
30
+ export function collectParams(root: SQLNode): import("../types.js").ParamLike[];
31
+ import { SQLNode } from '../ast/node.js';
32
+ import { AggregateNode } from '../ast/aggregate.js';
33
+ import { ColumnRefNode } from '../ast/column-ref.js';
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Perform a traversal of a SQL expression AST.
3
+ * @param {import('../ast/node.js').SQLNode} node Root node for AST traversal.
4
+ * @param {import('../types.js').VisitorCallback} visit Visitor callback function.
5
+ * @return {import('../types.js').VisitorResult}
6
+ */
7
+ export function walk(node: import("../ast/node.js").SQLNode, visit: import("../types.js").VisitorCallback): import("../types.js").VisitorResult;
package/jsconfig.json ADDED
@@ -0,0 +1,11 @@
1
+ {
2
+ "include": ["src/**/*"],
3
+ "compilerOptions": {
4
+ "checkJs": true,
5
+ "noEmit": true,
6
+ "noImplicitAny": false,
7
+ "module": "node16",
8
+ "skipLibCheck": true,
9
+ "types": []
10
+ }
11
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uwdata/mosaic-sql",
3
- "version": "0.11.0",
3
+ "version": "0.12.1",
4
4
  "description": "SQL query construction and analysis.",
5
5
  "keywords": [
6
6
  "sql",
@@ -14,16 +14,18 @@
14
14
  "module": "src/index.js",
15
15
  "jsdelivr": "dist/mosaic-sql.min.js",
16
16
  "unpkg": "dist/mosaic-sql.min.js",
17
+ "types": "dist/types/index-types.d.ts",
17
18
  "repository": {
18
19
  "type": "git",
19
20
  "url": "https://github.com/uwdata/mosaic.git"
20
21
  },
21
22
  "scripts": {
22
23
  "prebuild": "rimraf dist && mkdir dist",
23
- "build": "node ../../esbuild.js mosaic-sql",
24
+ "build": "npm run types && node ../../esbuild.js mosaic-sql",
25
+ "types": "tsc",
24
26
  "lint": "eslint src test",
25
- "test": "vitest run",
27
+ "test": "vitest run && tsc -p jsconfig.json",
26
28
  "prepublishOnly": "npm run test && npm run lint && npm run build"
27
29
  },
28
- "gitHead": "861d616f39926a1d2aee83b59dbdd70b0b3caf12"
30
+ "gitHead": "fe3a7c34352da54ec36a1ebf557846f46a649782"
29
31
  }
@@ -0,0 +1,164 @@
1
+ import { AGGREGATE } from '../constants.js';
2
+ import { asVerbatim } from '../util/ast.js';
3
+ import { isString } from '../util/type-check.js';
4
+ import { ExprNode } from './node.js';
5
+ import { WindowNode } from './window.js';
6
+
7
+ export class AggregateNode extends ExprNode {
8
+ /**
9
+ * Instantiate an aggregate function node.
10
+ * @param {string} name The aggregate function name.
11
+ * @param {ExprNode[]} args The aggregate function arguments.
12
+ * @param {boolean} [distinct] The distinct flag.
13
+ * @param {ExprNode} [filter] Filter expression.
14
+ */
15
+ constructor(name, args, distinct, filter) {
16
+ super(AGGREGATE);
17
+ /**
18
+ * The aggregate function name.
19
+ * @type {string}
20
+ * @readonly
21
+ */
22
+ this.name = name;
23
+ /**
24
+ * The aggregate function arguments.
25
+ * @type {ExprNode[]}
26
+ * @readonly
27
+ */
28
+ this.args = args;
29
+ /**
30
+ * The distinct flag.
31
+ * @type {boolean}
32
+ * @readonly
33
+ */
34
+ this.isDistinct = distinct;
35
+ /**
36
+ * Filter criteria.
37
+ * @type {ExprNode}
38
+ * @readonly
39
+ */
40
+ this.filter = filter;
41
+ }
42
+
43
+ /**
44
+ * Return a new derived aggregate over distinct values.
45
+ * @param {boolean} [isDistinct=true] The distinct flag.
46
+ * @returns {AggregateNode} A new aggregate node.
47
+ */
48
+ distinct(isDistinct = true) {
49
+ return new AggregateNode(this.name, this.args, isDistinct, this.filter);
50
+ }
51
+
52
+ /**
53
+ * Return a new derived aggregate function that filters values.
54
+ * @param {ExprNode | string} filter The filter expression.
55
+ * @returns {AggregateNode} A new aggregate node.
56
+ */
57
+ where(filter) {
58
+ if (isString(filter)) filter = asVerbatim(filter);
59
+ return new AggregateNode(this.name, this.args, this.isDistinct, filter);
60
+ }
61
+
62
+ /**
63
+ * Return a new window function over this aggregate.
64
+ * @returns {WindowNode} A new window node.
65
+ */
66
+ window() {
67
+ return new WindowNode(this);
68
+ }
69
+
70
+ /**
71
+ * Return a new window function over this aggregate with the given partitions.
72
+ * @param {...import('../types.js').ExprVarArgs} expr The partition by criteria.
73
+ * @returns {WindowNode} A new window node.
74
+ */
75
+ partitionby(...expr) {
76
+ return this.window().partitionby(...expr);
77
+ }
78
+
79
+ /**
80
+ * Return a new window function over this aggregate with the given ordering.
81
+ * @param {...import('../types.js').ExprVarArgs} expr The order by criteria.
82
+ * @returns {WindowNode} A new window node.
83
+ */
84
+ orderby(...expr) {
85
+ return this.window().orderby(...expr);
86
+ }
87
+
88
+ /**
89
+ * Generate a SQL query string for this node.
90
+ * @returns {string}
91
+ */
92
+ toString() {
93
+ const { name, args, isDistinct, filter } = this;
94
+ const dist = isDistinct ? 'DISTINCT ' : '';
95
+ const arg = args?.length ? args.join(', ') : '*';
96
+ const filt = filter ? ` FILTER (WHERE ${filter})` : '';
97
+ return `${name}(${dist}${arg})${filt}`;
98
+ }
99
+ }
100
+
101
+ /**
102
+ * An array of known aggregate function names.
103
+ * From https://duckdb.org/docs/sql/functions/aggregates.html.
104
+ */
105
+ export const aggregateNames = [
106
+ 'any_value',
107
+ 'approx_count_distinct',
108
+ 'approx_quantile',
109
+ 'arbitrary',
110
+ 'arg_max',
111
+ 'arg_max_null',
112
+ 'arg_min',
113
+ 'arg_min_null',
114
+ 'array_agg',
115
+ 'avg',
116
+ 'bit_and',
117
+ 'bit_or',
118
+ 'bit_xor',
119
+ 'bitstring_agg',
120
+ 'bool_and',
121
+ 'bool_or',
122
+ 'corr',
123
+ 'count',
124
+ 'covar_pop',
125
+ 'covar_samp',
126
+ 'entropy',
127
+ 'favg',
128
+ 'first',
129
+ 'fsum',
130
+ 'geomean',
131
+ 'kurtosis_pop',
132
+ 'kurtosis',
133
+ 'last',
134
+ 'mad',
135
+ 'max',
136
+ 'max_by',
137
+ 'median',
138
+ 'min',
139
+ 'min_by',
140
+ 'mode',
141
+ 'product',
142
+ 'quantile',
143
+ 'quantile_cont',
144
+ 'quantile_disc',
145
+ 'regr_avgx',
146
+ 'regr_avgy',
147
+ 'regr_count',
148
+ 'regr_intercept',
149
+ 'regr_r2',
150
+ 'regr_sxx',
151
+ 'regr_sxy',
152
+ 'regr_syy',
153
+ 'regr_slope',
154
+ 'reservoir_quantile',
155
+ 'skewness',
156
+ 'stddev',
157
+ 'stddev_pop',
158
+ 'stddev_samp',
159
+ 'string_agg',
160
+ 'sum',
161
+ 'variance',
162
+ 'var_pop',
163
+ 'var_samp'
164
+ ];
@@ -0,0 +1,75 @@
1
+ import { BETWEEN_OPERATOR, NOT_BETWEEN_OPERATOR } from '../constants.js';
2
+ import { ExprNode } from './node.js';
3
+
4
+ class AbstractBetweenOpNode extends ExprNode {
5
+ /**
6
+ * Instantiate an abstract between operator node.
7
+ * @param {string} type The node type.
8
+ * @param {ExprNode} expr The input expression.
9
+ * @param {[ExprNode, ExprNode]} extent The range extent.
10
+ */
11
+ constructor(type, expr, extent) {
12
+ super(type);
13
+ /**
14
+ * The input expression.
15
+ * @type {ExprNode}
16
+ * @readonly
17
+ */
18
+ this.expr = expr;
19
+ /**
20
+ * The range extent.
21
+ * @type {[ExprNode, ExprNode]}
22
+ * @readonly
23
+ */
24
+ this.extent = extent;
25
+ }
26
+
27
+ /**
28
+ * Generate a SQL query string for this node.
29
+ * @returns {string}
30
+ */
31
+ toSQL(op) {
32
+ const { extent: r, expr } = this;
33
+ return r ? `(${expr} ${op} ${r[0]} AND ${r[1]})` : '';
34
+ }
35
+ }
36
+
37
+ export class BetweenOpNode extends AbstractBetweenOpNode {
38
+ /**
39
+ * Instantiate a between operator node.
40
+ * @param {ExprNode} expr The input expression.
41
+ * @param {[ExprNode, ExprNode]} extent
42
+ * The range extent.
43
+ */
44
+ constructor(expr, extent) {
45
+ super(BETWEEN_OPERATOR, expr, extent);
46
+ }
47
+
48
+ /**
49
+ * Generate a SQL query string for this node.
50
+ * @returns {string}
51
+ */
52
+ toString() {
53
+ return super.toSQL('BETWEEN');
54
+ }
55
+ }
56
+
57
+ export class NotBetweenOpNode extends AbstractBetweenOpNode {
58
+ /**
59
+ * Instantiate a not between operator node.
60
+ * @param {ExprNode} expr The input expression.
61
+ * @param {[ExprNode, ExprNode]} extent
62
+ * The range extent.
63
+ */
64
+ constructor(expr, extent) {
65
+ super(NOT_BETWEEN_OPERATOR, expr, extent);
66
+ }
67
+
68
+ /**
69
+ * Generate a SQL query string for this node.
70
+ * @returns {string}
71
+ */
72
+ toString() {
73
+ return super.toSQL('NOT BETWEEN');
74
+ }
75
+ }
@@ -0,0 +1,40 @@
1
+ import { BINARY_OPERATOR } from '../constants.js';
2
+ import { ExprNode } from './node.js';
3
+
4
+ export class BinaryOpNode extends ExprNode {
5
+ /**
6
+ * Instantiate a binary operator node.
7
+ * @param {string} op The operator type.
8
+ * @param {ExprNode} left The left input expression.
9
+ * @param {ExprNode} right The right input expression.
10
+ */
11
+ constructor(op, left, right) {
12
+ super(BINARY_OPERATOR);
13
+ /**
14
+ * The operator type.
15
+ * @type {string}
16
+ * @readonly
17
+ */
18
+ this.op = op;
19
+ /**
20
+ * The left input expression.
21
+ * @type {ExprNode}
22
+ * @readonly
23
+ */
24
+ this.left = left;
25
+ /**
26
+ * The right input expression.
27
+ * @type {ExprNode}
28
+ * @readonly
29
+ */
30
+ this.right = right;
31
+ }
32
+
33
+ /**
34
+ * Generate a SQL query string for this node.
35
+ * @returns {string}
36
+ */
37
+ toString() {
38
+ return `(${this.left} ${this.op} ${this.right})`;
39
+ }
40
+ }
@@ -0,0 +1,105 @@
1
+ import { CASE, WHEN } from '../constants.js';
2
+ import { asNode } from '../util/ast.js';
3
+ import { ExprNode, SQLNode } from './node.js';
4
+
5
+ export class CaseNode extends ExprNode {
6
+ /**
7
+ * Instantiate a case node.
8
+ * @param {ExprNode} [expr] An optional base expression, that comes
9
+ * immediately after the CASE keyword. If specified, this case statement
10
+ * acts like a switch statement, with WHEN expressions as values to
11
+ * match against the switch value rather than boolean conditions.
12
+ * @param {WhenNode[]} [when] An array of WHEN/THEN expression nodes.
13
+ * @param {ExprNode} [elseExpr] An ELSE expression.
14
+ */
15
+ constructor(expr = undefined, when = [], elseExpr = undefined) {
16
+ super(CASE);
17
+ /**
18
+ * The optional base expression.
19
+ * @type {ExprNode}
20
+ * @readonly
21
+ */
22
+ this.expr = expr;
23
+ /**
24
+ * An array of WHEN/THEN expression nodes.
25
+ * @type {WhenNode[]}
26
+ * @readonly
27
+ */
28
+ this._when = when;
29
+ /**
30
+ * An ELSE expression.
31
+ * @type {ExprNode}
32
+ * @readonly
33
+ */
34
+ this._else = elseExpr;
35
+ }
36
+
37
+ /**
38
+ * Return a new case node with the given conditional added as
39
+ * the last WHEN / THEN pair.
40
+ * @param {import('../types.js').ExprValue} cond
41
+ * The WHEN condition expression.
42
+ * @param {import('../types.js').ExprValue} value
43
+ * The THEN value expression.
44
+ * @returns {CaseNode}
45
+ */
46
+ when(cond, value) {
47
+ return new CaseNode(
48
+ this.expr,
49
+ this._when.concat(new WhenNode(asNode(cond), asNode(value))),
50
+ this._else
51
+ );
52
+ }
53
+
54
+ /**
55
+ * Return a new case node with the given ELSE expression.
56
+ * @param {import('../types.js').ExprValue} expr The ELSE expression.
57
+ * @returns {CaseNode}
58
+ */
59
+ else(expr) {
60
+ return new CaseNode(this.expr, this._when, asNode(expr));
61
+ }
62
+
63
+ /**
64
+ * Generate a SQL query string for this node.
65
+ * @returns {string}
66
+ */
67
+ toString() {
68
+ return 'CASE '
69
+ + (this.expr ? `${this.expr} ` : '')
70
+ + this._when.join(' ')
71
+ + (this._else ? ` ELSE ${this._else}` : '')
72
+ + ' END';
73
+ }
74
+ }
75
+
76
+ export class WhenNode extends SQLNode {
77
+ /**
78
+ * Instantiate a case node.
79
+ * @param {ExprNode} when The WHEN condition expression.
80
+ * @param {ExprNode} then The THEN value expression.
81
+ */
82
+ constructor(when, then) {
83
+ super(WHEN);
84
+ /**
85
+ * The condition expression.
86
+ * @type {ExprNode}
87
+ * @readonly
88
+ */
89
+ this.when = when;
90
+ /**
91
+ * The value expression.
92
+ * @type {ExprNode}
93
+ * @readonly
94
+ */
95
+ this.then = then;
96
+ }
97
+
98
+ /**
99
+ * Generate a SQL query string for this node.
100
+ * @returns {string}
101
+ */
102
+ toString() {
103
+ return `WHEN ${this.when} THEN ${this.then}`;
104
+ }
105
+ }
@@ -0,0 +1,34 @@
1
+ import { CAST } from '../constants.js';
2
+ import { ExprNode } from './node.js';
3
+
4
+ export class CastNode extends ExprNode {
5
+ /**
6
+ * Instantiate a cast node.
7
+ * @param {ExprNode} expr The expression to type cast.
8
+ * @param {string} type The type to cast to.
9
+ */
10
+ constructor(expr, type) {
11
+ super(CAST);
12
+ /**
13
+ * The expression to type cast.
14
+ * @type {ExprNode}
15
+ * @readonly
16
+ */
17
+ this.expr = expr;
18
+ /**
19
+ * The type to cast to.
20
+ * @type {string}
21
+ * @readonly
22
+ */
23
+ this.cast = type;
24
+ }
25
+
26
+ /**
27
+ * Generate a SQL query string for this node.
28
+ * @returns {string}
29
+ */
30
+ toString() {
31
+ // TODO? could include check to see if parens are necessary
32
+ return `(${this.expr})::${this.cast}`;
33
+ }
34
+ }
@@ -0,0 +1,29 @@
1
+ import { COLUMN_PARAM } from '../constants.js';
2
+ import { ColumnRefNode } from './column-ref.js';
3
+
4
+ export class ColumnParamNode extends ColumnRefNode {
5
+ /**
6
+ * Instantiate a column param node.
7
+ * @param {import('./param.js').ParamNode} param The column name as a
8
+ * parameter node.
9
+ * @param {import('./table-ref.js').TableRefNode} [table] The table
10
+ * reference.
11
+ */
12
+ constructor(param, table) {
13
+ super(COLUMN_PARAM, table);
14
+ /**
15
+ * The column name as a parameter node.
16
+ * @type {import('./param.js').ParamNode}
17
+ * @readonly
18
+ */
19
+ this.param = param;
20
+ }
21
+
22
+ /**
23
+ * Returns the column name.
24
+ * @returns {string}
25
+ */
26
+ get column() {
27
+ return `${this.param.value}`;
28
+ }
29
+ }
@@ -0,0 +1,72 @@
1
+ import { COLUMN_REF } from '../constants.js';
2
+ import { quoteIdentifier } from '../util/string.js';
3
+ import { ExprNode } from './node.js';
4
+
5
+ /**
6
+ * Check if a value is a column reference node.
7
+ * @param {*} value The value to check.
8
+ * @returns {value is ColumnRefNode}
9
+ */
10
+ export function isColumnRef(value) {
11
+ return value instanceof ColumnRefNode;
12
+ }
13
+
14
+ export class ColumnRefNode extends ExprNode {
15
+ /**
16
+ * Instantiate a column reference node.
17
+ * @param {import('./table-ref.js').TableRefNode} [table] The table reference.
18
+ */
19
+ constructor(type, table) {
20
+ super(type);
21
+ /**
22
+ * The table reference.
23
+ * @type {import('./table-ref.js').TableRefNode}
24
+ * @readonly
25
+ */
26
+ this.table = table;
27
+ }
28
+
29
+ /**
30
+ * Returns the column name.
31
+ * @returns {string}
32
+ */
33
+ get column() {
34
+ return null; // subclasses to override
35
+ }
36
+
37
+ /**
38
+ * Generate a SQL query string for this node.
39
+ * @returns {string}
40
+ */
41
+ toString() {
42
+ const { column, table } = this;
43
+ const tref = `${table ?? ''}`;
44
+ const id = column === '*' ? '*' : quoteIdentifier(column);
45
+ return (tref ? (tref + '.') : '') + id;
46
+ }
47
+ }
48
+
49
+ export class ColumnNameRefNode extends ColumnRefNode {
50
+ /**
51
+ * Instantiate a column reference node.
52
+ * @param {string} name The column name.
53
+ * @param {import('./table-ref.js').TableRefNode} [table] The table reference.
54
+ */
55
+ constructor(name, table) {
56
+ super(COLUMN_REF, table);
57
+ /**
58
+ * The column name.
59
+ * @type {string}
60
+ * @readonly
61
+ */
62
+ this.name = name;
63
+ }
64
+
65
+ /**
66
+ * Returns the column name.
67
+ * @returns {string}
68
+ */
69
+ get column() {
70
+ return this.name;
71
+ }
72
+ }
@@ -0,0 +1,26 @@
1
+ import { FRAGMENT } from '../constants.js';
2
+ import { ExprNode } from './node.js';
3
+
4
+ export class FragmentNode extends ExprNode {
5
+ /**
6
+ * Instantiate a fragment node with arbitrary content.
7
+ * @param {ExprNode[]} spans The consecutive parts making up the fragment.
8
+ */
9
+ constructor(spans) {
10
+ super(FRAGMENT);
11
+ /**
12
+ * The consecutive parts making up the fragment.
13
+ * @type {ExprNode[]}
14
+ * @readonly
15
+ */
16
+ this.spans = spans;
17
+ }
18
+
19
+ /**
20
+ * Generate a SQL query string for this node.
21
+ * @returns {string}
22
+ */
23
+ toString() {
24
+ return this.spans.join('');
25
+ }
26
+ }