@uwdata/mosaic-sql 0.12.2 → 0.13.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.
- package/README.md +1 -1
- package/dist/types/ast/query.d.ts +59 -14
- package/dist/types/ast/with.d.ts +11 -1
- package/dist/types/functions/aggregate.d.ts +6 -0
- package/dist/types/functions/cte.d.ts +13 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/types/types.d.ts +3 -1
- package/package.json +9 -9
- package/src/ast/literal.js +1 -1
- package/src/ast/query.js +102 -33
- package/src/ast/with.js +16 -2
- package/src/functions/aggregate.js +9 -0
- package/src/functions/cte.js +16 -0
- package/src/index.js +2 -1
- package/src/transforms/m4.js +12 -3
- package/src/types.ts +6 -1
- package/vitest.config.ts +3 -0
- package/dist/mosaic-sql.js +0 -2610
- package/dist/mosaic-sql.min.js +0 -1
package/README.md
CHANGED
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@uwdata/mosaic-sql)
|
|
4
4
|
|
|
5
|
-
An API for convenient construction and analysis of SQL queries. Query objects
|
|
5
|
+
An API for convenient construction and analysis of SQL queries. Constructed `Query` objects coerce to SQL query strings.
|
|
6
6
|
|
|
7
7
|
Many `mosaic-sql` utilities are included as part of the [vgplot](https://github.com/uwdata/mosaic/tree/main/packages/vgplot) API.
|
|
@@ -17,6 +17,12 @@ export function isSelectQuery(value: any): value is SelectQuery;
|
|
|
17
17
|
*/
|
|
18
18
|
export function isDescribeQuery(value: any): value is DescribeQuery;
|
|
19
19
|
export class Query extends ExprNode {
|
|
20
|
+
/**
|
|
21
|
+
* Create a new WITH clause with the given CTE queries.
|
|
22
|
+
* @param {...import('../types.js').WithExpr} expr The WITH CTE queries.
|
|
23
|
+
* @returns {WithClause}
|
|
24
|
+
*/
|
|
25
|
+
static with(...expr: import("../types.js").WithExpr[]): WithClause;
|
|
20
26
|
/**
|
|
21
27
|
* Create a new select query with the given SELECT expressions.
|
|
22
28
|
* @param {...import('../types.js').SelectExpr} expr The SELECT expressions.
|
|
@@ -29,12 +35,6 @@ export class Query extends ExprNode {
|
|
|
29
35
|
* @returns {SelectQuery}
|
|
30
36
|
*/
|
|
31
37
|
static from(...expr: import("../types.js").FromExpr[]): SelectQuery;
|
|
32
|
-
/**
|
|
33
|
-
* Create a new select query with the given WITH CTE queries.
|
|
34
|
-
* @param {...import('../types.js').WithExpr} expr The WITH CTE queries.
|
|
35
|
-
* @returns {SelectQuery}
|
|
36
|
-
*/
|
|
37
|
-
static with(...expr: import("../types.js").WithExpr[]): SelectQuery;
|
|
38
38
|
/**
|
|
39
39
|
* Create a new UNION set operation over the given queries.
|
|
40
40
|
* @param {...Query} queries The queries.
|
|
@@ -69,6 +69,8 @@ export class Query extends ExprNode {
|
|
|
69
69
|
* Instantiate a new query.
|
|
70
70
|
*/
|
|
71
71
|
constructor(type: any);
|
|
72
|
+
/** @type {WithClauseNode[]} */
|
|
73
|
+
_with: WithClauseNode[];
|
|
72
74
|
/** @type {ExprNode[]} */
|
|
73
75
|
_orderby: ExprNode[];
|
|
74
76
|
/** @type {number} */
|
|
@@ -87,6 +89,12 @@ export class Query extends ExprNode {
|
|
|
87
89
|
* @returns {Query}
|
|
88
90
|
*/
|
|
89
91
|
clone(): Query;
|
|
92
|
+
/**
|
|
93
|
+
* Add WITH common table expressions (CTEs).
|
|
94
|
+
* @param {...import('../types.js').WithExpr} expr Expressions to add.
|
|
95
|
+
* @returns {this}
|
|
96
|
+
*/
|
|
97
|
+
with(...expr: import("../types.js").WithExpr[]): this;
|
|
90
98
|
/**
|
|
91
99
|
* Add ORDER BY expressions.
|
|
92
100
|
* @param {...import('../types.js').OrderByExpr} expr Expressions to add.
|
|
@@ -111,8 +119,6 @@ export class SelectQuery extends Query {
|
|
|
111
119
|
* Instantiate a new select query.
|
|
112
120
|
*/
|
|
113
121
|
constructor();
|
|
114
|
-
/** @type {WithClauseNode[]} */
|
|
115
|
-
_with: WithClauseNode[];
|
|
116
122
|
/** @type {SelectClauseNode[]} */
|
|
117
123
|
_select: SelectClauseNode[];
|
|
118
124
|
/** @type {FromClauseNode[]} */
|
|
@@ -134,12 +140,6 @@ export class SelectQuery extends Query {
|
|
|
134
140
|
* @returns {SelectQuery}
|
|
135
141
|
*/
|
|
136
142
|
clone(): SelectQuery;
|
|
137
|
-
/**
|
|
138
|
-
* Add WITH common table expressions (CTEs).
|
|
139
|
-
* @param {...import('../types.js').WithExpr} expr Expressions to add.
|
|
140
|
-
* @returns {this}
|
|
141
|
-
*/
|
|
142
|
-
with(...expr: import("../types.js").WithExpr[]): this;
|
|
143
143
|
/**
|
|
144
144
|
* Add SELECT expressions.
|
|
145
145
|
* @param {...import('../types.js').SelectExpr} expr Expressions to add.
|
|
@@ -261,8 +261,53 @@ export class SetOperation extends Query {
|
|
|
261
261
|
}
|
|
262
262
|
import { ExprNode } from './node.js';
|
|
263
263
|
import { WithClauseNode } from './with.js';
|
|
264
|
+
declare class WithClause {
|
|
265
|
+
/**
|
|
266
|
+
* Instantiate a new WITH clause instance.
|
|
267
|
+
* @param {...import('../types.js').WithExpr} expr The WITH CTE queries.
|
|
268
|
+
*/
|
|
269
|
+
constructor(...expr: import("../types.js").WithExpr[]);
|
|
270
|
+
_with: import("../types.js").WithExpr[];
|
|
271
|
+
/**
|
|
272
|
+
* Create a new select query with the given SELECT expressions.
|
|
273
|
+
* @param {...import('../types.js').SelectExpr} expr The SELECT expressions.
|
|
274
|
+
* @returns {SelectQuery}
|
|
275
|
+
*/
|
|
276
|
+
select(...expr: import("../types.js").SelectExpr[]): SelectQuery;
|
|
277
|
+
/**
|
|
278
|
+
* Create a new select query with the given FROM expressions.
|
|
279
|
+
* @param {...import('../types.js').FromExpr} expr The FROM expressions.
|
|
280
|
+
* @returns {SelectQuery}
|
|
281
|
+
*/
|
|
282
|
+
from(...expr: import("../types.js").FromExpr[]): SelectQuery;
|
|
283
|
+
/**
|
|
284
|
+
* Create a new UNION set operation over the given queries.
|
|
285
|
+
* @param {...Query} queries The queries.
|
|
286
|
+
* @returns {SetOperation}
|
|
287
|
+
*/
|
|
288
|
+
union(...queries: Query[]): SetOperation;
|
|
289
|
+
/**
|
|
290
|
+
* Create a new UNION ALL set operation over the given queries.
|
|
291
|
+
* @param {...Query} queries The queries.
|
|
292
|
+
* @returns {SetOperation}
|
|
293
|
+
*/
|
|
294
|
+
unionAll(...queries: Query[]): SetOperation;
|
|
295
|
+
/**
|
|
296
|
+
* Create a new INTERSECT set operation over the given queries.
|
|
297
|
+
* @param {...Query} queries The queries.
|
|
298
|
+
* @returns {SetOperation}
|
|
299
|
+
*/
|
|
300
|
+
intersect(...queries: Query[]): SetOperation;
|
|
301
|
+
/**
|
|
302
|
+
* Create a new EXCEPT set operation over the given queries.
|
|
303
|
+
* @param {...Query} queries The queries.
|
|
304
|
+
* @returns {SetOperation}
|
|
305
|
+
*/
|
|
306
|
+
except(...queries: Query[]): SetOperation;
|
|
307
|
+
}
|
|
264
308
|
import { SelectClauseNode } from './select.js';
|
|
265
309
|
import { FromClauseNode } from './from.js';
|
|
266
310
|
import { SampleClauseNode } from './sample.js';
|
|
267
311
|
import { WindowClauseNode } from './window.js';
|
|
268
312
|
import { SQLNode } from './node.js';
|
|
313
|
+
export {};
|
package/dist/types/ast/with.d.ts
CHANGED
|
@@ -3,8 +3,12 @@ export class WithClauseNode extends SQLNode {
|
|
|
3
3
|
* Instantiate a with clause node for a common table expression (CTE).
|
|
4
4
|
* @param {string} name The common table expression (CTE) name.
|
|
5
5
|
* @param {Query} query The common table expression (CTE) query.
|
|
6
|
+
* @param {boolean | null} [materialized] The common table expression (CTE)
|
|
7
|
+
* materialization flag. If `true`, forces materialization of the CTE.
|
|
8
|
+
* If `false`, materialization is not performed. Otherwise (for example, if
|
|
9
|
+
* `undefined` or `null`), materialization is decided by the database.
|
|
6
10
|
*/
|
|
7
|
-
constructor(name: string, query: Query);
|
|
11
|
+
constructor(name: string, query: Query, materialized?: boolean | null);
|
|
8
12
|
/**
|
|
9
13
|
* The common table expression (CTE) name.
|
|
10
14
|
* @type {string}
|
|
@@ -17,6 +21,12 @@ export class WithClauseNode extends SQLNode {
|
|
|
17
21
|
* @readonly
|
|
18
22
|
*/
|
|
19
23
|
readonly query: Query;
|
|
24
|
+
/**
|
|
25
|
+
* The common table expression (CTE) materialization flag.
|
|
26
|
+
* @type {boolean | null}
|
|
27
|
+
* @readonly
|
|
28
|
+
*/
|
|
29
|
+
readonly materialized: boolean | null;
|
|
20
30
|
}
|
|
21
31
|
import { SQLNode } from './node.js';
|
|
22
32
|
import { Query } from './query.js';
|
|
@@ -65,6 +65,12 @@ export function entropy(expr: import("../types.js").ExprValue): AggregateNode;
|
|
|
65
65
|
* @returns {AggregateNode} A SQL aggregate function call.
|
|
66
66
|
*/
|
|
67
67
|
export function first(expr: import("../types.js").ExprValue): AggregateNode;
|
|
68
|
+
/**
|
|
69
|
+
* Compute a geomean aggregate.
|
|
70
|
+
* @param {import('../types.js').ExprValue} expr The expression to aggregate.
|
|
71
|
+
* @returns {AggregateNode} A SQL aggregate function call.
|
|
72
|
+
*/
|
|
73
|
+
export function geomean(expr: import("../types.js").ExprValue): AggregateNode;
|
|
68
74
|
/**
|
|
69
75
|
* Compute a sample kurtosis aggregate.
|
|
70
76
|
* @param {import('../types.js').ExprValue} expr The expression to aggregate.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create a common table expression (CTE) to include within a WITH clause.
|
|
3
|
+
* @param {string} name The common table expression (CTE) name.
|
|
4
|
+
* @param {Query} query The common table expression (CTE) query.
|
|
5
|
+
* @param {boolean | null} [materialized] The common table expression (CTE)
|
|
6
|
+
* materialization flag. If `true`, forces materialization of the CTE.
|
|
7
|
+
* If `false`, materialization is not performed. Otherwise (for example, if
|
|
8
|
+
* `undefined` or `null`), materialization is decided by the database.
|
|
9
|
+
* @returns {WithClauseNode}
|
|
10
|
+
*/
|
|
11
|
+
export function cte(name: string, query: Query, materialized?: boolean | null): WithClauseNode;
|
|
12
|
+
import { Query } from '../ast/query.js';
|
|
13
|
+
import { WithClauseNode } from '../ast/with.js';
|
package/dist/types/index.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ export { VerbatimNode } from "./ast/verbatim.js";
|
|
|
15
15
|
export { WithClauseNode } from "./ast/with.js";
|
|
16
16
|
export { cond } from "./functions/case.js";
|
|
17
17
|
export { column } from "./functions/column.js";
|
|
18
|
+
export { cte } from "./functions/cte.js";
|
|
18
19
|
export { literal } from "./functions/literal.js";
|
|
19
20
|
export { sql } from "./functions/sql-template-tag.js";
|
|
20
21
|
export { rewrite } from "./visit/rewrite.js";
|
|
@@ -38,7 +39,7 @@ export { DescribeQuery, Query, SelectQuery, SetOperation, isDescribeQuery, isQue
|
|
|
38
39
|
export { TableRefNode, isTableRef } from "./ast/table-ref.js";
|
|
39
40
|
export { UnaryOpNode, UnaryPosftixOpNode } from "./ast/unary-op.js";
|
|
40
41
|
export { WindowClauseNode, WindowDefNode, WindowFrameNode, WindowFunctionNode, WindowNode } from "./ast/window.js";
|
|
41
|
-
export { argmax, argmin, arrayAgg, avg, corr, count, covariance, covarPop, entropy, first, 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";
|
|
42
|
+
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";
|
|
42
43
|
export { cast, float32, float64, int32 } from "./functions/cast.js";
|
|
43
44
|
export { dateBin, dateMonth, dateMonthDay, dateDay, epoch_ms, interval } from "./functions/datetime.js";
|
|
44
45
|
export { abs, ceil, exp, floor, greatest, isFinite, isInfinite, isNaN, least, ln, log, round, sign, sqrt, trunc } from "./functions/numeric.js";
|
package/dist/types/types.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { ColumnRefNode } from './ast/column-ref.js';
|
|
|
2
2
|
import { ExprNode, SQLNode } from './ast/node.js';
|
|
3
3
|
import { TableRefNode } from './ast/table-ref.js';
|
|
4
4
|
import { Query } from './ast/query.js';
|
|
5
|
+
import { WithClauseNode } from './ast/with.js';
|
|
5
6
|
/**
|
|
6
7
|
* Interface representing a dynamic parameter value.
|
|
7
8
|
*/
|
|
@@ -51,7 +52,8 @@ export type WindowFunctionName = 'cume_dist' | 'dense_rank' | 'first_value' | 'l
|
|
|
51
52
|
export type MaybeArray<T> = T | T[];
|
|
52
53
|
export type SelectEntry = string | ColumnRefNode | [string, ExprNode] | Record<string, ExprValue>;
|
|
53
54
|
export type SelectExpr = MaybeArray<SelectEntry>;
|
|
54
|
-
export type
|
|
55
|
+
export type WithEntry = WithClauseNode | Record<string, Query>;
|
|
56
|
+
export type WithExpr = MaybeArray<WithEntry>;
|
|
55
57
|
export type FromEntry = string | TableRefNode | SQLNode | [string, SQLNode] | Record<string, string | SQLNode>;
|
|
56
58
|
export type FromExpr = MaybeArray<FromEntry>;
|
|
57
59
|
export type FilterExpr = MaybeArray<string | ExprNode>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uwdata/mosaic-sql",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "SQL query construction and analysis.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sql",
|
|
@@ -10,22 +10,22 @@
|
|
|
10
10
|
"license": "BSD-3-Clause",
|
|
11
11
|
"author": "Jeffrey Heer (https://idl.uw.edu)",
|
|
12
12
|
"type": "module",
|
|
13
|
-
"
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"types": "dist/types/index-types.d.ts",
|
|
13
|
+
"exports": {
|
|
14
|
+
"types": "./dist/types/index-types.d.ts",
|
|
15
|
+
"default": "./src/index.js"
|
|
16
|
+
},
|
|
18
17
|
"repository": {
|
|
19
18
|
"type": "git",
|
|
20
19
|
"url": "https://github.com/uwdata/mosaic.git"
|
|
21
20
|
},
|
|
22
21
|
"scripts": {
|
|
23
22
|
"prebuild": "rimraf dist && mkdir dist",
|
|
24
|
-
"build": "npm run types
|
|
23
|
+
"build": "npm run types",
|
|
25
24
|
"types": "tsc",
|
|
26
25
|
"lint": "eslint src test",
|
|
27
|
-
"test": "vitest run &&
|
|
26
|
+
"test": "vitest run && npm run tsc",
|
|
27
|
+
"tsc": "tsc -p jsconfig.json",
|
|
28
28
|
"prepublishOnly": "npm run test && npm run lint && npm run build"
|
|
29
29
|
},
|
|
30
|
-
"gitHead": "
|
|
30
|
+
"gitHead": "b5a0e03e200c0f04c46562a288f084ffc9f6ad55"
|
|
31
31
|
}
|
package/src/ast/literal.js
CHANGED
|
@@ -30,7 +30,7 @@ export function literalToSQL(value) {
|
|
|
30
30
|
case 'number':
|
|
31
31
|
return Number.isFinite(value) ? `${value}` : 'NULL';
|
|
32
32
|
case 'string':
|
|
33
|
-
return `'${value.
|
|
33
|
+
return `'${value.replaceAll(`'`, `''`)}'`;
|
|
34
34
|
case 'boolean':
|
|
35
35
|
return value ? 'TRUE' : 'FALSE';
|
|
36
36
|
default:
|
package/src/ast/query.js
CHANGED
|
@@ -40,6 +40,15 @@ export function isDescribeQuery(value) {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
export class Query extends ExprNode {
|
|
43
|
+
/**
|
|
44
|
+
* Create a new WITH clause with the given CTE queries.
|
|
45
|
+
* @param {...import('../types.js').WithExpr} expr The WITH CTE queries.
|
|
46
|
+
* @returns {WithClause}
|
|
47
|
+
*/
|
|
48
|
+
static with(...expr) {
|
|
49
|
+
return new WithClause(...expr);
|
|
50
|
+
}
|
|
51
|
+
|
|
43
52
|
/**
|
|
44
53
|
* Create a new select query with the given SELECT expressions.
|
|
45
54
|
* @param {...import('../types.js').SelectExpr} expr The SELECT expressions.
|
|
@@ -58,15 +67,6 @@ export class Query extends ExprNode {
|
|
|
58
67
|
return new SelectQuery().from(...expr);
|
|
59
68
|
}
|
|
60
69
|
|
|
61
|
-
/**
|
|
62
|
-
* Create a new select query with the given WITH CTE queries.
|
|
63
|
-
* @param {...import('../types.js').WithExpr} expr The WITH CTE queries.
|
|
64
|
-
* @returns {SelectQuery}
|
|
65
|
-
*/
|
|
66
|
-
static with(...expr) {
|
|
67
|
-
return new SelectQuery().with(...expr);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
70
|
/**
|
|
71
71
|
* Create a new UNION set operation over the given queries.
|
|
72
72
|
* @param {...Query} queries The queries.
|
|
@@ -117,6 +117,8 @@ export class Query extends ExprNode {
|
|
|
117
117
|
*/
|
|
118
118
|
constructor(type) {
|
|
119
119
|
super(type);
|
|
120
|
+
/** @type {WithClauseNode[]} */
|
|
121
|
+
this._with = [];
|
|
120
122
|
/** @type {ExprNode[]} */
|
|
121
123
|
this._orderby = [];
|
|
122
124
|
/** @type {number} */
|
|
@@ -143,6 +145,27 @@ export class Query extends ExprNode {
|
|
|
143
145
|
return this;
|
|
144
146
|
}
|
|
145
147
|
|
|
148
|
+
/**
|
|
149
|
+
* Add WITH common table expressions (CTEs).
|
|
150
|
+
* @param {...import('../types.js').WithExpr} expr Expressions to add.
|
|
151
|
+
* @returns {this}
|
|
152
|
+
*/
|
|
153
|
+
with(...expr) {
|
|
154
|
+
/** @type {WithClauseNode[]} */
|
|
155
|
+
const list = [];
|
|
156
|
+
const add = (name, q) => {
|
|
157
|
+
const query = q.clone();
|
|
158
|
+
query.cteFor = this;
|
|
159
|
+
list.push(new WithClauseNode(name, query));
|
|
160
|
+
};
|
|
161
|
+
expr.flat().forEach(e => {
|
|
162
|
+
if (e instanceof WithClauseNode) list.push(e);
|
|
163
|
+
else if (e != null) for (const name in e) add(name, e[name]);
|
|
164
|
+
});
|
|
165
|
+
this._with = this._with.concat(list);
|
|
166
|
+
return this;
|
|
167
|
+
}
|
|
168
|
+
|
|
146
169
|
/**
|
|
147
170
|
* Add ORDER BY expressions.
|
|
148
171
|
* @param {...import('../types.js').OrderByExpr} expr Expressions to add.
|
|
@@ -180,8 +203,6 @@ export class SelectQuery extends Query {
|
|
|
180
203
|
*/
|
|
181
204
|
constructor() {
|
|
182
205
|
super(SELECT_QUERY);
|
|
183
|
-
/** @type {WithClauseNode[]} */
|
|
184
|
-
this._with = [];
|
|
185
206
|
/** @type {SelectClauseNode[]} */
|
|
186
207
|
this._select = [];
|
|
187
208
|
/** @type {FromClauseNode[]} */
|
|
@@ -232,26 +253,6 @@ export class SelectQuery extends Query {
|
|
|
232
253
|
return Object.assign(new SelectQuery(), this);
|
|
233
254
|
}
|
|
234
255
|
|
|
235
|
-
/**
|
|
236
|
-
* Add WITH common table expressions (CTEs).
|
|
237
|
-
* @param {...import('../types.js').WithExpr} expr Expressions to add.
|
|
238
|
-
* @returns {this}
|
|
239
|
-
*/
|
|
240
|
-
with(...expr) {
|
|
241
|
-
/** @type {WithClauseNode[]} */
|
|
242
|
-
const list = [];
|
|
243
|
-
const add = (name, q) => {
|
|
244
|
-
const query = q.clone();
|
|
245
|
-
query.cteFor = this;
|
|
246
|
-
list.push(new WithClauseNode(name, query));
|
|
247
|
-
};
|
|
248
|
-
expr.flat().forEach(e => {
|
|
249
|
-
if (e != null) for (const name in e) add(name, e[name]);
|
|
250
|
-
});
|
|
251
|
-
this._with = this._with.concat(list);
|
|
252
|
-
return this;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
256
|
/**
|
|
256
257
|
* Add SELECT expressions.
|
|
257
258
|
* @param {...import('../types.js').SelectExpr} expr Expressions to add.
|
|
@@ -559,10 +560,14 @@ export class SetOperation extends Query {
|
|
|
559
560
|
* @returns {string}
|
|
560
561
|
*/
|
|
561
562
|
toString() {
|
|
562
|
-
const { op, queries, _orderby, _limit, _offset } = this;
|
|
563
|
+
const { op, queries, _with, _orderby, _limit, _offset } = this;
|
|
564
|
+
const sql = [];
|
|
565
|
+
|
|
566
|
+
// WITH
|
|
567
|
+
if (_with.length) sql.push(`WITH ${_with.join(', ')}`);
|
|
563
568
|
|
|
564
569
|
// SUBQUERIES
|
|
565
|
-
|
|
570
|
+
sql.push(queries.join(` ${op} `));
|
|
566
571
|
|
|
567
572
|
// ORDER BY
|
|
568
573
|
if (_orderby.length) sql.push(`ORDER BY ${_orderby.join(', ')}`);
|
|
@@ -576,3 +581,67 @@ export class SetOperation extends Query {
|
|
|
576
581
|
return sql.join(' ');
|
|
577
582
|
}
|
|
578
583
|
}
|
|
584
|
+
|
|
585
|
+
class WithClause {
|
|
586
|
+
/**
|
|
587
|
+
* Instantiate a new WITH clause instance.
|
|
588
|
+
* @param {...import('../types.js').WithExpr} expr The WITH CTE queries.
|
|
589
|
+
*/
|
|
590
|
+
constructor(...expr) {
|
|
591
|
+
this._with = expr;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* Create a new select query with the given SELECT expressions.
|
|
596
|
+
* @param {...import('../types.js').SelectExpr} expr The SELECT expressions.
|
|
597
|
+
* @returns {SelectQuery}
|
|
598
|
+
*/
|
|
599
|
+
select(...expr) {
|
|
600
|
+
return Query.select(...expr).with(...this._with);
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
/**
|
|
604
|
+
* Create a new select query with the given FROM expressions.
|
|
605
|
+
* @param {...import('../types.js').FromExpr} expr The FROM expressions.
|
|
606
|
+
* @returns {SelectQuery}
|
|
607
|
+
*/
|
|
608
|
+
from(...expr) {
|
|
609
|
+
return Query.from(...expr).with(...this._with);
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* Create a new UNION set operation over the given queries.
|
|
614
|
+
* @param {...Query} queries The queries.
|
|
615
|
+
* @returns {SetOperation}
|
|
616
|
+
*/
|
|
617
|
+
union(...queries) {
|
|
618
|
+
return Query.union(...queries).with(...this._with);
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
/**
|
|
622
|
+
* Create a new UNION ALL set operation over the given queries.
|
|
623
|
+
* @param {...Query} queries The queries.
|
|
624
|
+
* @returns {SetOperation}
|
|
625
|
+
*/
|
|
626
|
+
unionAll(...queries) {
|
|
627
|
+
return Query.unionAll(...queries).with(...this._with);
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
/**
|
|
631
|
+
* Create a new INTERSECT set operation over the given queries.
|
|
632
|
+
* @param {...Query} queries The queries.
|
|
633
|
+
* @returns {SetOperation}
|
|
634
|
+
*/
|
|
635
|
+
intersect(...queries) {
|
|
636
|
+
return Query.intersect(...queries).with(...this._with);
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
/**
|
|
640
|
+
* Create a new EXCEPT set operation over the given queries.
|
|
641
|
+
* @param {...Query} queries The queries.
|
|
642
|
+
* @returns {SetOperation}
|
|
643
|
+
*/
|
|
644
|
+
except(...queries) {
|
|
645
|
+
return Query.except(...queries).with(...this._with);
|
|
646
|
+
}
|
|
647
|
+
}
|
package/src/ast/with.js
CHANGED
|
@@ -7,8 +7,12 @@ export class WithClauseNode extends SQLNode {
|
|
|
7
7
|
* Instantiate a with clause node for a common table expression (CTE).
|
|
8
8
|
* @param {string} name The common table expression (CTE) name.
|
|
9
9
|
* @param {Query} query The common table expression (CTE) query.
|
|
10
|
+
* @param {boolean | null} [materialized] The common table expression (CTE)
|
|
11
|
+
* materialization flag. If `true`, forces materialization of the CTE.
|
|
12
|
+
* If `false`, materialization is not performed. Otherwise (for example, if
|
|
13
|
+
* `undefined` or `null`), materialization is decided by the database.
|
|
10
14
|
*/
|
|
11
|
-
constructor(name, query) {
|
|
15
|
+
constructor(name, query, materialized = undefined) {
|
|
12
16
|
super(WITH_CLAUSE);
|
|
13
17
|
/**
|
|
14
18
|
* The common table expression (CTE) name.
|
|
@@ -22,9 +26,19 @@ export class WithClauseNode extends SQLNode {
|
|
|
22
26
|
* @readonly
|
|
23
27
|
*/
|
|
24
28
|
this.query = query;
|
|
29
|
+
/**
|
|
30
|
+
* The common table expression (CTE) materialization flag.
|
|
31
|
+
* @type {boolean | null}
|
|
32
|
+
* @readonly
|
|
33
|
+
*/
|
|
34
|
+
this.materialized = materialized;
|
|
25
35
|
}
|
|
26
36
|
|
|
27
37
|
toString() {
|
|
28
|
-
|
|
38
|
+
const flag = this.materialized;
|
|
39
|
+
const mat = flag === true ? ' MATERIALIZED'
|
|
40
|
+
: flag === false ? ' NOT MATERIALIZED'
|
|
41
|
+
: '';
|
|
42
|
+
return `"${this.name}" AS${mat} (${this.query})`;
|
|
29
43
|
}
|
|
30
44
|
}
|
|
@@ -98,6 +98,15 @@ export function first(expr) {
|
|
|
98
98
|
return aggFn('first', expr);
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
+
/**
|
|
102
|
+
* Compute a geomean aggregate.
|
|
103
|
+
* @param {import('../types.js').ExprValue} expr The expression to aggregate.
|
|
104
|
+
* @returns {AggregateNode} A SQL aggregate function call.
|
|
105
|
+
*/
|
|
106
|
+
export function geomean(expr) {
|
|
107
|
+
return aggFn('geomean', expr);
|
|
108
|
+
}
|
|
109
|
+
|
|
101
110
|
/**
|
|
102
111
|
* Compute a sample kurtosis aggregate.
|
|
103
112
|
* @param {import('../types.js').ExprValue} expr The expression to aggregate.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Query } from '../ast/query.js';
|
|
2
|
+
import { WithClauseNode } from '../ast/with.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Create a common table expression (CTE) to include within a WITH clause.
|
|
6
|
+
* @param {string} name The common table expression (CTE) name.
|
|
7
|
+
* @param {Query} query The common table expression (CTE) query.
|
|
8
|
+
* @param {boolean | null} [materialized] The common table expression (CTE)
|
|
9
|
+
* materialization flag. If `true`, forces materialization of the CTE.
|
|
10
|
+
* If `false`, materialization is not performed. Otherwise (for example, if
|
|
11
|
+
* `undefined` or `null`), materialization is decided by the database.
|
|
12
|
+
* @returns {WithClauseNode}
|
|
13
|
+
*/
|
|
14
|
+
export function cte(name, query, materialized) {
|
|
15
|
+
return new WithClauseNode(name, query, materialized);
|
|
16
|
+
}
|
package/src/index.js
CHANGED
|
@@ -24,10 +24,11 @@ export { VerbatimNode } from './ast/verbatim.js';
|
|
|
24
24
|
export { WindowClauseNode, WindowDefNode, WindowFrameNode, WindowFunctionNode, WindowNode } from './ast/window.js';
|
|
25
25
|
export { WithClauseNode } from './ast/with.js';
|
|
26
26
|
|
|
27
|
-
export { argmax, argmin, arrayAgg, avg, corr, count, covariance, covarPop, entropy, first, 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';
|
|
27
|
+
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
28
|
export { cond } from './functions/case.js';
|
|
29
29
|
export { cast, float32, float64, int32 } from './functions/cast.js';
|
|
30
30
|
export { column } from './functions/column.js';
|
|
31
|
+
export { cte } from './functions/cte.js';
|
|
31
32
|
export { dateBin, dateMonth, dateMonthDay, dateDay, epoch_ms, interval } from './functions/datetime.js';
|
|
32
33
|
export { literal } from './functions/literal.js';
|
|
33
34
|
export { abs, ceil, exp, floor, greatest, isFinite, isInfinite, isNaN, least, ln, log, round, sign, sqrt, trunc } from './functions/numeric.js';
|
package/src/transforms/m4.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { Query } from '../ast/query.js';
|
|
1
|
+
import { Query, isQuery } from '../ast/query.js';
|
|
2
2
|
import { argmax, argmin, max, min } from '../functions/aggregate.js';
|
|
3
3
|
import { int32 } from '../functions/cast.js';
|
|
4
|
+
import { cte } from '../functions/cte.js';
|
|
4
5
|
import { floor } from '../functions/numeric.js';
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -22,12 +23,20 @@ import { floor } from '../functions/numeric.js';
|
|
|
22
23
|
export function m4(input, bin, x, y, groups = []) {
|
|
23
24
|
const pixel = int32(floor(bin));
|
|
24
25
|
|
|
26
|
+
// Below, we treat input as a CTE when it is a query. In this case,
|
|
27
|
+
// we also request that the CTE be explicitly materialized.
|
|
28
|
+
const useCTE = isQuery(input);
|
|
29
|
+
const from = useCTE ? 'input' : input;
|
|
30
|
+
const query = useCTE
|
|
31
|
+
? Query.with(cte(/** @type {string} */(from), input, true))
|
|
32
|
+
: Query;
|
|
33
|
+
|
|
25
34
|
const q = (sel) => Query
|
|
26
|
-
.from(
|
|
35
|
+
.from(from)
|
|
27
36
|
.select(sel)
|
|
28
37
|
.groupby(pixel, groups);
|
|
29
38
|
|
|
30
|
-
return
|
|
39
|
+
return query
|
|
31
40
|
.union(
|
|
32
41
|
q([{ [x]: min(x), [y]: argmin(y, x) }, ...groups]),
|
|
33
42
|
q([{ [x]: max(x), [y]: argmax(y, x) }, ...groups]),
|
package/src/types.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { ColumnRefNode } from './ast/column-ref.js';
|
|
|
2
2
|
import { ExprNode, SQLNode } from './ast/node.js';
|
|
3
3
|
import { TableRefNode } from './ast/table-ref.js';
|
|
4
4
|
import { Query } from './ast/query.js';
|
|
5
|
+
import { WithClauseNode } from './ast/with.js';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Interface representing a dynamic parameter value.
|
|
@@ -80,7 +81,11 @@ export type SelectEntry =
|
|
|
80
81
|
|
|
81
82
|
export type SelectExpr = MaybeArray<SelectEntry>;
|
|
82
83
|
|
|
83
|
-
export type
|
|
84
|
+
export type WithEntry =
|
|
85
|
+
| WithClauseNode
|
|
86
|
+
| Record<string, Query>;
|
|
87
|
+
|
|
88
|
+
export type WithExpr = MaybeArray<WithEntry>;
|
|
84
89
|
|
|
85
90
|
export type FromEntry =
|
|
86
91
|
| string
|
package/vitest.config.ts
ADDED