@uwdata/mosaic-sql 0.10.0 → 0.12.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/dist/mosaic-sql.js +2242 -1064
- package/dist/mosaic-sql.min.js +1 -1
- package/dist/types/ast/aggregate.d.ts +70 -0
- package/dist/types/ast/between-op.d.ts +46 -0
- package/dist/types/ast/binary-op.d.ts +28 -0
- package/dist/types/ast/case.d.ts +68 -0
- package/dist/types/ast/cast.d.ts +21 -0
- package/dist/types/ast/column-param.d.ts +17 -0
- package/dist/types/ast/column-ref.d.ts +39 -0
- package/dist/types/ast/fragment.d.ts +14 -0
- package/dist/types/ast/from.d.ts +21 -0
- package/dist/types/ast/function.d.ts +21 -0
- package/dist/types/ast/in-op.d.ts +21 -0
- package/dist/types/ast/interval.d.ts +21 -0
- package/dist/types/ast/literal.d.ts +15 -0
- package/dist/types/ast/logical-op.d.ts +46 -0
- package/dist/types/ast/node.d.ts +24 -0
- package/dist/types/ast/order-by.d.ts +29 -0
- package/dist/types/ast/param.d.ts +19 -0
- package/dist/types/ast/query.d.ts +268 -0
- package/dist/types/ast/sample.d.ts +42 -0
- package/dist/types/ast/select.d.ts +22 -0
- package/dist/types/ast/table-ref.d.ts +25 -0
- package/dist/types/ast/unary-op.d.ts +39 -0
- package/dist/types/ast/verbatim.d.ts +9 -0
- package/dist/types/ast/window.d.ts +177 -0
- package/dist/types/ast/with.d.ts +22 -0
- package/dist/types/constants.d.ts +38 -0
- package/dist/types/functions/aggregate.d.ts +229 -0
- package/dist/types/functions/case.d.ts +15 -0
- package/dist/types/functions/cast.d.ts +26 -0
- package/dist/types/functions/column.d.ts +9 -0
- package/dist/types/functions/datetime.d.ts +44 -0
- package/dist/types/functions/literal.d.ts +16 -0
- package/dist/types/functions/numeric.d.ts +93 -0
- package/dist/types/functions/operators.d.ts +198 -0
- package/dist/types/functions/order-by.d.ts +17 -0
- package/dist/types/functions/spatial.d.ts +37 -0
- package/dist/types/functions/sql-template-tag.d.ts +16 -0
- package/dist/types/functions/string.d.ts +55 -0
- package/dist/types/functions/table-ref.d.ts +9 -0
- package/dist/types/functions/window.d.ts +87 -0
- package/dist/types/index-types.d.ts +2 -0
- package/dist/types/index.d.ts +53 -0
- package/dist/types/load/create.d.ts +8 -0
- package/dist/types/load/extension.d.ts +1 -0
- package/dist/types/load/load.d.ts +12 -0
- package/dist/types/load/sql-from.d.ts +11 -0
- package/dist/types/transforms/bin-1d.d.ts +14 -0
- package/dist/types/transforms/bin-2d.d.ts +18 -0
- package/dist/types/transforms/bin-linear-1d.d.ts +9 -0
- package/dist/types/transforms/bin-linear-2d.d.ts +18 -0
- package/dist/types/transforms/line-density.d.ts +23 -0
- package/dist/types/transforms/m4.d.ts +18 -0
- package/dist/types/transforms/scales.d.ts +1 -0
- package/dist/types/types.d.ts +59 -0
- package/dist/types/util/ast.d.ts +60 -0
- package/dist/types/util/function.d.ts +54 -0
- package/dist/types/util/string.d.ts +3 -0
- package/dist/types/util/type-check.d.ts +18 -0
- package/dist/types/visit/recurse.d.ts +28 -0
- package/dist/types/visit/rewrite.d.ts +10 -0
- package/dist/types/visit/visitors.d.ts +33 -0
- package/dist/types/visit/walk.d.ts +7 -0
- package/jsconfig.json +11 -0
- package/package.json +6 -4
- package/src/ast/aggregate.js +164 -0
- package/src/ast/between-op.js +75 -0
- package/src/ast/binary-op.js +40 -0
- package/src/ast/case.js +105 -0
- package/src/ast/cast.js +34 -0
- package/src/ast/column-param.js +29 -0
- package/src/ast/column-ref.js +72 -0
- package/src/ast/fragment.js +26 -0
- package/src/ast/from.js +40 -0
- package/src/ast/function.js +34 -0
- package/src/ast/in-op.js +33 -0
- package/src/ast/interval.js +33 -0
- package/src/ast/literal.js +55 -0
- package/src/ast/logical-op.js +67 -0
- package/src/ast/node.js +29 -0
- package/src/ast/order-by.js +48 -0
- package/src/ast/param.js +35 -0
- package/src/ast/query.js +578 -0
- package/src/ast/sample.js +53 -0
- package/src/ast/select.js +44 -0
- package/src/ast/table-ref.js +44 -0
- package/src/ast/unary-op.js +64 -0
- package/src/ast/verbatim.js +26 -0
- package/src/ast/window.js +290 -0
- package/src/ast/with.js +30 -0
- package/src/constants.js +44 -0
- package/src/functions/aggregate.js +335 -0
- package/src/functions/case.js +21 -0
- package/src/functions/cast.js +39 -0
- package/src/functions/column.js +20 -0
- package/src/functions/datetime.js +65 -0
- package/src/functions/literal.js +22 -0
- package/src/functions/numeric.js +139 -0
- package/src/functions/operators.js +298 -0
- package/src/functions/order-by.js +24 -0
- package/src/functions/spatial.js +56 -0
- package/src/functions/sql-template-tag.js +51 -0
- package/src/functions/string.js +82 -0
- package/src/functions/table-ref.js +14 -0
- package/src/functions/window.js +121 -0
- package/src/index-types.ts +2 -0
- package/src/index.js +57 -155
- package/src/load/create.js +10 -2
- package/src/load/load.js +4 -4
- package/src/load/sql-from.js +7 -6
- package/src/transforms/bin-1d.js +21 -0
- package/src/transforms/bin-2d.js +29 -0
- package/src/transforms/bin-linear-1d.js +26 -0
- package/src/transforms/bin-linear-2d.js +71 -0
- package/src/transforms/line-density.js +113 -0
- package/src/transforms/m4.js +38 -0
- package/src/{scales.js → transforms/scales.js} +31 -17
- package/src/types.ts +96 -0
- package/src/util/ast.js +96 -0
- package/src/util/function.js +78 -0
- package/src/util/string.js +16 -0
- package/src/util/type-check.js +29 -0
- package/src/visit/recurse.js +57 -0
- package/src/visit/rewrite.js +32 -0
- package/src/visit/visitors.js +108 -0
- package/src/visit/walk.js +30 -0
- package/tsconfig.json +12 -0
- package/src/Query.js +0 -593
- package/src/aggregates.js +0 -185
- package/src/cast.js +0 -19
- package/src/datetime.js +0 -31
- package/src/desc.js +0 -13
- package/src/expression.js +0 -170
- package/src/functions.js +0 -25
- package/src/literal.js +0 -6
- package/src/operators.js +0 -54
- package/src/ref.js +0 -109
- package/src/repeat.js +0 -3
- package/src/spatial.js +0 -10
- package/src/to-sql.js +0 -52
- package/src/windows.js +0 -239
package/src/Query.js
DELETED
|
@@ -1,593 +0,0 @@
|
|
|
1
|
-
import { isSQLExpression } from './expression.js';
|
|
2
|
-
import { asColumn, asRelation, isColumnRefFor, Ref } from './ref.js';
|
|
3
|
-
|
|
4
|
-
export class Query {
|
|
5
|
-
|
|
6
|
-
static select(...expr) {
|
|
7
|
-
return new Query().select(...expr);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
static from(...expr) {
|
|
11
|
-
return new Query().from(...expr);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
static with(...expr) {
|
|
15
|
-
return new Query().with(...expr);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
static union(...queries) {
|
|
19
|
-
return new SetOperation('UNION', queries.flat());
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
static unionAll(...queries) {
|
|
23
|
-
return new SetOperation('UNION ALL', queries.flat());
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
static intersect(...queries) {
|
|
27
|
-
return new SetOperation('INTERSECT', queries.flat());
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
static except(...queries) {
|
|
31
|
-
return new SetOperation('EXCEPT', queries.flat());
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
static describe(query) {
|
|
35
|
-
const q = query.clone();
|
|
36
|
-
const { clone, toString } = q;
|
|
37
|
-
return Object.assign(q, {
|
|
38
|
-
describe: true,
|
|
39
|
-
clone: () => Query.describe(clone.call(q)),
|
|
40
|
-
toString: () => `DESCRIBE ${toString.call(q)}`
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
constructor() {
|
|
45
|
-
this.query = {
|
|
46
|
-
with: [],
|
|
47
|
-
select: [],
|
|
48
|
-
from: [],
|
|
49
|
-
where: [],
|
|
50
|
-
groupby: [],
|
|
51
|
-
having: [],
|
|
52
|
-
window: [],
|
|
53
|
-
qualify: [],
|
|
54
|
-
orderby: []
|
|
55
|
-
};
|
|
56
|
-
this.cteFor = null;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
clone() {
|
|
60
|
-
const q = new Query();
|
|
61
|
-
q.query = { ...this.query };
|
|
62
|
-
return q;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Retrieve current WITH common table expressions (CTEs).
|
|
67
|
-
* @returns {any[]}
|
|
68
|
-
*//**
|
|
69
|
-
* Add WITH common table expressions (CTEs).
|
|
70
|
-
* @param {...any} expr Expressions to add.
|
|
71
|
-
* @returns {this}
|
|
72
|
-
*/
|
|
73
|
-
with(...expr) {
|
|
74
|
-
const { query } = this;
|
|
75
|
-
if (expr.length === 0) {
|
|
76
|
-
// @ts-ignore
|
|
77
|
-
return query.with;
|
|
78
|
-
} else {
|
|
79
|
-
const list = [];
|
|
80
|
-
const add = (as, q) => {
|
|
81
|
-
const query = q.clone();
|
|
82
|
-
query.cteFor = this;
|
|
83
|
-
list.push({ as, query });
|
|
84
|
-
};
|
|
85
|
-
expr.flat().forEach(e => {
|
|
86
|
-
if (e == null) {
|
|
87
|
-
// do nothing
|
|
88
|
-
} else if (e.as && e.query) {
|
|
89
|
-
add(e.as, e.query);
|
|
90
|
-
} else {
|
|
91
|
-
for (const as in e) {
|
|
92
|
-
add(as, e[as]);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
query.with = query.with.concat(list);
|
|
97
|
-
return this;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Retrieve current SELECT expressions.
|
|
103
|
-
* @returns {any[]}
|
|
104
|
-
*//**
|
|
105
|
-
* Add SELECT expressions.
|
|
106
|
-
* @param {...any} expr Expressions to add.
|
|
107
|
-
* @returns {this}
|
|
108
|
-
*/
|
|
109
|
-
select(...expr) {
|
|
110
|
-
const { query } = this;
|
|
111
|
-
if (expr.length === 0) {
|
|
112
|
-
// @ts-ignore
|
|
113
|
-
return query.select;
|
|
114
|
-
} else {
|
|
115
|
-
const list = [];
|
|
116
|
-
for (const e of expr.flat()) {
|
|
117
|
-
if (e == null) {
|
|
118
|
-
// do nothing
|
|
119
|
-
} else if (typeof e === 'string') {
|
|
120
|
-
list.push({ as: e, expr: asColumn(e) });
|
|
121
|
-
} else if (e instanceof Ref) {
|
|
122
|
-
list.push({ as: e.column, expr: e });
|
|
123
|
-
} else if (Array.isArray(e)) {
|
|
124
|
-
list.push({ as: e[0], expr: e[1] });
|
|
125
|
-
} else {
|
|
126
|
-
for (const as in e) {
|
|
127
|
-
list.push({ as: unquote(as), expr: asColumn(e[as]) });
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const keys = new Set(list.map(x => x.as));
|
|
133
|
-
query.select = query.select
|
|
134
|
-
.filter(x => !keys.has(x.as))
|
|
135
|
-
.concat(list.filter(x => x.expr));
|
|
136
|
-
return this;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
$select(...expr) {
|
|
141
|
-
this.query.select = [];
|
|
142
|
-
return this.select(...expr);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
distinct(value = true) {
|
|
146
|
-
this.query.distinct = !!value;
|
|
147
|
-
return this;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Retrieve current from expressions.
|
|
152
|
-
* @returns {any[]}
|
|
153
|
-
*//**
|
|
154
|
-
* Provide table from expressions.
|
|
155
|
-
* @param {...any} expr
|
|
156
|
-
* @returns {this}
|
|
157
|
-
*/
|
|
158
|
-
from(...expr) {
|
|
159
|
-
const { query } = this;
|
|
160
|
-
if (expr.length === 0) {
|
|
161
|
-
// @ts-ignore
|
|
162
|
-
return query.from;
|
|
163
|
-
} else {
|
|
164
|
-
const list = [];
|
|
165
|
-
expr.flat().forEach(e => {
|
|
166
|
-
if (e == null) {
|
|
167
|
-
// do nothing
|
|
168
|
-
} else if (typeof e === 'string') {
|
|
169
|
-
list.push({ as: e, from: asRelation(e) });
|
|
170
|
-
} else if (e instanceof Ref) {
|
|
171
|
-
list.push({ as: e.table, from: e });
|
|
172
|
-
} else if (isQuery(e) || isSQLExpression(e)) {
|
|
173
|
-
list.push({ from: e });
|
|
174
|
-
} else if (Array.isArray(e)) {
|
|
175
|
-
list.push({ as: unquote(e[0]), from: asRelation(e[1]) });
|
|
176
|
-
} else {
|
|
177
|
-
for (const as in e) {
|
|
178
|
-
list.push({ as: unquote(as), from: asRelation(e[as]) });
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
});
|
|
182
|
-
query.from = query.from.concat(list);
|
|
183
|
-
return this;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
$from(...expr) {
|
|
188
|
-
this.query.from = [];
|
|
189
|
-
return this.from(...expr);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* Retrieve current SAMPLE settings.
|
|
194
|
-
* @returns {any[]}
|
|
195
|
-
*//**
|
|
196
|
-
* Set SAMPLE settings.
|
|
197
|
-
* @param {number|object} value The percentage or number of rows to sample.
|
|
198
|
-
* @param {string} [method] The sampling method to use.
|
|
199
|
-
* @returns {this}
|
|
200
|
-
*/
|
|
201
|
-
sample(value, method) {
|
|
202
|
-
const { query } = this;
|
|
203
|
-
if (arguments.length === 0) {
|
|
204
|
-
// @ts-ignore
|
|
205
|
-
return query.sample;
|
|
206
|
-
} else {
|
|
207
|
-
let spec = value;
|
|
208
|
-
if (typeof value === 'number') {
|
|
209
|
-
spec = value > 0 && value < 1
|
|
210
|
-
? { perc: 100 * value, method }
|
|
211
|
-
: { rows: Math.round(value), method };
|
|
212
|
-
}
|
|
213
|
-
query.sample = spec;
|
|
214
|
-
return this;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* Retrieve current WHERE expressions.
|
|
220
|
-
* @returns {any[]}
|
|
221
|
-
*//**
|
|
222
|
-
* Add WHERE expressions.
|
|
223
|
-
* @param {...any} expr Expressions to add.
|
|
224
|
-
* @returns {this}
|
|
225
|
-
*/
|
|
226
|
-
where(...expr) {
|
|
227
|
-
const { query } = this;
|
|
228
|
-
if (expr.length === 0) {
|
|
229
|
-
// @ts-ignore
|
|
230
|
-
return query.where;
|
|
231
|
-
} else {
|
|
232
|
-
query.where = query.where.concat(
|
|
233
|
-
expr.flat().filter(x => x)
|
|
234
|
-
);
|
|
235
|
-
return this;
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
$where(...expr) {
|
|
240
|
-
this.query.where = [];
|
|
241
|
-
return this.where(...expr);
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* Retrieve current GROUP BY expressions.
|
|
246
|
-
* @returns {any[]}
|
|
247
|
-
*//**
|
|
248
|
-
* Add GROUP BY expressions.
|
|
249
|
-
* @param {...any} expr Expressions to add.
|
|
250
|
-
* @returns {this}
|
|
251
|
-
*/
|
|
252
|
-
groupby(...expr) {
|
|
253
|
-
const { query } = this;
|
|
254
|
-
if (expr.length === 0) {
|
|
255
|
-
// @ts-ignore
|
|
256
|
-
return query.groupby;
|
|
257
|
-
} else {
|
|
258
|
-
query.groupby = query.groupby.concat(
|
|
259
|
-
expr.flat().filter(x => x).map(asColumn)
|
|
260
|
-
);
|
|
261
|
-
return this;
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
$groupby(...expr) {
|
|
266
|
-
this.query.groupby = [];
|
|
267
|
-
return this.groupby(...expr);
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* Retrieve current HAVING expressions.
|
|
272
|
-
* @returns {any[]}
|
|
273
|
-
*//**
|
|
274
|
-
* Add HAVING expressions.
|
|
275
|
-
* @param {...any} expr Expressions to add.
|
|
276
|
-
* @returns {this}
|
|
277
|
-
*/
|
|
278
|
-
having(...expr) {
|
|
279
|
-
const { query } = this;
|
|
280
|
-
if (expr.length === 0) {
|
|
281
|
-
// @ts-ignore
|
|
282
|
-
return query.having;
|
|
283
|
-
} else {
|
|
284
|
-
query.having = query.having.concat(
|
|
285
|
-
expr.flat().filter(x => x)
|
|
286
|
-
);
|
|
287
|
-
return this;
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
/**
|
|
292
|
-
* Retrieve current WINDOW definitions.
|
|
293
|
-
* @returns {any[]}
|
|
294
|
-
*//**
|
|
295
|
-
* Add WINDOW definitions.
|
|
296
|
-
* @param {...any} expr Expressions to add.
|
|
297
|
-
* @returns {this}
|
|
298
|
-
*/
|
|
299
|
-
window(...expr) {
|
|
300
|
-
const { query } = this;
|
|
301
|
-
if (expr.length === 0) {
|
|
302
|
-
// @ts-ignore
|
|
303
|
-
return query.window;
|
|
304
|
-
} else {
|
|
305
|
-
const list = [];
|
|
306
|
-
expr.flat().forEach(e => {
|
|
307
|
-
if (e == null) {
|
|
308
|
-
// do nothing
|
|
309
|
-
} else {
|
|
310
|
-
for (const as in e) {
|
|
311
|
-
list.push({ as: unquote(as), expr: e[as] });
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
});
|
|
315
|
-
query.window = query.window.concat(list);
|
|
316
|
-
return this;
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
/**
|
|
321
|
-
* Retrieve current QUALIFY expressions.
|
|
322
|
-
* @returns {any[]}
|
|
323
|
-
*//**
|
|
324
|
-
* Add QUALIFY expressions.
|
|
325
|
-
* @param {...any} expr Expressions to add.
|
|
326
|
-
* @returns {this}
|
|
327
|
-
*/
|
|
328
|
-
qualify(...expr) {
|
|
329
|
-
const { query } = this;
|
|
330
|
-
if (expr.length === 0) {
|
|
331
|
-
// @ts-ignore
|
|
332
|
-
return query.qualify;
|
|
333
|
-
} else {
|
|
334
|
-
query.qualify = query.qualify.concat(
|
|
335
|
-
expr.flat().filter(x => x)
|
|
336
|
-
);
|
|
337
|
-
return this;
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
/**
|
|
342
|
-
* Retrieve current ORDER BY expressions.
|
|
343
|
-
* @returns {any[]}
|
|
344
|
-
*//**
|
|
345
|
-
* Add ORDER BY expressions.
|
|
346
|
-
* @param {...any} expr Expressions to add.
|
|
347
|
-
* @returns {this}
|
|
348
|
-
*/
|
|
349
|
-
orderby(...expr) {
|
|
350
|
-
const { query } = this;
|
|
351
|
-
if (expr.length === 0) {
|
|
352
|
-
// @ts-ignore
|
|
353
|
-
return query.orderby;
|
|
354
|
-
} else {
|
|
355
|
-
query.orderby = query.orderby.concat(
|
|
356
|
-
expr.flat().filter(x => x).map(asColumn)
|
|
357
|
-
);
|
|
358
|
-
return this;
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
/**
|
|
363
|
-
* Retrieve current LIMIT value.
|
|
364
|
-
* @returns {number|null}
|
|
365
|
-
*//**
|
|
366
|
-
* Set the query result LIMIT.
|
|
367
|
-
* @param {number} value The limit value.
|
|
368
|
-
* @returns {this}
|
|
369
|
-
*/
|
|
370
|
-
limit(value) {
|
|
371
|
-
const { query } = this;
|
|
372
|
-
if (arguments.length === 0) {
|
|
373
|
-
return query.limit;
|
|
374
|
-
} else {
|
|
375
|
-
query.limit = Number.isFinite(value) ? value : undefined;
|
|
376
|
-
return this;
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
/**
|
|
381
|
-
* Retrieve current OFFSET value.
|
|
382
|
-
* @returns {number|null}
|
|
383
|
-
*//**
|
|
384
|
-
* Set the query result OFFSET.
|
|
385
|
-
* @param {number} value The offset value.
|
|
386
|
-
* @returns {this}
|
|
387
|
-
*/
|
|
388
|
-
offset(value) {
|
|
389
|
-
const { query } = this;
|
|
390
|
-
if (arguments.length === 0) {
|
|
391
|
-
return query.offset;
|
|
392
|
-
} else {
|
|
393
|
-
query.offset = Number.isFinite(value) ? value : undefined;
|
|
394
|
-
return this;
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
get subqueries() {
|
|
399
|
-
const { query, cteFor } = this;
|
|
400
|
-
const ctes = (cteFor?.query || query).with;
|
|
401
|
-
const cte = ctes?.reduce((o, {as, query}) => (o[as] = query, o), {});
|
|
402
|
-
const q = [];
|
|
403
|
-
query.from.forEach(({ from }) => {
|
|
404
|
-
if (isQuery(from)) {
|
|
405
|
-
q.push(from);
|
|
406
|
-
} else if (cte[from.table]) {
|
|
407
|
-
const sub = cte[from.table];
|
|
408
|
-
q.push(sub);
|
|
409
|
-
}
|
|
410
|
-
});
|
|
411
|
-
return q;
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
toString() {
|
|
415
|
-
const {
|
|
416
|
-
with: cte, select, distinct, from, sample, where, groupby,
|
|
417
|
-
having, window, qualify, orderby, limit, offset
|
|
418
|
-
} = this.query;
|
|
419
|
-
|
|
420
|
-
const sql = [];
|
|
421
|
-
|
|
422
|
-
// WITH
|
|
423
|
-
if (cte.length) {
|
|
424
|
-
const list = cte.map(({ as, query })=> `"${as}" AS (${query})`);
|
|
425
|
-
sql.push(`WITH ${list.join(', ')}`);
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
// SELECT
|
|
429
|
-
const sels = select.map(
|
|
430
|
-
({ as, expr }) => isColumnRefFor(expr, as) && !expr.table
|
|
431
|
-
? `${expr}`
|
|
432
|
-
: `${expr} AS "${as}"`
|
|
433
|
-
);
|
|
434
|
-
sql.push(`SELECT${distinct ? ' DISTINCT' : ''} ${sels.join(', ')}`);
|
|
435
|
-
|
|
436
|
-
// FROM
|
|
437
|
-
if (from.length) {
|
|
438
|
-
const rels = from.map(({ as, from }) => {
|
|
439
|
-
const rel = isQuery(from) ? `(${from})` : `${from}`;
|
|
440
|
-
return !as || as === from.table ? rel : `${rel} AS "${as}"`;
|
|
441
|
-
});
|
|
442
|
-
sql.push(`FROM ${rels.join(', ')}`);
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
// WHERE
|
|
446
|
-
if (where.length) {
|
|
447
|
-
const clauses = where.map(String).filter(x => x).join(' AND ');
|
|
448
|
-
if (clauses) sql.push(`WHERE ${clauses}`);
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
// SAMPLE
|
|
452
|
-
if (sample) {
|
|
453
|
-
const { rows, perc, method, seed } = sample;
|
|
454
|
-
const size = rows ? `${rows} ROWS` : `${perc} PERCENT`;
|
|
455
|
-
const how = method ? ` (${method}${seed != null ? `, ${seed}` : ''})` : '';
|
|
456
|
-
sql.push(`USING SAMPLE ${size}${how}`);
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
// GROUP BY
|
|
460
|
-
if (groupby.length) {
|
|
461
|
-
sql.push(`GROUP BY ${groupby.join(', ')}`);
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
// HAVING
|
|
465
|
-
if (having.length) {
|
|
466
|
-
const clauses = having.map(String).filter(x => x).join(' AND ');
|
|
467
|
-
if (clauses) sql.push(`HAVING ${clauses}`);
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
// WINDOW
|
|
471
|
-
if (window.length) {
|
|
472
|
-
const windows = window.map(({ as, expr }) => `"${as}" AS (${expr})`);
|
|
473
|
-
sql.push(`WINDOW ${windows.join(', ')}`);
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
// QUALIFY
|
|
477
|
-
if (qualify.length) {
|
|
478
|
-
const clauses = qualify.map(String).filter(x => x).join(' AND ');
|
|
479
|
-
if (clauses) sql.push(`QUALIFY ${clauses}`);
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
// ORDER BY
|
|
483
|
-
if (orderby.length) {
|
|
484
|
-
sql.push(`ORDER BY ${orderby.join(', ')}`);
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
// LIMIT
|
|
488
|
-
if (Number.isFinite(limit)) {
|
|
489
|
-
sql.push(`LIMIT ${limit}`);
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
// OFFSET
|
|
493
|
-
if (Number.isFinite(offset)) {
|
|
494
|
-
sql.push(`OFFSET ${offset}`);
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
return sql.join(' ');
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
export class SetOperation {
|
|
502
|
-
constructor(op, queries) {
|
|
503
|
-
this.op = op;
|
|
504
|
-
this.queries = queries.map(q => q.clone());
|
|
505
|
-
this.query = { orderby: [] };
|
|
506
|
-
this.cteFor = null;
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
clone() {
|
|
510
|
-
const q = new SetOperation(this.op, this.queries);
|
|
511
|
-
q.query = { ...this.query };
|
|
512
|
-
return q;
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
orderby(...expr) {
|
|
516
|
-
const { query } = this;
|
|
517
|
-
if (expr.length === 0) {
|
|
518
|
-
return query.orderby;
|
|
519
|
-
} else {
|
|
520
|
-
query.orderby = query.orderby.concat(
|
|
521
|
-
expr.flat().filter(x => x).map(asColumn)
|
|
522
|
-
);
|
|
523
|
-
return this;
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
limit(value) {
|
|
528
|
-
const { query } = this;
|
|
529
|
-
if (arguments.length === 0) {
|
|
530
|
-
return query.limit;
|
|
531
|
-
} else {
|
|
532
|
-
query.limit = Number.isFinite(value) ? value : undefined;
|
|
533
|
-
return this;
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
offset(value) {
|
|
538
|
-
const { query } = this;
|
|
539
|
-
if (arguments.length === 0) {
|
|
540
|
-
return query.offset;
|
|
541
|
-
} else {
|
|
542
|
-
query.offset = Number.isFinite(value) ? value : undefined;
|
|
543
|
-
return this;
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
get subqueries() {
|
|
548
|
-
const { queries, cteFor } = this;
|
|
549
|
-
if (cteFor) queries.forEach(q => q.cteFor = cteFor);
|
|
550
|
-
return queries;
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
toString() {
|
|
554
|
-
const { op, queries, query: { orderby, limit, offset } } = this;
|
|
555
|
-
|
|
556
|
-
// SUBQUERIES
|
|
557
|
-
const sql = [ queries.join(` ${op} `) ];
|
|
558
|
-
|
|
559
|
-
// ORDER BY
|
|
560
|
-
if (orderby.length) {
|
|
561
|
-
sql.push(`ORDER BY ${orderby.join(', ')}`);
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
// LIMIT
|
|
565
|
-
if (Number.isFinite(limit)) {
|
|
566
|
-
sql.push(`LIMIT ${limit}`);
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
// OFFSET
|
|
570
|
-
if (Number.isFinite(offset)) {
|
|
571
|
-
sql.push(`OFFSET ${offset}`);
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
return sql.join(' ');
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
export function isQuery(value) {
|
|
579
|
-
return value instanceof Query || value instanceof SetOperation;
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
export function isDescribeQuery(value) {
|
|
583
|
-
// @ts-ignore
|
|
584
|
-
return isQuery(value) && value.describe;
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
function unquote(s) {
|
|
588
|
-
return isDoubleQuoted(s) ? s.slice(1, -1) : s;
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
function isDoubleQuoted(s) {
|
|
592
|
-
return s[0] === '"' && s[s.length-1] === '"';
|
|
593
|
-
}
|