@uwdata/mosaic-sql 0.16.2 → 0.17.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 (97) hide show
  1. package/package.json +5 -9
  2. package/src/ast/aggregate.js +50 -8
  3. package/src/ast/collate.js +33 -0
  4. package/src/ast/from.js +13 -4
  5. package/src/ast/node.js +13 -0
  6. package/src/ast/query.js +54 -22
  7. package/src/ast/sample.js +3 -3
  8. package/src/ast/subquery.js +23 -0
  9. package/src/ast/verbatim.js +8 -1
  10. package/src/ast/window-frame.js +107 -0
  11. package/src/ast/window.js +65 -99
  12. package/src/constants.js +5 -6
  13. package/src/functions/collate.js +16 -0
  14. package/src/functions/datetime.js +1 -11
  15. package/src/functions/interval.js +83 -0
  16. package/src/functions/literal.js +3 -2
  17. package/src/functions/window-frame.js +61 -0
  18. package/src/index.js +12 -4
  19. package/src/load/load.js +1 -1
  20. package/src/transforms/bin-date.js +2 -1
  21. package/src/transforms/filter-query.js +44 -0
  22. package/src/types.ts +9 -0
  23. package/src/visit/clone.js +53 -0
  24. package/src/visit/recurse.js +17 -5
  25. package/src/visit/rewrite.js +3 -11
  26. package/src/visit/walk.js +0 -1
  27. package/tsconfig.json +3 -7
  28. package/LICENSE +0 -47
  29. package/dist/types/ast/aggregate.d.ts +0 -71
  30. package/dist/types/ast/between-op.d.ts +0 -46
  31. package/dist/types/ast/binary-op.d.ts +0 -28
  32. package/dist/types/ast/case.d.ts +0 -67
  33. package/dist/types/ast/cast.d.ts +0 -21
  34. package/dist/types/ast/column-param.d.ts +0 -23
  35. package/dist/types/ast/column-ref.d.ts +0 -40
  36. package/dist/types/ast/fragment.d.ts +0 -14
  37. package/dist/types/ast/from.d.ts +0 -21
  38. package/dist/types/ast/function.d.ts +0 -21
  39. package/dist/types/ast/in-op.d.ts +0 -21
  40. package/dist/types/ast/interval.d.ts +0 -21
  41. package/dist/types/ast/literal.d.ts +0 -15
  42. package/dist/types/ast/logical-op.d.ts +0 -46
  43. package/dist/types/ast/node.d.ts +0 -24
  44. package/dist/types/ast/order-by.d.ts +0 -29
  45. package/dist/types/ast/param.d.ts +0 -20
  46. package/dist/types/ast/query.d.ts +0 -320
  47. package/dist/types/ast/sample.d.ts +0 -42
  48. package/dist/types/ast/select.d.ts +0 -22
  49. package/dist/types/ast/table-ref.d.ts +0 -25
  50. package/dist/types/ast/unary-op.d.ts +0 -39
  51. package/dist/types/ast/verbatim.d.ts +0 -9
  52. package/dist/types/ast/window.d.ts +0 -180
  53. package/dist/types/ast/with.d.ts +0 -32
  54. package/dist/types/constants.d.ts +0 -38
  55. package/dist/types/functions/aggregate.d.ts +0 -236
  56. package/dist/types/functions/case.d.ts +0 -13
  57. package/dist/types/functions/cast.d.ts +0 -26
  58. package/dist/types/functions/column.d.ts +0 -11
  59. package/dist/types/functions/cte.d.ts +0 -13
  60. package/dist/types/functions/datetime.d.ts +0 -45
  61. package/dist/types/functions/literal.d.ts +0 -16
  62. package/dist/types/functions/numeric.d.ts +0 -95
  63. package/dist/types/functions/operators.d.ts +0 -200
  64. package/dist/types/functions/order-by.d.ts +0 -18
  65. package/dist/types/functions/spatial.d.ts +0 -38
  66. package/dist/types/functions/sql-template-tag.d.ts +0 -15
  67. package/dist/types/functions/string.d.ts +0 -57
  68. package/dist/types/functions/table-ref.d.ts +0 -9
  69. package/dist/types/functions/util.d.ts +0 -8
  70. package/dist/types/functions/window.d.ts +0 -89
  71. package/dist/types/index-types.d.ts +0 -2
  72. package/dist/types/index.d.ts +0 -59
  73. package/dist/types/load/create.d.ts +0 -8
  74. package/dist/types/load/extension.d.ts +0 -1
  75. package/dist/types/load/load.d.ts +0 -12
  76. package/dist/types/load/sql-from.d.ts +0 -11
  77. package/dist/types/transforms/bin-1d.d.ts +0 -15
  78. package/dist/types/transforms/bin-2d.d.ts +0 -19
  79. package/dist/types/transforms/bin-date.d.ts +0 -44
  80. package/dist/types/transforms/bin-histogram.d.ts +0 -51
  81. package/dist/types/transforms/bin-linear-1d.d.ts +0 -12
  82. package/dist/types/transforms/bin-linear-2d.d.ts +0 -19
  83. package/dist/types/transforms/line-density.d.ts +0 -24
  84. package/dist/types/transforms/m4.d.ts +0 -21
  85. package/dist/types/transforms/scales.d.ts +0 -1
  86. package/dist/types/transforms/util/bin-step.d.ts +0 -61
  87. package/dist/types/transforms/util/time-interval.d.ts +0 -13
  88. package/dist/types/types.d.ts +0 -62
  89. package/dist/types/util/ast.d.ts +0 -61
  90. package/dist/types/util/function.d.ts +0 -56
  91. package/dist/types/util/string.d.ts +0 -3
  92. package/dist/types/util/type-check.d.ts +0 -22
  93. package/dist/types/visit/recurse.d.ts +0 -28
  94. package/dist/types/visit/rewrite.d.ts +0 -10
  95. package/dist/types/visit/visitors.d.ts +0 -34
  96. package/dist/types/visit/walk.d.ts +0 -10
  97. package/jsconfig.json +0 -11
package/src/ast/window.js CHANGED
@@ -1,19 +1,12 @@
1
1
  /**
2
+ * @import { ExprVarArgs, OrderByExpr, WindowFunctionName } from '../types.js'
2
3
  * @import { AggregateNode } from './aggregate.js'
3
- * @import { ExprVarArgs, WindowFunctionName } from '../types.js'
4
- * @import { ParamLike } from '../types.js'
4
+ * @import { WindowFrameNode } from './window-frame.js'
5
5
  */
6
- import { WINDOW, WINDOW_CLAUSE, WINDOW_DEF, WINDOW_FRAME } from '../constants.js';
6
+ import { WINDOW, WINDOW_CLAUSE, WINDOW_DEF, WINDOW_FUNCTION } from '../constants.js';
7
7
  import { exprList } from '../util/function.js';
8
8
  import { quoteIdentifier } from '../util/string.js';
9
- import { isParamLike } from '../util/type-check.js';
10
- import { FunctionNode } from './function.js';
11
- import { ExprNode, isNode, SQLNode } from './node.js';
12
- import { ParamNode } from './param.js';
13
-
14
- /**
15
- * @typedef {[any, any] | ParamLike} FrameExtent
16
- */
9
+ import { ExprNode, SQLNode } from './node.js';
17
10
 
18
11
  export class WindowClauseNode extends SQLNode {
19
12
  /**
@@ -90,21 +83,12 @@ export class WindowNode extends ExprNode {
90
83
  }
91
84
 
92
85
  /**
93
- * Return an updated window with the given rows frame.
94
- * @param {FrameExtent} extent The row-based window frame extent.
95
- * @returns {WindowNode} A new window node.
96
- */
97
- rows(extent) {
98
- return new WindowNode(this.func, this.def.rows(extent));
99
- }
100
-
101
- /**
102
- * Return an updated window with the given range frame.
103
- * @param {FrameExtent} extent The range-based window frame extent.
86
+ * Return an updated window with the given frame definition.
87
+ * @param {WindowFrameNode} framedef The frame definition.
104
88
  * @returns {WindowNode} A new window node.
105
89
  */
106
- range(extent) {
107
- return new WindowNode(this.func, this.def.range(extent));
90
+ frame(framedef) {
91
+ return new WindowNode(this.func, this.def.frame(framedef));
108
92
  }
109
93
 
110
94
  /**
@@ -116,14 +100,55 @@ export class WindowNode extends ExprNode {
116
100
  }
117
101
  }
118
102
 
119
- export class WindowFunctionNode extends FunctionNode {
103
+ export class WindowFunctionNode extends ExprNode {
120
104
  /**
121
105
  * Instantiate a window function call node.
122
- * @param {WindowFunctionName} name The function name.
123
- * @param {ExprNode[]} [args=[]] The function arguments.
106
+ * @param {WindowFunctionName} name The window function name.
107
+ * @param {ExprNode[]} [args=[]] The window function arguments.
108
+ * @param {boolean} [ignoreNulls=false] Flag to ignore null values.
109
+ * @param {OrderByExpr} [argOrder] Order expressions for window arguments.
110
+ * Note that this argument ordering is distinct from the window ordering.
124
111
  */
125
- constructor(name, args) {
126
- super(name, args);
112
+ constructor(name, args = [], ignoreNulls = false, argOrder = []) {
113
+ super(WINDOW_FUNCTION);
114
+ /**
115
+ * The window function name.
116
+ * @type {string}
117
+ * @readonly
118
+ */
119
+ this.name = name;
120
+ /**
121
+ * The window function arguments.
122
+ * @type {ExprNode[]}
123
+ * @readonly
124
+ */
125
+ this.args = args;
126
+ /**
127
+ * Flag to ignore null values.
128
+ * @type {boolean}
129
+ * @readonly
130
+ */
131
+ this.ignoreNulls = ignoreNulls;
132
+ /**
133
+ * Order by expression for window arguments.
134
+ * @type {ExprNode[]}
135
+ * @readonly
136
+ */
137
+ this.order = exprList([argOrder]);
138
+ }
139
+
140
+ /**
141
+ * Generate a SQL query string for this node.
142
+ * @returns {string}
143
+ */
144
+ toString() {
145
+ const { name, args, ignoreNulls, order } = this;
146
+ const arg = [
147
+ args.join(', '),
148
+ order.length ? `ORDER BY ${order.join(', ')}` : '',
149
+ ignoreNulls ? 'IGNORE NULLS' : ''
150
+ ].filter(x => x).join(' ');
151
+ return `${name}(${arg})`;
127
152
  }
128
153
  }
129
154
 
@@ -133,9 +158,9 @@ export class WindowDefNode extends SQLNode {
133
158
  * @param {string} [name] The base window definition name.
134
159
  * @param {ExprNode[]} [partition] The partition by criteria.
135
160
  * @param {ExprNode[]} [order] The order by criteria.
136
- * @param {WindowFrameNode} [frame] The window frame definition.
161
+ * @param {WindowFrameNode} [framedef] The window frame definition.
137
162
  */
138
- constructor(name, partition, order, frame) {
163
+ constructor(name, partition, order, framedef) {
139
164
  super(WINDOW_DEF);
140
165
  /**
141
166
  * The base window definition name.
@@ -160,7 +185,7 @@ export class WindowDefNode extends SQLNode {
160
185
  * @type {WindowFrameNode}
161
186
  * @readonly
162
187
  */
163
- this.frame = frame;
188
+ this.framedef = framedef;
164
189
  }
165
190
 
166
191
  /**
@@ -191,21 +216,12 @@ export class WindowDefNode extends SQLNode {
191
216
  }
192
217
 
193
218
  /**
194
- * Return an updated window definition with the given rows frame.
195
- * @param {FrameExtent} extent The row-based window frame extent.
196
- * @returns {WindowDefNode} A new window definition node.
197
- */
198
- rows(extent) {
199
- return deriveDef(this, { frame: new WindowFrameNode(extent) });
200
- }
201
-
202
- /**
203
- * Return an updated window definition with the given range frame.
204
- * @param {FrameExtent} extent The range-based window frame extent.
219
+ * Return an updated window definition with the given frame definition.
220
+ * @param {WindowFrameNode} framedef The frame definition.
205
221
  * @returns {WindowDefNode} A new window definition node.
206
222
  */
207
- range(extent) {
208
- return deriveDef(this, { frame: new WindowFrameNode(extent, true) });
223
+ frame(framedef) {
224
+ return deriveDef(this, { framedef });
209
225
  }
210
226
 
211
227
  /**
@@ -213,62 +229,18 @@ export class WindowDefNode extends SQLNode {
213
229
  * @returns {string}
214
230
  */
215
231
  toString() {
216
- const { name, partition, order, frame } = this;
232
+ const { name, partition, order, framedef } = this;
217
233
  const base = name && quoteIdentifier(name);
218
234
  const def = [
219
235
  base,
220
236
  partition?.length && `PARTITION BY ${partition.join(', ')}`,
221
237
  order?.length && `ORDER BY ${order.join(', ')}`,
222
- frame
238
+ framedef
223
239
  ].filter(x => x);
224
240
  return base && def.length < 2 ? base : `(${def.join(' ')})`;
225
241
  }
226
242
  }
227
243
 
228
- export class WindowFrameNode extends SQLNode {
229
- /**
230
- * Instantiate a window frame definition node.
231
- * @param {FrameExtent} extent The frame extent as [preceding, following]
232
- * row or interval offsets.
233
- * @param {boolean} [range] The frame type: `true` for range, otherwise rows.
234
- * @param {ExprNode} [exclude] The window exclusion criteria.
235
- */
236
- constructor(extent, range = false, exclude = undefined) {
237
- super(WINDOW_FRAME);
238
- /**
239
- * The frame extent as [preceding, following] row or interval offsets.
240
- * @type {ParamNode | [any, any]}
241
- * @readonly
242
- */
243
- this.extent = isParamLike(extent) ? new ParamNode(extent) : extent;
244
- /**
245
- * The frame type: `true` for range, otherwise rows.
246
- * @type {boolean}
247
- * @readonly
248
- */
249
- this.range = range;
250
- /**
251
- * The window exclusion criteria.
252
- * @type {ExprNode}
253
- * @readonly
254
- */
255
- this.exclude = exclude;
256
- }
257
-
258
- /**
259
- * Generate a SQL query string for this node.
260
- * @returns {string}
261
- */
262
- toString() {
263
- const { range, exclude, extent } = this;
264
- const type = range ? 'RANGE' : 'ROWS';
265
- const [prev, next] = isNode(extent) ? extent.value : extent;
266
- const a = frameValue(prev, 'PRECEDING');
267
- const b = frameValue(next, 'FOLLOWING');
268
- return `${type} BETWEEN ${a} AND ${b}${exclude ? ` ${exclude}` : ''}`;
269
- }
270
- }
271
-
272
244
  /**
273
245
  * Derive a new window definition node from an existing one.
274
246
  * @param {WindowDefNode} def The existing window definition.
@@ -276,19 +248,13 @@ export class WindowFrameNode extends SQLNode {
276
248
  * @param {string} [options.name] The base window definition name.
277
249
  * @param {ExprNode[]} [options.partition] The partition by criteria.
278
250
  * @param {ExprNode[]} [options.order] The order by criteria.
279
- * @param {WindowFrameNode} [options.frame] The window frame definition.
251
+ * @param {WindowFrameNode} [options.framedef] The window frame definition.
280
252
  */
281
253
  function deriveDef(def, options) {
282
254
  return new WindowDefNode(
283
255
  options.name ?? def.name,
284
256
  options.partition ?? def.partition,
285
257
  options.order ?? def.order,
286
- options.frame ?? def.frame
258
+ options.framedef ?? def.framedef
287
259
  );
288
260
  }
289
-
290
- function frameValue(value, order) {
291
- return value === 0 ? 'CURRENT ROW'
292
- : Number.isFinite(value) ? `${Math.abs(value)} ${order}`
293
- : `UNBOUNDED ${order}`;
294
- }
package/src/constants.js CHANGED
@@ -8,6 +8,7 @@ export const ORDER_BY = 'ORDER_BY';
8
8
  export const CAST = 'CAST';
9
9
  export const CASE = 'CASE';
10
10
  export const WHEN = 'WHEN';
11
+ export const COLLATE = 'COLLATE';
11
12
 
12
13
  export const UNARY_OPERATOR = 'UNARY';
13
14
  export const UNARY_POSTFIX_OPERATOR = 'UNARY_POSTFIX';
@@ -20,8 +21,10 @@ export const IN_OPERATOR = 'IN';
20
21
  export const FUNCTION = 'FUNCTION';
21
22
  export const AGGREGATE = 'AGGREGATE';
22
23
  export const WINDOW = 'WINDOW';
24
+ export const WINDOW_FUNCTION = 'WINDOW_FUNCTION';
23
25
  export const WINDOW_DEF = 'WINDOW_DEF';
24
26
  export const WINDOW_FRAME = 'WINDOW_FRAME';
27
+ export const WINDOW_EXTENT_EXPR = 'WINDOW_EXTENT_EXPR';
25
28
 
26
29
  export const EXPRESSION = 'EXPRESSION';
27
30
  export const FRAGMENT = 'FRAGMENT';
@@ -29,16 +32,12 @@ export const VERBATIM = 'VERBATIM';
29
32
  export const PARAM = 'PARAM';
30
33
 
31
34
  export const WITH_CLAUSE = 'WITH_CLAUSE';
35
+ export const WINDOW_CLAUSE = 'WINDOW_CLAUSE';
32
36
  export const SELECT_CLAUSE = 'SELECT_CLAUSE';
33
37
  export const FROM_CLAUSE = 'FROM_CLAUSE';
34
- export const WHERE_CLAUSE = 'WHERE_CLAUSE';
35
38
  export const SAMPLE_CLAUSE = 'SAMPLE_CLAUSE';
36
- export const GROUPBY_CLAUSE = 'GROUPBY_CLAUSE';
37
- export const HAVING_CLAUSE = 'HAVING_CLAUSE';
38
- export const WINDOW_CLAUSE = 'WINDOW_CLAUSE';
39
- export const QUALIFY_CLAUSE = 'QUALIFY_CLAUSE';
40
- export const ORDERBY_CLAUSE = 'ORDERBY_CLAUSE';
41
39
 
42
40
  export const SELECT_QUERY = 'SELECT_QUERY';
43
41
  export const DESCRIBE_QUERY = 'DESCRIBE_QUERY';
44
42
  export const SET_OPERATION = 'SET_OPERATION';
43
+ export const SCALAR_SUBQUERY = 'SCALAR_SUBQUERY';
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @import { ExprValue } from '../types.js'
3
+ */
4
+ import { CollateNode } from '../ast/collate.js';
5
+ import { asNode } from '../util/ast.js';
6
+
7
+ /**
8
+ * Indicate ascending sort order for an expression.
9
+ * @param {ExprValue} expr The expression to collate.
10
+ * @param {string} collation The collation type, such as
11
+ * 'NOCASE', 'NOACCENT', 'NFC', or locale-specific collations.
12
+ * @returns {CollateNode}
13
+ */
14
+ export function collate(expr, collation) {
15
+ return new CollateNode(asNode(expr), collation);
16
+ }
@@ -2,19 +2,9 @@
2
2
  * @import { FunctionNode } from '../ast/function.js'
3
3
  * @import { ExprValue } from '../types.js'
4
4
  */
5
- import { IntervalNode } from '../ast/interval.js';
6
5
  import { asNode } from '../util/ast.js';
7
6
  import { fn } from '../util/function.js';
8
-
9
- /**
10
- * Create a new interval.
11
- * @param {string} unit The interval unit, such as day or year.
12
- * @param {number} steps The number interval unit steps.
13
- * @returns {IntervalNode}
14
- */
15
- export function interval(unit, steps) {
16
- return new IntervalNode(unit, steps);
17
- }
7
+ import { interval } from './interval.js';
18
8
 
19
9
  /**
20
10
  * Given a date/time value, return the milliseconds since the UNIX epoch.
@@ -0,0 +1,83 @@
1
+ import { IntervalNode } from '../ast/interval.js';
2
+
3
+ /**
4
+ * Create a new interval.
5
+ * @param {string} unit The interval unit, such as day or year.
6
+ * @param {number} steps The number of interval unit steps.
7
+ * @returns {IntervalNode}
8
+ */
9
+ export function interval(unit, steps) {
10
+ return new IntervalNode(unit, steps);
11
+ }
12
+
13
+ /**
14
+ * Create a new years interval.
15
+ * @param {number} steps The number of years.
16
+ * @returns {IntervalNode}
17
+ */
18
+ export function years(steps) {
19
+ return interval('YEARS', steps);
20
+ }
21
+
22
+ /**
23
+ * Create a new months interval.
24
+ * @param {number} steps The number of months.
25
+ * @returns {IntervalNode}
26
+ */
27
+ export function months(steps) {
28
+ return interval('MONTHS', steps);
29
+ }
30
+
31
+ /**
32
+ * Create a new days interval.
33
+ * @param {number} steps The number of days.
34
+ * @returns {IntervalNode}
35
+ */
36
+ export function days(steps) {
37
+ return interval('DAYS', steps);
38
+ }
39
+
40
+ /**
41
+ * Create a new hours interval.
42
+ * @param {number} steps The number of hours.
43
+ * @returns {IntervalNode}
44
+ */
45
+ export function hours(steps) {
46
+ return interval('HOURS', steps);
47
+ }
48
+
49
+ /**
50
+ * Create a new minutes interval.
51
+ * @param {number} steps The number of minutes.
52
+ * @returns {IntervalNode}
53
+ */
54
+ export function minutes(steps) {
55
+ return interval('MINUTES', steps);
56
+ }
57
+
58
+ /**
59
+ * Create a new seconds interval.
60
+ * @param {number} steps The number of seconds.
61
+ * @returns {IntervalNode}
62
+ */
63
+ export function seconds(steps) {
64
+ return interval('SECONDS', steps);
65
+ }
66
+
67
+ /**
68
+ * Create a new milliseconds interval.
69
+ * @param {number} steps The number of milliseconds.
70
+ * @returns {IntervalNode}
71
+ */
72
+ export function milliseconds(steps) {
73
+ return interval('MILLISECONDS', steps);
74
+ }
75
+
76
+ /**
77
+ * Create a new microseconds interval.
78
+ * @param {number} steps The number of microseconds.
79
+ * @returns {IntervalNode}
80
+ */
81
+ export function microseconds(steps) {
82
+ return interval('MICROSECONDS', steps);
83
+ }
@@ -15,8 +15,9 @@ export function literal(value) {
15
15
  /**
16
16
  * Return a SQL AST node for verbatim string content.
17
17
  * @param {string} value The verbatim value.
18
+ * @param {string} [hint] A type hint for analyzing verbatim content.
18
19
  * @returns {VerbatimNode}
19
20
  */
20
- export function verbatim(value) {
21
- return new VerbatimNode(value);
21
+ export function verbatim(value, hint) {
22
+ return new VerbatimNode(value, hint);
22
23
  }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * @import { FrameExclude } from '../ast/window-frame.js'
3
+ * @import { FrameExtent, FrameValue } from '../types.js'
4
+ */
5
+ import { CURRENT_ROW, FOLLOWING, GROUPS, PRECEDING, RANGE, ROWS, WindowFrameExprNode, WindowFrameNode } from '../ast/window-frame.js';
6
+
7
+ /**
8
+ * Return an updated window definition with the given rows frame.
9
+ * @param {FrameExtent} extent The row-based window frame extent.
10
+ * @param {FrameExclude} [exclude] The window frame exclusion criteria.
11
+ * @returns {WindowFrameNode} A window frame node.
12
+ */
13
+ export function frameRows(extent, exclude) {
14
+ return new WindowFrameNode(ROWS, extent, exclude);
15
+ }
16
+
17
+ /**
18
+ * Return an updated window definition with the given range frame.
19
+ * @param {FrameExtent} extent The range-based window frame extent.
20
+ * @param {FrameExclude} [exclude] The window frame exclusion criteria.
21
+ * @returns {WindowFrameNode} A window frame node.
22
+ */
23
+ export function frameRange(extent, exclude) {
24
+ return new WindowFrameNode(RANGE, extent, exclude);
25
+ }
26
+
27
+ /**
28
+ * Return an updated window definition with the given groups frame.
29
+ * @param {FrameExtent} extent The group-based window frame extent.
30
+ * @param {FrameExclude} [exclude] The window frame exclusion criteria.
31
+ * @returns {WindowFrameNode} A window frame node.
32
+ */
33
+ export function frameGroups(extent, exclude) {
34
+ return new WindowFrameNode(GROUPS, extent, exclude);
35
+ }
36
+
37
+ /**
38
+ * A `PRECEDING` frame value expression.
39
+ * @param {FrameValue} value The frame value.
40
+ * @returns {WindowFrameExprNode} A preceding value.
41
+ */
42
+ export function preceding(value) {
43
+ return new WindowFrameExprNode(PRECEDING, value);
44
+ }
45
+
46
+ /**
47
+ * A `FOLLOWING` frame value expression.
48
+ * @param {FrameValue} value The frame value.
49
+ * @returns {WindowFrameExprNode} A following value.
50
+ */
51
+ export function following(value) {
52
+ return new WindowFrameExprNode(FOLLOWING, value);
53
+ }
54
+
55
+ /**
56
+ * A `CURRENT ROW` frame value expression.
57
+ * @returns {WindowFrameExprNode} A current row value.
58
+ */
59
+ export function currentRow() {
60
+ return new WindowFrameExprNode(CURRENT_ROW);
61
+ }
package/src/index.js CHANGED
@@ -1,8 +1,9 @@
1
- export { AggregateNode } from './ast/aggregate.js';
1
+ export { AggregateNode, aggregateNames, isAggregateFunction } from './ast/aggregate.js';
2
2
  export { BetweenOpNode, NotBetweenOpNode } from './ast/between-op.js'
3
3
  export { BinaryOpNode } from './ast/binary-op.js';
4
4
  export { CaseNode, WhenNode } from './ast/case.js';
5
5
  export { CastNode } from './ast/cast.js';
6
+ export { CollateNode } from './ast/collate.js';
6
7
  export { ColumnParamNode, isColumnParam } from './ast/column-param.js';
7
8
  export { ColumnRefNode, ColumnNameRefNode, isColumnRef } from './ast/column-ref.js';
8
9
  export { FragmentNode } from './ast/fragment.js';
@@ -17,20 +18,24 @@ export { OrderByNode } from './ast/order-by.js';
17
18
  export { ParamNode } from './ast/param.js';
18
19
  export { DescribeQuery, Query, SelectQuery, SetOperation, isDescribeQuery, isQuery, isSelectQuery } from './ast/query.js';
19
20
  export { SampleClauseNode } from './ast/sample.js';
21
+ export { ScalarSubqueryNode } from './ast/subquery.js';
20
22
  export { SelectClauseNode } from './ast/select.js';
21
23
  export { TableRefNode, isTableRef } from './ast/table-ref.js';
22
24
  export { UnaryOpNode, UnaryPosftixOpNode } from './ast/unary-op.js';
23
25
  export { VerbatimNode } from './ast/verbatim.js';
24
- export { WindowClauseNode, WindowDefNode, WindowFrameNode, WindowFunctionNode, WindowNode } from './ast/window.js';
26
+ export { WindowClauseNode, WindowDefNode, WindowFunctionNode, WindowNode } from './ast/window.js';
27
+ export { WindowFrameNode, WindowFrameExprNode } from './ast/window-frame.js';
25
28
  export { WithClauseNode } from './ast/with.js';
26
29
 
27
30
  export { argmax, argmin, arrayAgg, avg, corr, count, covariance, covarPop, entropy, first, geomean, kurtosis, mad, max, median, min, mode, last, product, quantile, regrAvgX, regrAvgY, regrCount, regrIntercept, regrR2, regrSXX, regrSXY, regrSYY, regrSlope, skewness, stddev, stddevPop, stringAgg, sum, variance, varPop } from './functions/aggregate.js';
28
31
  export { cond } from './functions/case.js';
29
32
  export { cast, float32, float64, int32 } from './functions/cast.js';
33
+ export { collate } from './functions/collate.js';
30
34
  export { column } from './functions/column.js';
31
35
  export { cte } from './functions/cte.js';
32
- export { dateBin, dateMonth, dateMonthDay, dateDay, epoch_ms, interval } from './functions/datetime.js';
33
- export { literal } from './functions/literal.js';
36
+ export { dateBin, dateMonth, dateMonthDay, dateDay, epoch_ms } from './functions/datetime.js';
37
+ export { days, hours, interval, microseconds, minutes, milliseconds, months, seconds, years } from './functions/interval.js';
38
+ export { literal, verbatim } from './functions/literal.js';
34
39
  export { abs, ceil, exp, floor, greatest, isFinite, isInfinite, isNaN, least, ln, log, round, sign, sqrt, trunc } from './functions/numeric.js';
35
40
  export { and, or, not, isNull, isNotNull, bitNot, bitAnd, bitOr, bitLeft, bitRight, add, sub, mul, div, idiv, mod, pow, eq, neq, lt, gt, lte, gte, isDistinct, isNotDistinct, isBetween, isNotBetween, isIn } from './functions/operators.js';
36
41
  export { asc, desc } from './functions/order-by.js';
@@ -39,7 +44,9 @@ export { sql } from './functions/sql-template-tag.js';
39
44
  export { regexp_matches, contains, prefix, suffix, lower, upper, length } from './functions/string.js';
40
45
  export { coalesce } from './functions/util.js';
41
46
  export { cume_dist, dense_rank, first_value, lag, last_value, lead, nth_value, ntile, percent_rank, rank, row_number } from './functions/window.js';
47
+ export { currentRow, following, frameGroups, frameRange, frameRows, preceding } from './functions/window-frame.js';
42
48
 
49
+ export { deepClone } from './visit/clone.js';
43
50
  export { rewrite } from './visit/rewrite.js';
44
51
  export { collectAggregates, collectColumns, collectParams, isAggregateExpression } from './visit/visitors.js';
45
52
  export { walk } from './visit/walk.js';
@@ -54,6 +61,7 @@ export { binDate } from './transforms/bin-date.js';
54
61
  export { binHistogram } from './transforms/bin-histogram.js';
55
62
  export { binLinear1d } from './transforms/bin-linear-1d.js';
56
63
  export { binLinear2d } from './transforms/bin-linear-2d.js';
64
+ export { filterQuery } from './transforms/filter-query.js';
57
65
  export { lineDensity } from './transforms/line-density.js';
58
66
  export { m4 } from './transforms/m4.js';
59
67
  export { scaleTransform } from './transforms/scales.js';
package/src/load/load.js CHANGED
@@ -25,7 +25,7 @@ export function loadParquet(tableName, fileName, options) {
25
25
  /**
26
26
  * Load geometry data within a spatial file format.
27
27
  * This method requires that the DuckDB spatial extension is loaded.
28
- * Supports GeoJSON, TopoJSON, and other comomn spatial formats.
28
+ * Supports GeoJSON, TopoJSON, and other common spatial formats.
29
29
  * For TopoJSON, wet the layer option to indicate the feature to extract.
30
30
  */
31
31
  export function loadSpatial(tableName, fileName, options = {}) {
@@ -2,7 +2,8 @@
2
2
  * @import { ExprNode } from '../ast/node.js'
3
3
  * @import { ExprValue, TimeUnit } from '../types.js'
4
4
  */
5
- import { dateBin, interval } from '../functions/datetime.js';
5
+ import { dateBin } from '../functions/datetime.js';
6
+ import { interval } from '../functions/interval.js';
6
7
  import { add } from '../functions/operators.js';
7
8
  import { timeInterval } from './util/time-interval.js';
8
9
 
@@ -0,0 +1,44 @@
1
+ /**
2
+ * @import { Query } from '../ast/query.js'
3
+ * @import { TableRefNode } from '../ast/table-ref.js'
4
+ * @import { FilterExpr } from '../types.js'
5
+ */
6
+ import { isSelectQuery } from '../ast/query.js';
7
+ import { isTableRef } from '../ast/table-ref.js';
8
+ import { deepClone } from '../visit/clone.js';
9
+ import { walk } from '../visit/walk.js';
10
+
11
+ /**
12
+ * Returns a generator function that clones the given query and adds
13
+ * a WHERE clause for the specified table reference.
14
+ * @param {Query} query The query to clone and extend.
15
+ * @param {TableRefNode} tableRef The table to filter.
16
+ * @returns {(filter: FilterExpr) => Query} The generator function.
17
+ */
18
+ export function filterQuery(query, tableRef) {
19
+ return (filter) => {
20
+ const clone = deepClone(query);
21
+ walk(clone, (node) => {
22
+ if (
23
+ isSelectQuery(node) &&
24
+ node._from.length === 1 &&
25
+ isTableRef(node._from[0].expr) &&
26
+ arrayEquals(node._from[0].expr.table, tableRef.table)
27
+ ) {
28
+ node.where(filter);
29
+ }
30
+ });
31
+ return clone;
32
+ };
33
+ }
34
+
35
+ function arrayEquals(a, b) {
36
+ if (a === b) return true;
37
+ if (a == null || b == null) return false;
38
+ if (a.length !== b.length) return false;
39
+
40
+ for (var i = 0; i < a.length; ++i) {
41
+ if (a[i] !== b[i]) return false;
42
+ }
43
+ return true;
44
+ }
package/src/types.ts CHANGED
@@ -110,3 +110,12 @@ export type TimeUnit =
110
110
  | 'second'
111
111
  | 'millisecond'
112
112
  | 'microsecond';
113
+
114
+ export type FrameValue = ExprNode | number | null;
115
+
116
+ export type FrameExtent = [FrameValue, FrameValue] | ParamLike;
117
+
118
+ export type FrameScope =
119
+ | 'PRECEDING'
120
+ | 'FOLLOWING'
121
+ | 'CURRENT ROW';
@@ -0,0 +1,53 @@
1
+ import { isNode } from '../ast/node.js';
2
+ import { recurse } from './recurse.js';
3
+
4
+ /**
5
+ * Create a deep clone of the given SQL AST node and all children nodes.
6
+ * @template T
7
+ * @param {T} node The node to deeply clone.
8
+ * @returns {T} The cloned node.
9
+ */
10
+ export function deepClone(node) {
11
+ const clone = shallowClone(node);
12
+
13
+ if (isNode(node)) {
14
+ const props = recurse[node.type];
15
+ const n = props?.length ?? 0;
16
+ for (let i = 0; i < n; ++i) {
17
+ const key = props[i];
18
+ const value = node[key];
19
+ clone[key] = Array.isArray(value)
20
+ ? value.map(v => deepClone(v))
21
+ : deepClone(value);
22
+ }
23
+ }
24
+
25
+ return clone;
26
+ }
27
+
28
+ /**
29
+ * Create a shallow clone of the given SQL AST node.
30
+ * @template T
31
+ * @param {T} node The node to clone.
32
+ * @returns {T} The cloned node.
33
+ */
34
+ function shallowClone(node) {
35
+ /** @type {T} */
36
+ let clone;
37
+
38
+ if (!node || typeof node !== 'object') {
39
+ return node;
40
+ } else if (isNode(node)) {
41
+ clone = node.clone();
42
+ } else if (node instanceof Date) {
43
+ // @ts-expect-error
44
+ return new Date(+node);
45
+ } else if (Array.isArray(node)) {
46
+ // @ts-expect-error
47
+ return node.slice();
48
+ } else {
49
+ return { ...node };
50
+ }
51
+
52
+ return clone;
53
+ }