data-finder-ts 0.1.3 → 0.1.5
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 +17 -55
- package/dist/chunk-BGEX377Q.js +230 -0
- package/dist/chunk-BGEX377Q.js.map +1 -0
- package/dist/chunk-BKPWV3OF.js +962 -0
- package/dist/chunk-BKPWV3OF.js.map +1 -0
- package/dist/{chunk-EYXBYV2X.js → chunk-GPHWC533.js} +2 -2
- package/dist/chunk-KAK75RVS.js +198 -0
- package/dist/chunk-KAK75RVS.js.map +1 -0
- package/dist/chunk-MGEL5RWM.js +628 -0
- package/dist/chunk-MGEL5RWM.js.map +1 -0
- package/dist/chunk-PF6EJZHB.js +1015 -0
- package/dist/chunk-PF6EJZHB.js.map +1 -0
- package/dist/datafinder/attribute.cjs +595 -18
- package/dist/datafinder/attribute.cjs.map +1 -1
- package/dist/datafinder/attribute.d.cts +73 -10
- package/dist/datafinder/attribute.d.ts +73 -10
- package/dist/datafinder/attribute.js +2 -2
- package/dist/datafinder/runner.cjs +1589 -288
- package/dist/datafinder/runner.cjs.map +1 -1
- package/dist/datafinder/runner.d.cts +41 -7
- package/dist/datafinder/runner.d.ts +41 -7
- package/dist/datafinder/runner.js +12 -6
- package/dist/datafinder/sql-generator.cjs +1484 -281
- package/dist/datafinder/sql-generator.cjs.map +1 -1
- package/dist/datafinder/sql-generator.d.cts +19 -14
- package/dist/datafinder/sql-generator.d.ts +19 -14
- package/dist/datafinder/sql-generator.js +9 -7
- package/dist/datafinder/typed-attributes.cjs +856 -93
- package/dist/datafinder/typed-attributes.cjs.map +1 -1
- package/dist/datafinder/typed-attributes.d.cts +3 -135
- package/dist/datafinder/typed-attributes.d.ts +3 -135
- package/dist/datafinder/typed-attributes.js +3 -3
- package/dist/dialect-CogGPm_y.d.cts +38 -0
- package/dist/dialect-aaG1bDi5.d.ts +38 -0
- package/dist/index.cjs +2080 -480
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +119 -14
- package/dist/index.d.ts +119 -14
- package/dist/index.js +362 -12
- package/dist/index.js.map +1 -1
- package/dist/model/milestoning.cjs +529 -0
- package/dist/model/milestoning.cjs.map +1 -1
- package/dist/model/milestoning.js +2 -2
- package/dist/model/relational.cjs +608 -12
- package/dist/model/relational.cjs.map +1 -1
- package/dist/model/relational.d.cts +456 -47
- package/dist/model/relational.d.ts +456 -47
- package/dist/model/relational.js +61 -3
- package/dist/typed-attributes-CUTf_6Ru.d.ts +328 -0
- package/dist/typed-attributes-CdWXq_78.d.cts +328 -0
- package/package.json +5 -2
- package/dist/chunk-3SSWFES4.js +0 -448
- package/dist/chunk-3SSWFES4.js.map +0 -1
- package/dist/chunk-5K2Z3YDY.js +0 -393
- package/dist/chunk-5K2Z3YDY.js.map +0 -1
- package/dist/chunk-6QTCGJWX.js +0 -98
- package/dist/chunk-6QTCGJWX.js.map +0 -1
- package/dist/chunk-DFYZVBII.js +0 -652
- package/dist/chunk-DFYZVBII.js.map +0 -1
- package/dist/chunk-V647VNMY.js +0 -135
- package/dist/chunk-V647VNMY.js.map +0 -1
- /package/dist/{chunk-EYXBYV2X.js.map → chunk-GPHWC533.js.map} +0 -0
|
@@ -20,36 +20,70 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/datafinder/sql-generator.ts
|
|
21
21
|
var sql_generator_exports = {};
|
|
22
22
|
__export(sql_generator_exports, {
|
|
23
|
-
|
|
23
|
+
arithmeticNeedsParentheses: () => arithmeticNeedsParentheses,
|
|
24
24
|
buildQueryOperation: () => buildQueryOperation,
|
|
25
|
+
needsParentheses: () => needsParentheses,
|
|
25
26
|
selectSqlToString: () => selectSqlToString,
|
|
26
27
|
toSql: () => toSql
|
|
27
28
|
});
|
|
28
29
|
module.exports = __toCommonJS(sql_generator_exports);
|
|
29
30
|
|
|
30
31
|
// src/model/relational.ts
|
|
32
|
+
var LIKE_ESCAPE = "!";
|
|
33
|
+
function escapeLike(value) {
|
|
34
|
+
return value.replaceAll(LIKE_ESCAPE, LIKE_ESCAPE + LIKE_ESCAPE).replaceAll("%", LIKE_ESCAPE + "%").replaceAll("_", LIKE_ESCAPE + "_");
|
|
35
|
+
}
|
|
31
36
|
var RelationalOperationElement = class {
|
|
32
37
|
};
|
|
33
38
|
var Operation = class extends RelationalOperationElement {
|
|
34
|
-
|
|
39
|
+
/** Name this column in the result: `f.price().sum().alias('Total')`, `f.age().gt(30).alias('Adult')`. */
|
|
40
|
+
alias(name) {
|
|
41
|
+
return new Alias(this, name);
|
|
42
|
+
}
|
|
43
|
+
and(other) {
|
|
35
44
|
return new LogicalOperation(this, "AND" /* AND */, other);
|
|
36
45
|
}
|
|
46
|
+
/** Combine with `other` using OR. A chain reads left to right: `a.or(b).and(c)` is `(a OR b) AND c`. */
|
|
47
|
+
or(other) {
|
|
48
|
+
return new LogicalOperation(this, "OR" /* OR */, other);
|
|
49
|
+
}
|
|
37
50
|
};
|
|
38
51
|
var NoOperation = class extends Operation {
|
|
39
|
-
|
|
52
|
+
and(other) {
|
|
40
53
|
return other;
|
|
41
54
|
}
|
|
55
|
+
/** No filter matches every row, so OR-ing anything with it still matches every row. */
|
|
56
|
+
or(_other) {
|
|
57
|
+
return this;
|
|
58
|
+
}
|
|
42
59
|
};
|
|
43
60
|
var ConstantOperation = class extends RelationalOperationElement {
|
|
61
|
+
/** Name this column in the result. */
|
|
62
|
+
alias(name) {
|
|
63
|
+
return new Alias(this, name);
|
|
64
|
+
}
|
|
65
|
+
/** Sort by this expression, smallest first. */
|
|
66
|
+
ascending() {
|
|
67
|
+
return new SortOperation(this, "ASC" /* ASC */);
|
|
68
|
+
}
|
|
69
|
+
/** Sort by this expression, largest first. */
|
|
70
|
+
descending() {
|
|
71
|
+
return new SortOperation(this, "DESC" /* DESC */);
|
|
72
|
+
}
|
|
44
73
|
};
|
|
45
|
-
var
|
|
74
|
+
var NumericConstantOperation = class extends ConstantOperation {
|
|
75
|
+
arithmeticOperand() {
|
|
76
|
+
return this;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
var IntegerConstantOperation = class extends NumericConstantOperation {
|
|
46
80
|
constructor(value) {
|
|
47
81
|
super();
|
|
48
82
|
this.value = value;
|
|
49
83
|
}
|
|
50
84
|
value;
|
|
51
85
|
};
|
|
52
|
-
var FloatConstantOperation = class extends
|
|
86
|
+
var FloatConstantOperation = class extends NumericConstantOperation {
|
|
53
87
|
constructor(value) {
|
|
54
88
|
super();
|
|
55
89
|
this.value = value;
|
|
@@ -63,6 +97,9 @@ var StringConstantOperation = class extends ConstantOperation {
|
|
|
63
97
|
}
|
|
64
98
|
value;
|
|
65
99
|
};
|
|
100
|
+
var DATE_ONLY_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
|
|
101
|
+
var DateOnly = class extends Date {
|
|
102
|
+
};
|
|
66
103
|
var DateConstantOperation = class extends ConstantOperation {
|
|
67
104
|
constructor(value) {
|
|
68
105
|
super();
|
|
@@ -77,7 +114,7 @@ var DateTimeConstantOperation = class extends ConstantOperation {
|
|
|
77
114
|
}
|
|
78
115
|
value;
|
|
79
116
|
};
|
|
80
|
-
var DecimalConstantOperation = class extends
|
|
117
|
+
var DecimalConstantOperation = class extends NumericConstantOperation {
|
|
81
118
|
constructor(value) {
|
|
82
119
|
super();
|
|
83
120
|
this.value = value;
|
|
@@ -111,6 +148,20 @@ var IsNullOperation = class extends UnaryOperation {
|
|
|
111
148
|
};
|
|
112
149
|
var IsNotNullOperation = class extends UnaryOperation {
|
|
113
150
|
};
|
|
151
|
+
var InOperation = class extends UnaryOperation {
|
|
152
|
+
constructor(element, values) {
|
|
153
|
+
super(element);
|
|
154
|
+
this.values = values;
|
|
155
|
+
}
|
|
156
|
+
values;
|
|
157
|
+
};
|
|
158
|
+
var NotInOperation = class extends UnaryOperation {
|
|
159
|
+
constructor(element, values) {
|
|
160
|
+
super(element);
|
|
161
|
+
this.values = values;
|
|
162
|
+
}
|
|
163
|
+
values;
|
|
164
|
+
};
|
|
114
165
|
var ComparisonOperation = class extends BinaryOperation {
|
|
115
166
|
constructor(left, operator, right) {
|
|
116
167
|
super(left, right);
|
|
@@ -134,21 +185,41 @@ var WindowSpecification = class {
|
|
|
134
185
|
orderBy;
|
|
135
186
|
};
|
|
136
187
|
var AggregateOperation = class _AggregateOperation extends UnaryOperation {
|
|
137
|
-
constructor(element, operator, displayName, window) {
|
|
188
|
+
constructor(element, operator, displayName, window, separator, orderBy = []) {
|
|
138
189
|
super(element);
|
|
139
190
|
this.operator = operator;
|
|
140
191
|
this.displayName = displayName;
|
|
141
192
|
this.window = window;
|
|
193
|
+
this.separator = separator;
|
|
194
|
+
this.orderBy = orderBy;
|
|
142
195
|
}
|
|
143
196
|
operator;
|
|
144
197
|
displayName;
|
|
145
198
|
window;
|
|
199
|
+
separator;
|
|
200
|
+
orderBy;
|
|
201
|
+
/** Sort by this expression, smallest first. */
|
|
202
|
+
ascending() {
|
|
203
|
+
return new SortOperation(this, "ASC" /* ASC */);
|
|
204
|
+
}
|
|
205
|
+
/** Sort by this expression, largest first. */
|
|
206
|
+
descending() {
|
|
207
|
+
return new SortOperation(this, "DESC" /* DESC */);
|
|
208
|
+
}
|
|
209
|
+
arithmeticOperand() {
|
|
210
|
+
return this;
|
|
211
|
+
}
|
|
212
|
+
comparisonOperand() {
|
|
213
|
+
return this;
|
|
214
|
+
}
|
|
146
215
|
over(partitionBy, orderBy) {
|
|
147
216
|
return new _AggregateOperation(
|
|
148
217
|
this.element,
|
|
149
218
|
this.operator,
|
|
150
219
|
this.displayName,
|
|
151
|
-
new WindowSpecification(partitionBy ?? [], orderBy ?? [])
|
|
220
|
+
new WindowSpecification(partitionBy ?? [], orderBy ?? []),
|
|
221
|
+
this.separator,
|
|
222
|
+
this.orderBy
|
|
152
223
|
);
|
|
153
224
|
}
|
|
154
225
|
};
|
|
@@ -166,6 +237,14 @@ var WindowFunctionOperation = class _WindowFunctionOperation extends UnaryOperat
|
|
|
166
237
|
secondArg;
|
|
167
238
|
extraArgs;
|
|
168
239
|
window;
|
|
240
|
+
/** Sort by this expression, smallest first. */
|
|
241
|
+
ascending() {
|
|
242
|
+
return new SortOperation(this, "ASC" /* ASC */);
|
|
243
|
+
}
|
|
244
|
+
/** Sort by this expression, largest first. */
|
|
245
|
+
descending() {
|
|
246
|
+
return new SortOperation(this, "DESC" /* DESC */);
|
|
247
|
+
}
|
|
169
248
|
over(partitionBy, orderBy) {
|
|
170
249
|
return new _WindowFunctionOperation(
|
|
171
250
|
this.element,
|
|
@@ -189,7 +268,38 @@ var ScalarFunctionOperation = class extends UnaryOperation {
|
|
|
189
268
|
displayName;
|
|
190
269
|
secondArg;
|
|
191
270
|
extraArgs;
|
|
271
|
+
/** Sort by this expression, smallest first. */
|
|
272
|
+
ascending() {
|
|
273
|
+
return new SortOperation(this, "ASC" /* ASC */);
|
|
274
|
+
}
|
|
275
|
+
/** Sort by this expression, largest first. */
|
|
276
|
+
descending() {
|
|
277
|
+
return new SortOperation(this, "DESC" /* DESC */);
|
|
278
|
+
}
|
|
279
|
+
/** This expression as an operand of a comparison. */
|
|
280
|
+
comparisonOperand() {
|
|
281
|
+
return this;
|
|
282
|
+
}
|
|
283
|
+
arithmeticOperand() {
|
|
284
|
+
return this;
|
|
285
|
+
}
|
|
286
|
+
/** Only a function that gives a number can be used in arithmetic. */
|
|
287
|
+
assertNumeric() {
|
|
288
|
+
if (!NUMERIC_FUNCTIONS.has(this.func)) {
|
|
289
|
+
throw new TypeError(`${this.func} does not give a number, so it cannot be used in arithmetic`);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
192
292
|
};
|
|
293
|
+
var NUMERIC_FUNCTIONS = /* @__PURE__ */ new Set([
|
|
294
|
+
"ABS" /* ABS */,
|
|
295
|
+
"CEILING" /* CEILING */,
|
|
296
|
+
"FLOOR" /* FLOOR */,
|
|
297
|
+
"MOD" /* MOD */,
|
|
298
|
+
"POWER" /* POWER */,
|
|
299
|
+
"SQRT" /* SQRT */,
|
|
300
|
+
"ROUND" /* ROUND */,
|
|
301
|
+
"LENGTH" /* LENGTH */
|
|
302
|
+
]);
|
|
193
303
|
var DateExtractOperation = class extends UnaryOperation {
|
|
194
304
|
constructor(element, part, displayName) {
|
|
195
305
|
super(element);
|
|
@@ -198,6 +308,34 @@ var DateExtractOperation = class extends UnaryOperation {
|
|
|
198
308
|
}
|
|
199
309
|
part;
|
|
200
310
|
displayName;
|
|
311
|
+
/** Sort by this expression, smallest first. */
|
|
312
|
+
ascending() {
|
|
313
|
+
return new SortOperation(this, "ASC" /* ASC */);
|
|
314
|
+
}
|
|
315
|
+
/** Sort by this expression, largest first. */
|
|
316
|
+
descending() {
|
|
317
|
+
return new SortOperation(this, "DESC" /* DESC */);
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
var DateTruncOperation = class extends UnaryOperation {
|
|
321
|
+
constructor(element, part, displayName) {
|
|
322
|
+
super(element);
|
|
323
|
+
this.part = part;
|
|
324
|
+
this.displayName = displayName;
|
|
325
|
+
}
|
|
326
|
+
part;
|
|
327
|
+
displayName;
|
|
328
|
+
/** Sort by this expression, earliest first. */
|
|
329
|
+
ascending() {
|
|
330
|
+
return new SortOperation(this, "ASC" /* ASC */);
|
|
331
|
+
}
|
|
332
|
+
/** Sort by this expression, latest first. */
|
|
333
|
+
descending() {
|
|
334
|
+
return new SortOperation(this, "DESC" /* DESC */);
|
|
335
|
+
}
|
|
336
|
+
comparisonOperand() {
|
|
337
|
+
return this;
|
|
338
|
+
}
|
|
201
339
|
};
|
|
202
340
|
var DateArithmeticOperation = class extends UnaryOperation {
|
|
203
341
|
constructor(element, n, unit, isAdd = true, displayName) {
|
|
@@ -211,6 +349,14 @@ var DateArithmeticOperation = class extends UnaryOperation {
|
|
|
211
349
|
unit;
|
|
212
350
|
isAdd;
|
|
213
351
|
displayName;
|
|
352
|
+
/** Sort by this expression, smallest first. */
|
|
353
|
+
ascending() {
|
|
354
|
+
return new SortOperation(this, "ASC" /* ASC */);
|
|
355
|
+
}
|
|
356
|
+
/** Sort by this expression, largest first. */
|
|
357
|
+
descending() {
|
|
358
|
+
return new SortOperation(this, "DESC" /* DESC */);
|
|
359
|
+
}
|
|
214
360
|
};
|
|
215
361
|
var DateDiffOperation = class extends UnaryOperation {
|
|
216
362
|
constructor(element, other, unit, displayName) {
|
|
@@ -222,20 +368,31 @@ var DateDiffOperation = class extends UnaryOperation {
|
|
|
222
368
|
other;
|
|
223
369
|
unit;
|
|
224
370
|
displayName;
|
|
371
|
+
/** Sort by this expression, smallest first. */
|
|
372
|
+
ascending() {
|
|
373
|
+
return new SortOperation(this, "ASC" /* ASC */);
|
|
374
|
+
}
|
|
375
|
+
/** Sort by this expression, largest first. */
|
|
376
|
+
descending() {
|
|
377
|
+
return new SortOperation(this, "DESC" /* DESC */);
|
|
378
|
+
}
|
|
225
379
|
};
|
|
226
380
|
var Column = class extends RelationalOperationElement {
|
|
227
|
-
constructor(name, type, owner, primaryKey = false) {
|
|
381
|
+
constructor(name, type, owner, primaryKey = false, nullable = true) {
|
|
228
382
|
super();
|
|
229
383
|
this.name = name;
|
|
230
384
|
this.type = type;
|
|
231
385
|
this.owner = owner;
|
|
232
386
|
this.primaryKey = primaryKey;
|
|
387
|
+
this.nullable = nullable && !primaryKey;
|
|
233
388
|
}
|
|
234
389
|
name;
|
|
235
390
|
type;
|
|
236
391
|
owner;
|
|
237
392
|
primaryKey;
|
|
238
393
|
table;
|
|
394
|
+
/** Whether the column may hold NULL. As in Legend, a primary key is never null. */
|
|
395
|
+
nullable;
|
|
239
396
|
};
|
|
240
397
|
var Table = class {
|
|
241
398
|
constructor(name, columns, schema) {
|
|
@@ -264,13 +421,28 @@ var Table = class {
|
|
|
264
421
|
}
|
|
265
422
|
};
|
|
266
423
|
var ColumnWithJoin = class extends RelationalOperationElement {
|
|
267
|
-
|
|
424
|
+
/**
|
|
425
|
+
* `embedded` is an alternate reference to a flat (denormalized) column on the owning table that
|
|
426
|
+
* holds the same value without the join; the SQL generator uses it when the join can be elided.
|
|
427
|
+
*/
|
|
428
|
+
constructor(column, parent, embedded, _optional = false) {
|
|
268
429
|
super();
|
|
269
430
|
this.column = column;
|
|
270
431
|
this.parent = parent;
|
|
432
|
+
this.embedded = embedded;
|
|
433
|
+
this._optional = _optional;
|
|
271
434
|
}
|
|
272
435
|
column;
|
|
273
436
|
parent;
|
|
437
|
+
embedded;
|
|
438
|
+
_optional;
|
|
439
|
+
/** Whether the value can be missing: its property is optional, or a navigation on the way to it is. */
|
|
440
|
+
get optional() {
|
|
441
|
+
for (let node = this.parent; node !== void 0; node = node.parent) {
|
|
442
|
+
if (node.optional) return true;
|
|
443
|
+
}
|
|
444
|
+
return this._optional;
|
|
445
|
+
}
|
|
274
446
|
};
|
|
275
447
|
var SortOperation = class {
|
|
276
448
|
constructor(column, direction) {
|
|
@@ -286,19 +458,366 @@ var CountAllOperation = class extends RelationalOperationElement {
|
|
|
286
458
|
this.table = table;
|
|
287
459
|
}
|
|
288
460
|
table;
|
|
461
|
+
/** Name this column in the result. */
|
|
462
|
+
alias(name) {
|
|
463
|
+
return new Alias(this, name);
|
|
464
|
+
}
|
|
465
|
+
/** Sort by this expression, smallest first. */
|
|
466
|
+
ascending() {
|
|
467
|
+
return new SortOperation(this, "ASC" /* ASC */);
|
|
468
|
+
}
|
|
469
|
+
/** Sort by this expression, largest first. */
|
|
470
|
+
descending() {
|
|
471
|
+
return new SortOperation(this, "DESC" /* DESC */);
|
|
472
|
+
}
|
|
473
|
+
comparisonOperand() {
|
|
474
|
+
return this;
|
|
475
|
+
}
|
|
476
|
+
};
|
|
477
|
+
var Alias = class _Alias extends RelationalOperationElement {
|
|
478
|
+
constructor(element, name) {
|
|
479
|
+
super();
|
|
480
|
+
this.element = element;
|
|
481
|
+
this.name = name;
|
|
482
|
+
}
|
|
483
|
+
element;
|
|
484
|
+
name;
|
|
485
|
+
alias(name) {
|
|
486
|
+
return new _Alias(this.element, name);
|
|
487
|
+
}
|
|
488
|
+
/** Sorts by the column the alias names. */
|
|
489
|
+
ascending() {
|
|
490
|
+
return new SortOperation(this.element, "ASC" /* ASC */);
|
|
491
|
+
}
|
|
492
|
+
/** Sorts by the column the alias names. */
|
|
493
|
+
descending() {
|
|
494
|
+
return new SortOperation(this.element, "DESC" /* DESC */);
|
|
495
|
+
}
|
|
496
|
+
};
|
|
497
|
+
var CaseOperation = class extends Operation {
|
|
498
|
+
constructor(condition, then, fallback, displayName) {
|
|
499
|
+
super();
|
|
500
|
+
this.condition = condition;
|
|
501
|
+
this.then = then;
|
|
502
|
+
this.fallback = fallback;
|
|
503
|
+
this.displayName = displayName;
|
|
504
|
+
}
|
|
505
|
+
condition;
|
|
506
|
+
then;
|
|
507
|
+
fallback;
|
|
508
|
+
displayName;
|
|
509
|
+
};
|
|
510
|
+
var ExistsOperation = class extends RelationalOperationElement {
|
|
511
|
+
constructor(node) {
|
|
512
|
+
super();
|
|
513
|
+
this.node = node;
|
|
514
|
+
}
|
|
515
|
+
node;
|
|
516
|
+
/** Name this column in the result. */
|
|
517
|
+
alias(name) {
|
|
518
|
+
return new Alias(this, name);
|
|
519
|
+
}
|
|
520
|
+
and(other) {
|
|
521
|
+
return new LogicalOperation(this, "AND" /* AND */, other);
|
|
522
|
+
}
|
|
523
|
+
or(other) {
|
|
524
|
+
return new LogicalOperation(this, "OR" /* OR */, other);
|
|
525
|
+
}
|
|
526
|
+
};
|
|
527
|
+
var NotExistsOperation = class extends RelationalOperationElement {
|
|
528
|
+
constructor(node) {
|
|
529
|
+
super();
|
|
530
|
+
this.node = node;
|
|
531
|
+
}
|
|
532
|
+
node;
|
|
533
|
+
/** Name this column in the result. */
|
|
534
|
+
alias(name) {
|
|
535
|
+
return new Alias(this, name);
|
|
536
|
+
}
|
|
537
|
+
and(other) {
|
|
538
|
+
return new LogicalOperation(this, "AND" /* AND */, other);
|
|
539
|
+
}
|
|
540
|
+
or(other) {
|
|
541
|
+
return new LogicalOperation(this, "OR" /* OR */, other);
|
|
542
|
+
}
|
|
543
|
+
};
|
|
544
|
+
var SelectOperation = class {
|
|
545
|
+
constructor(display, filter, orderBy = [], groupBy = [], limit, table, joinFilters = /* @__PURE__ */ new Map(), distinct = false, offset, having) {
|
|
546
|
+
this.display = display;
|
|
547
|
+
this.filter = filter;
|
|
548
|
+
this.orderBy = orderBy;
|
|
549
|
+
this.groupBy = groupBy;
|
|
550
|
+
this.limit = limit;
|
|
551
|
+
this.table = table;
|
|
552
|
+
this.joinFilters = joinFilters;
|
|
553
|
+
this.distinct = distinct;
|
|
554
|
+
this.offset = offset;
|
|
555
|
+
this.having = having;
|
|
556
|
+
}
|
|
557
|
+
display;
|
|
558
|
+
filter;
|
|
559
|
+
orderBy;
|
|
560
|
+
groupBy;
|
|
561
|
+
limit;
|
|
562
|
+
table;
|
|
563
|
+
joinFilters;
|
|
564
|
+
distinct;
|
|
565
|
+
offset;
|
|
566
|
+
having;
|
|
567
|
+
};
|
|
568
|
+
function containsAggregateOrWindow(op) {
|
|
569
|
+
if (op instanceof AggregateOperation || op instanceof WindowFunctionOperation || op instanceof CountAllOperation) return true;
|
|
570
|
+
if (op instanceof BinaryOperation) return containsAggregateOrWindow(op.left) || containsAggregateOrWindow(op.right);
|
|
571
|
+
if (op instanceof UnaryOperation || op instanceof Alias) return containsAggregateOrWindow(op.element);
|
|
572
|
+
return false;
|
|
573
|
+
}
|
|
574
|
+
function containsAggregate(op) {
|
|
575
|
+
if (op instanceof AggregateOperation || op instanceof CountAllOperation) return true;
|
|
576
|
+
if (op instanceof BinaryOperation) return containsAggregate(op.left) || containsAggregate(op.right);
|
|
577
|
+
if (op instanceof UnaryOperation || op instanceof Alias) return containsAggregate(op.element);
|
|
578
|
+
return false;
|
|
579
|
+
}
|
|
580
|
+
function valueOperand(value) {
|
|
581
|
+
if (typeof value === "boolean") return new BooleanConstantOperation(value);
|
|
582
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
583
|
+
return Number.isInteger(value) ? new IntegerConstantOperation(value) : new FloatConstantOperation(value);
|
|
584
|
+
}
|
|
585
|
+
if (typeof value === "string") return new StringConstantOperation(value);
|
|
586
|
+
if (value instanceof DateOnly) return new DateConstantOperation(value);
|
|
587
|
+
if (value instanceof Date) return new DateTimeConstantOperation(value);
|
|
588
|
+
throw new TypeError(`A value to compare with is a boolean, a finite number, a string or a date, not ${value === null ? "null" : typeof value}`);
|
|
589
|
+
}
|
|
590
|
+
function operandOf(other) {
|
|
591
|
+
if (other instanceof RelationalOperationElement) return other;
|
|
592
|
+
if (typeof other?.cwj === "function") return other.cwj();
|
|
593
|
+
return valueOperand(other);
|
|
594
|
+
}
|
|
595
|
+
var Comparable = class {
|
|
596
|
+
_compared(operator, other) {
|
|
597
|
+
return new ComparisonOperation(this.comparisonOperand(), operator, operandOf(other));
|
|
598
|
+
}
|
|
599
|
+
/** Filter to rows where this expression equals `other`. */
|
|
600
|
+
eq(other) {
|
|
601
|
+
return this._compared("EQUAL" /* EQUAL */, other);
|
|
602
|
+
}
|
|
603
|
+
/** Filter to rows where this expression does not equal `other`. */
|
|
604
|
+
ne(other) {
|
|
605
|
+
return this._compared("NOT_EQUAL" /* NOT_EQUAL */, other);
|
|
606
|
+
}
|
|
607
|
+
/** Filter to rows where this expression is less than `other`. */
|
|
608
|
+
lt(other) {
|
|
609
|
+
return this._compared("LESS_THAN" /* LESS_THAN */, other);
|
|
610
|
+
}
|
|
611
|
+
/** Filter to rows where this expression is at most `other`. */
|
|
612
|
+
lte(other) {
|
|
613
|
+
return this._compared("LESS_THAN_OR_EQUAL_TO" /* LESS_THAN_OR_EQUAL_TO */, other);
|
|
614
|
+
}
|
|
615
|
+
/** Filter to rows where this expression is greater than `other`. */
|
|
616
|
+
gt(other) {
|
|
617
|
+
return this._compared("GREATER_THAN" /* GREATER_THAN */, other);
|
|
618
|
+
}
|
|
619
|
+
/** Filter to rows where this expression is at least `other`. */
|
|
620
|
+
gte(other) {
|
|
621
|
+
return this._compared("GREATER_THAN_OR_EQUAL_TO" /* GREATER_THAN_OR_EQUAL_TO */, other);
|
|
622
|
+
}
|
|
623
|
+
};
|
|
624
|
+
function sample(ddof) {
|
|
625
|
+
if (ddof !== 0 && ddof !== 1) throw new RangeError(`ddof is 0 (population) or 1 (sample), not ${ddof}`);
|
|
626
|
+
return ddof === 1;
|
|
627
|
+
}
|
|
628
|
+
var StringPredicates = class {
|
|
629
|
+
_like(pattern) {
|
|
630
|
+
return new ComparisonOperation(this.comparisonOperand(), "LIKE" /* LIKE */, new StringConstantOperation(pattern));
|
|
631
|
+
}
|
|
632
|
+
/** Filter to rows where this text contains `value`. */
|
|
633
|
+
contains(value) {
|
|
634
|
+
return this._like(`%${escapeLike(value)}%`);
|
|
635
|
+
}
|
|
636
|
+
/** Filter to rows where this text starts with `prefix`. */
|
|
637
|
+
startsWith(prefix) {
|
|
638
|
+
return this._like(`${escapeLike(prefix)}%`);
|
|
639
|
+
}
|
|
640
|
+
/** Filter to rows where this text ends with `suffix`. */
|
|
641
|
+
endsWith(suffix) {
|
|
642
|
+
return this._like(`%${escapeLike(suffix)}`);
|
|
643
|
+
}
|
|
644
|
+
};
|
|
645
|
+
var Aggregates = class {
|
|
646
|
+
_aggregate(operator, label) {
|
|
647
|
+
return new AggregateOperation(this, operator, label + " Expression");
|
|
648
|
+
}
|
|
649
|
+
/** Sum of the values in the group. */
|
|
650
|
+
sum() {
|
|
651
|
+
return this._aggregate("SUM" /* SUM */, "Sum");
|
|
652
|
+
}
|
|
653
|
+
/** Smallest value in the group. */
|
|
654
|
+
min() {
|
|
655
|
+
return this._aggregate("MIN" /* MIN */, "Min");
|
|
656
|
+
}
|
|
657
|
+
/** Largest value in the group. */
|
|
658
|
+
max() {
|
|
659
|
+
return this._aggregate("MAX" /* MAX */, "Max");
|
|
660
|
+
}
|
|
661
|
+
/** Arithmetic mean of the values in the group. */
|
|
662
|
+
average() {
|
|
663
|
+
return this._aggregate("AVERAGE" /* AVERAGE */, "Average");
|
|
664
|
+
}
|
|
665
|
+
/** Number of non-null values in the group. */
|
|
666
|
+
count() {
|
|
667
|
+
return this._aggregate("COUNT" /* COUNT */, "Count");
|
|
668
|
+
}
|
|
669
|
+
/** Standard deviation of the values in the group: the sample one by default, `ddof = 0` for the population one. */
|
|
670
|
+
std(ddof = 1) {
|
|
671
|
+
return this._aggregate(sample(ddof) ? "STDDEV_SAMP" /* STDDEV_SAMP */ : "STDDEV_POP" /* STDDEV_POP */, "Std");
|
|
672
|
+
}
|
|
673
|
+
/** Variance of the values in the group: the sample one by default, `ddof = 0` for the population one. */
|
|
674
|
+
var(ddof = 1) {
|
|
675
|
+
return this._aggregate(sample(ddof) ? "VAR_SAMP" /* VAR_SAMP */ : "VAR_POP" /* VAR_POP */, "Var");
|
|
676
|
+
}
|
|
677
|
+
};
|
|
678
|
+
var BooleanAggregates = class {
|
|
679
|
+
/** True for a group where every row satisfies the condition. */
|
|
680
|
+
all() {
|
|
681
|
+
return new AggregateOperation(this, "BOOL_AND" /* BOOL_AND */, "All Expression");
|
|
682
|
+
}
|
|
683
|
+
/** True for a group where at least one row satisfies the condition. */
|
|
684
|
+
any() {
|
|
685
|
+
return new AggregateOperation(this, "BOOL_OR" /* BOOL_OR */, "Any Expression");
|
|
686
|
+
}
|
|
687
|
+
};
|
|
688
|
+
function applyMixins(derived, bases) {
|
|
689
|
+
for (const base of bases) {
|
|
690
|
+
for (const name of Object.getOwnPropertyNames(base.prototype)) {
|
|
691
|
+
if (name === "constructor" || Object.prototype.hasOwnProperty.call(derived.prototype, name)) continue;
|
|
692
|
+
Object.defineProperty(derived.prototype, name, Object.getOwnPropertyDescriptor(base.prototype, name));
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
var Arithmetic = class {
|
|
697
|
+
/** Raises if this expression is not a number. */
|
|
698
|
+
assertNumeric() {
|
|
699
|
+
}
|
|
700
|
+
_arithmetic(operator, other) {
|
|
701
|
+
this.assertNumeric();
|
|
702
|
+
let operand;
|
|
703
|
+
if (typeof other === "number") {
|
|
704
|
+
if (!Number.isFinite(other)) throw new TypeError("Arithmetic is between numbers and numeric columns, not a non-finite number");
|
|
705
|
+
operand = valueOperand(other);
|
|
706
|
+
} else if (other !== null && typeof other === "object" && typeof other.arithmeticOperand === "function") {
|
|
707
|
+
other.assertNumeric?.();
|
|
708
|
+
operand = other.arithmeticOperand();
|
|
709
|
+
} else {
|
|
710
|
+
throw new TypeError(`Arithmetic is between numbers and numeric columns, not ${other === null ? "null" : typeof other}`);
|
|
711
|
+
}
|
|
712
|
+
return new ArithmeticOperation(this.arithmeticOperand(), operator, operand);
|
|
713
|
+
}
|
|
714
|
+
/** `this + other`. */
|
|
715
|
+
plus(other) {
|
|
716
|
+
return this._arithmetic("+" /* ADD */, other);
|
|
717
|
+
}
|
|
718
|
+
/** `this - other`. */
|
|
719
|
+
minus(other) {
|
|
720
|
+
return this._arithmetic("-" /* SUBTRACT */, other);
|
|
721
|
+
}
|
|
722
|
+
/** `this * other`. */
|
|
723
|
+
times(other) {
|
|
724
|
+
return this._arithmetic("*" /* MULTIPLY */, other);
|
|
725
|
+
}
|
|
726
|
+
/** `this / other`. */
|
|
727
|
+
dividedBy(other) {
|
|
728
|
+
return this._arithmetic("/" /* DIVIDE */, other);
|
|
729
|
+
}
|
|
730
|
+
};
|
|
731
|
+
var ArithmeticOperation = class extends BinaryOperation {
|
|
732
|
+
constructor(left, operator, right, displayName) {
|
|
733
|
+
super(left, right);
|
|
734
|
+
this.operator = operator;
|
|
735
|
+
this.displayName = displayName;
|
|
736
|
+
}
|
|
737
|
+
operator;
|
|
738
|
+
displayName;
|
|
739
|
+
/** Sort by this expression, smallest first. */
|
|
740
|
+
ascending() {
|
|
741
|
+
return new SortOperation(this, "ASC" /* ASC */);
|
|
742
|
+
}
|
|
743
|
+
/** Sort by this expression, largest first. */
|
|
744
|
+
descending() {
|
|
745
|
+
return new SortOperation(this, "DESC" /* DESC */);
|
|
746
|
+
}
|
|
747
|
+
arithmeticOperand() {
|
|
748
|
+
return this;
|
|
749
|
+
}
|
|
750
|
+
comparisonOperand() {
|
|
751
|
+
return this;
|
|
752
|
+
}
|
|
753
|
+
};
|
|
754
|
+
var ConcatOperation = class extends Operation {
|
|
755
|
+
constructor(parts, displayName) {
|
|
756
|
+
super();
|
|
757
|
+
this.parts = parts;
|
|
758
|
+
this.displayName = displayName;
|
|
759
|
+
}
|
|
760
|
+
parts;
|
|
761
|
+
displayName;
|
|
762
|
+
/** Join more text on the end: `f.first().concat(' ', f.last())`. A concatenation joins into one. */
|
|
763
|
+
concat(...more) {
|
|
764
|
+
return concat(this, ...more);
|
|
765
|
+
}
|
|
766
|
+
/** Sort by this expression, smallest first. */
|
|
767
|
+
ascending() {
|
|
768
|
+
return new SortOperation(this, "ASC" /* ASC */);
|
|
769
|
+
}
|
|
770
|
+
/** Sort by this expression, largest first. */
|
|
771
|
+
descending() {
|
|
772
|
+
return new SortOperation(this, "DESC" /* DESC */);
|
|
773
|
+
}
|
|
774
|
+
comparisonOperand() {
|
|
775
|
+
return this;
|
|
776
|
+
}
|
|
289
777
|
};
|
|
778
|
+
function concat(...parts) {
|
|
779
|
+
const partsOf = (part) => {
|
|
780
|
+
if (part instanceof ConcatOperation) return part.parts;
|
|
781
|
+
if (typeof part === "string") return [new StringConstantOperation(part)];
|
|
782
|
+
if (part instanceof RelationalOperationElement) return [part];
|
|
783
|
+
if (part !== null && typeof part === "object" && typeof part.functionInput === "function") return [part.functionInput()];
|
|
784
|
+
throw new TypeError(`Text is joined with text, not ${part === null ? "null" : typeof part}`);
|
|
785
|
+
};
|
|
786
|
+
return new ConcatOperation(parts.flatMap(partsOf));
|
|
787
|
+
}
|
|
788
|
+
applyMixins(ConcatOperation, [Comparable, StringPredicates]);
|
|
789
|
+
applyMixins(DateTruncOperation, [Comparable]);
|
|
790
|
+
applyMixins(ArithmeticOperation, [Arithmetic, Comparable]);
|
|
791
|
+
applyMixins(ScalarFunctionOperation, [Comparable, Arithmetic, StringPredicates]);
|
|
792
|
+
applyMixins(AggregateOperation, [Arithmetic, Comparable, StringPredicates]);
|
|
793
|
+
applyMixins(CountAllOperation, [Comparable]);
|
|
794
|
+
applyMixins(NumericConstantOperation, [Arithmetic]);
|
|
795
|
+
applyMixins(ConstantOperation, [Aggregates]);
|
|
796
|
+
applyMixins(ArithmeticOperation, [Aggregates]);
|
|
797
|
+
applyMixins(ScalarFunctionOperation, [Aggregates]);
|
|
798
|
+
applyMixins(CaseOperation, [Aggregates]);
|
|
799
|
+
applyMixins(IsNullOperation, [BooleanAggregates]);
|
|
800
|
+
applyMixins(IsNotNullOperation, [BooleanAggregates]);
|
|
801
|
+
applyMixins(InOperation, [BooleanAggregates]);
|
|
802
|
+
applyMixins(NotInOperation, [BooleanAggregates]);
|
|
803
|
+
applyMixins(ComparisonOperation, [BooleanAggregates]);
|
|
804
|
+
applyMixins(LogicalOperation, [BooleanAggregates]);
|
|
290
805
|
|
|
291
806
|
// src/datafinder/attribute.ts
|
|
292
|
-
var Attribute = class {
|
|
807
|
+
var Attribute = class _Attribute {
|
|
293
808
|
_displayName;
|
|
294
809
|
_column;
|
|
295
810
|
_owner;
|
|
296
811
|
_parent;
|
|
297
|
-
|
|
812
|
+
_embedded;
|
|
813
|
+
_optional;
|
|
814
|
+
constructor(displayName, columnName, columnDbType, owner, parent, embedded, nullable = true, optional = false) {
|
|
815
|
+
this._optional = optional;
|
|
298
816
|
this._displayName = displayName;
|
|
299
|
-
this._column = new Column(columnName, columnDbType, owner);
|
|
817
|
+
this._column = new Column(columnName, columnDbType, owner, false, nullable);
|
|
300
818
|
this._owner = owner;
|
|
301
819
|
this._parent = parent;
|
|
820
|
+
this._embedded = embedded;
|
|
302
821
|
}
|
|
303
822
|
column() {
|
|
304
823
|
return this._column;
|
|
@@ -312,33 +831,102 @@ var Attribute = class {
|
|
|
312
831
|
displayName() {
|
|
313
832
|
return this._displayName;
|
|
314
833
|
}
|
|
834
|
+
/** Alternate attribute on a flat column of the owning table, used in place of this one when its join is elided. */
|
|
835
|
+
embedded() {
|
|
836
|
+
return this._embedded;
|
|
837
|
+
}
|
|
838
|
+
/** @internal The expression a function of this attribute applies to: its column. */
|
|
839
|
+
functionInput() {
|
|
840
|
+
return this.cwj();
|
|
841
|
+
}
|
|
842
|
+
/** @internal What a function of this attribute is labelled after: its display name. */
|
|
843
|
+
functionLabel() {
|
|
844
|
+
return this._displayName;
|
|
845
|
+
}
|
|
846
|
+
/** @internal This attribute as an operand of arithmetic: its column. */
|
|
847
|
+
arithmeticOperand() {
|
|
848
|
+
return this.cwj();
|
|
849
|
+
}
|
|
315
850
|
cwj() {
|
|
316
|
-
return new ColumnWithJoin(this._column, this._parent);
|
|
851
|
+
return new ColumnWithJoin(this._column, this._parent, this._embedded?.cwj(), this._optional);
|
|
317
852
|
}
|
|
853
|
+
/** Count the number of non-null values. Use in a projection with `groupBy` to aggregate per group. */
|
|
318
854
|
count() {
|
|
319
855
|
return new AggregateOperation(
|
|
320
|
-
|
|
856
|
+
this.cwj(),
|
|
321
857
|
"COUNT" /* COUNT */,
|
|
322
858
|
this._displayName + " Count"
|
|
323
859
|
);
|
|
324
860
|
}
|
|
861
|
+
/** Name this column in the result: `f.price().sum().alias('Total')`. */
|
|
862
|
+
alias(name) {
|
|
863
|
+
return new Alias(this, name);
|
|
864
|
+
}
|
|
865
|
+
/** The number of different non-NULL values in the group: `COUNT(DISTINCT column)`. Use with `groupBy` to count per group. */
|
|
866
|
+
countDistinct() {
|
|
867
|
+
return new AggregateOperation(this.cwj(), "COUNT_DISTINCT" /* COUNT_DISTINCT */, this._displayName + " Count Distinct");
|
|
868
|
+
}
|
|
869
|
+
/** The value, or `defaultValue` when it is NULL: `name().orElse('N/A')`. Like `COALESCE` in SQL. */
|
|
870
|
+
orElse(defaultValue) {
|
|
871
|
+
if (!["string", "number", "boolean"].includes(typeof defaultValue)) {
|
|
872
|
+
throw new TypeError(`An orElse default is a string, number or boolean, not ${defaultValue === null ? "null" : typeof defaultValue}`);
|
|
873
|
+
}
|
|
874
|
+
return new ScalarFunctionOperation(this.cwj(), "COALESCE" /* COALESCE */, "Or Else " + this._displayName, void 0, [defaultValue]);
|
|
875
|
+
}
|
|
876
|
+
/** Sort this attribute in ascending order. Pass to `orderBy` or a window function's `orderBy`. */
|
|
325
877
|
ascending() {
|
|
326
|
-
return new SortOperation(
|
|
878
|
+
return new SortOperation(this.cwj(), "ASC" /* ASC */);
|
|
327
879
|
}
|
|
880
|
+
/** Sort this attribute in descending order. Pass to `orderBy` or a window function's `orderBy`. */
|
|
328
881
|
descending() {
|
|
329
|
-
return new SortOperation(
|
|
882
|
+
return new SortOperation(this.cwj(), "DESC" /* DESC */);
|
|
330
883
|
}
|
|
884
|
+
/** Filter to rows where this attribute has no value. */
|
|
331
885
|
isNull() {
|
|
332
|
-
return new IsNullOperation(
|
|
886
|
+
return new IsNullOperation(this.cwj());
|
|
333
887
|
}
|
|
888
|
+
/** Filter to rows where this attribute has a value. */
|
|
334
889
|
isNotNull() {
|
|
335
|
-
return new IsNotNullOperation(
|
|
890
|
+
return new IsNotNullOperation(this.cwj());
|
|
891
|
+
}
|
|
892
|
+
/** Wrap a value as a constant of this attribute's type. Overridden by the typed attributes. */
|
|
893
|
+
toConstant(_value) {
|
|
894
|
+
throw new TypeError(`${this.constructor.name} does not support isIn / isNotIn`);
|
|
895
|
+
}
|
|
896
|
+
_constants(values) {
|
|
897
|
+
const constants = values.map((v) => this.toConstant(v));
|
|
898
|
+
if (constants.length === 0) throw new Error("isIn / isNotIn need at least one value");
|
|
899
|
+
return constants;
|
|
900
|
+
}
|
|
901
|
+
/** Filter to rows where this attribute equals any of `values`. */
|
|
902
|
+
isIn(values) {
|
|
903
|
+
return new InOperation(this.cwj(), this._constants(values));
|
|
904
|
+
}
|
|
905
|
+
/** Filter to rows where this attribute equals none of `values`. Rows with no value are excluded, as in SQL. */
|
|
906
|
+
isNotIn(values) {
|
|
907
|
+
return new NotInOperation(this.cwj(), this._constants(values));
|
|
336
908
|
}
|
|
337
909
|
_windowSpec(partitionBy, orderBy) {
|
|
338
|
-
const
|
|
910
|
+
const pbArr = partitionBy === void 0 ? [] : Array.isArray(partitionBy) ? partitionBy : [partitionBy];
|
|
911
|
+
const pb = pbArr.map((x) => x instanceof _Attribute ? x.cwj() : x);
|
|
339
912
|
const ob = orderBy === void 0 ? [] : Array.isArray(orderBy) ? orderBy : [orderBy];
|
|
340
913
|
return new WindowSpecification(pb, ob);
|
|
341
914
|
}
|
|
915
|
+
/**
|
|
916
|
+
* Assign a rank to each row within the ordered window, following pandas `Series.rank` conventions.
|
|
917
|
+
*
|
|
918
|
+
* `method` controls tie-breaking (default `'min'`):
|
|
919
|
+
* - `'min'` — tied rows share the lowest rank; the next rank skips.
|
|
920
|
+
* - `'dense'` — like `'min'` but ranks are contiguous (no gaps).
|
|
921
|
+
* - `'first'` — each row gets a unique sequential integer (no ties).
|
|
922
|
+
* - `'max'` — only meaningful with `pct: true` (see below).
|
|
923
|
+
*
|
|
924
|
+
* When `pct: true` the result is a relative rank between 0 and 1:
|
|
925
|
+
* - `method: 'min'` (default) → fraction of values strictly below this row (PERCENT_RANK).
|
|
926
|
+
* - `method: 'max'` → fraction of values at or below this row (cumulative distribution).
|
|
927
|
+
*
|
|
928
|
+
* `partitionBy` restarts the ranking within each group of distinct values.
|
|
929
|
+
*/
|
|
342
930
|
rank(opts = {}) {
|
|
343
931
|
const { method = "min", pct = false, partitionBy, orderBy } = opts;
|
|
344
932
|
let func;
|
|
@@ -363,6 +951,11 @@ var Attribute = class {
|
|
|
363
951
|
}
|
|
364
952
|
return new WindowFunctionOperation(null, func, name, void 0, [], this._windowSpec(partitionBy, orderBy));
|
|
365
953
|
}
|
|
954
|
+
/**
|
|
955
|
+
* Split rows into `buckets` equal-sized quantile bins ordered by `orderBy`.
|
|
956
|
+
* Each row receives a bucket number from 1 (lowest) to `buckets` (highest).
|
|
957
|
+
* Named after `pandas.qcut`.
|
|
958
|
+
*/
|
|
366
959
|
qcut(buckets, opts = {}) {
|
|
367
960
|
return new WindowFunctionOperation(
|
|
368
961
|
null,
|
|
@@ -373,12 +966,17 @@ var Attribute = class {
|
|
|
373
966
|
this._windowSpec(opts.partitionBy, opts.orderBy)
|
|
374
967
|
);
|
|
375
968
|
}
|
|
969
|
+
/**
|
|
970
|
+
* Return the value of this attribute from `periods` rows earlier (positive) or later (negative)
|
|
971
|
+
* within the ordered window, following `pandas.Series.shift`.
|
|
972
|
+
* Rows with no neighbour at the given offset return `null` (or `fillValue` if provided).
|
|
973
|
+
*/
|
|
376
974
|
shift(periods = 1, opts = {}) {
|
|
377
975
|
const extraArgs = opts.fillValue !== void 0 ? [opts.fillValue] : [];
|
|
378
976
|
const func = periods >= 0 ? "LAG" /* LAG */ : "LEAD" /* LEAD */;
|
|
379
977
|
const label = periods >= 0 ? "Lag" : "Lead";
|
|
380
978
|
return new WindowFunctionOperation(
|
|
381
|
-
|
|
979
|
+
this.cwj(),
|
|
382
980
|
func,
|
|
383
981
|
label + " " + this._displayName,
|
|
384
982
|
Math.abs(periods),
|
|
@@ -386,9 +984,13 @@ var Attribute = class {
|
|
|
386
984
|
this._windowSpec(opts.partitionBy, opts.orderBy)
|
|
387
985
|
);
|
|
388
986
|
}
|
|
987
|
+
/**
|
|
988
|
+
* Return the first value of this attribute in the window frame.
|
|
989
|
+
* Use `partitionBy` to restart the frame for each group.
|
|
990
|
+
*/
|
|
389
991
|
first(opts = {}) {
|
|
390
992
|
return new WindowFunctionOperation(
|
|
391
|
-
|
|
993
|
+
this.cwj(),
|
|
392
994
|
"FIRST_VALUE" /* FIRST_VALUE */,
|
|
393
995
|
"First " + this._displayName,
|
|
394
996
|
void 0,
|
|
@@ -396,9 +998,13 @@ var Attribute = class {
|
|
|
396
998
|
this._windowSpec(opts.partitionBy, opts.orderBy)
|
|
397
999
|
);
|
|
398
1000
|
}
|
|
1001
|
+
/**
|
|
1002
|
+
* Return the last value of this attribute in the window frame.
|
|
1003
|
+
* Use `partitionBy` to restart the frame for each group.
|
|
1004
|
+
*/
|
|
399
1005
|
last(opts = {}) {
|
|
400
1006
|
return new WindowFunctionOperation(
|
|
401
|
-
|
|
1007
|
+
this.cwj(),
|
|
402
1008
|
"LAST_VALUE" /* LAST_VALUE */,
|
|
403
1009
|
"Last " + this._displayName,
|
|
404
1010
|
void 0,
|
|
@@ -485,217 +1091,538 @@ var MilestonedTable = class extends Table {
|
|
|
485
1091
|
milestoningColumns;
|
|
486
1092
|
};
|
|
487
1093
|
|
|
1094
|
+
// src/datafinder/scalar-functions.ts
|
|
1095
|
+
var StringFunctionOperation = class extends ScalarFunctionOperation {
|
|
1096
|
+
functionInput() {
|
|
1097
|
+
return this;
|
|
1098
|
+
}
|
|
1099
|
+
functionLabel() {
|
|
1100
|
+
return labelOf(this);
|
|
1101
|
+
}
|
|
1102
|
+
};
|
|
1103
|
+
var NumericFunctionOperation = class extends ScalarFunctionOperation {
|
|
1104
|
+
functionInput() {
|
|
1105
|
+
return this;
|
|
1106
|
+
}
|
|
1107
|
+
functionLabel() {
|
|
1108
|
+
return labelOf(this);
|
|
1109
|
+
}
|
|
1110
|
+
};
|
|
1111
|
+
function labelOf(operation) {
|
|
1112
|
+
return operation.displayName ?? operation.func.charAt(0) + operation.func.slice(1).toLowerCase();
|
|
1113
|
+
}
|
|
1114
|
+
function stringFunction(element, func, label, secondArg, extraArgs = []) {
|
|
1115
|
+
return new StringFunctionOperation(element, func, label, secondArg, extraArgs);
|
|
1116
|
+
}
|
|
1117
|
+
function numberFunction(element, func, label, secondArg) {
|
|
1118
|
+
return new NumericFunctionOperation(element, func, label, secondArg);
|
|
1119
|
+
}
|
|
1120
|
+
var StringFunctions = class {
|
|
1121
|
+
/** Join text on the end: `f.first().concat(' ', f.last())`. A NULL part makes the whole NULL. */
|
|
1122
|
+
concat(...more) {
|
|
1123
|
+
return concat(this, ...more);
|
|
1124
|
+
}
|
|
1125
|
+
/** Convert every character to uppercase. */
|
|
1126
|
+
toUpperCase() {
|
|
1127
|
+
return stringFunction(this.functionInput(), "UPPER" /* UPPER */, "Upper " + this.functionLabel());
|
|
1128
|
+
}
|
|
1129
|
+
/** Convert every character to lowercase. */
|
|
1130
|
+
toLowerCase() {
|
|
1131
|
+
return stringFunction(this.functionInput(), "LOWER" /* LOWER */, "Lower " + this.functionLabel());
|
|
1132
|
+
}
|
|
1133
|
+
/** Remove leading and trailing whitespace. */
|
|
1134
|
+
trim() {
|
|
1135
|
+
return stringFunction(this.functionInput(), "TRIM" /* TRIM */, "Trim " + this.functionLabel());
|
|
1136
|
+
}
|
|
1137
|
+
/** Remove leading whitespace. */
|
|
1138
|
+
trimStart() {
|
|
1139
|
+
return stringFunction(this.functionInput(), "LTRIM" /* LTRIM */, "Trim Start " + this.functionLabel());
|
|
1140
|
+
}
|
|
1141
|
+
/** Remove trailing whitespace. */
|
|
1142
|
+
trimEnd() {
|
|
1143
|
+
return stringFunction(this.functionInput(), "RTRIM" /* RTRIM */, "Trim End " + this.functionLabel());
|
|
1144
|
+
}
|
|
1145
|
+
/** Return the number of characters in the string. */
|
|
1146
|
+
length() {
|
|
1147
|
+
return numberFunction(this.functionInput(), "LENGTH" /* LENGTH */, "Length " + this.functionLabel());
|
|
1148
|
+
}
|
|
1149
|
+
/** Return the string with characters in reverse order. */
|
|
1150
|
+
reverse() {
|
|
1151
|
+
return stringFunction(this.functionInput(), "REVERSE" /* REVERSE */, "Reverse " + this.functionLabel());
|
|
1152
|
+
}
|
|
1153
|
+
/** Return the first `n` characters. */
|
|
1154
|
+
left(n) {
|
|
1155
|
+
return stringFunction(this.functionInput(), "LEFT" /* LEFT */, "Left " + this.functionLabel(), n);
|
|
1156
|
+
}
|
|
1157
|
+
/** Return the last `n` characters. */
|
|
1158
|
+
right(n) {
|
|
1159
|
+
return stringFunction(this.functionInput(), "RIGHT" /* RIGHT */, "Right " + this.functionLabel(), n);
|
|
1160
|
+
}
|
|
1161
|
+
/** Return the string repeated `n` times. */
|
|
1162
|
+
repeat(n) {
|
|
1163
|
+
return stringFunction(this.functionInput(), "REPEAT" /* REPEAT */, "Repeat " + this.functionLabel(), n);
|
|
1164
|
+
}
|
|
1165
|
+
/** Replace all occurrences of `fromStr` with `toStr`. */
|
|
1166
|
+
replace(fromStr, toStr) {
|
|
1167
|
+
return stringFunction(this.functionInput(), "REPLACE" /* REPLACE */, "Replace " + this.functionLabel(), void 0, [fromStr, toStr]);
|
|
1168
|
+
}
|
|
1169
|
+
/**
|
|
1170
|
+
* Extract a portion of the string.
|
|
1171
|
+
* `start` is zero-based (following Python convention); `length` is optional.
|
|
1172
|
+
*/
|
|
1173
|
+
substring(start, length) {
|
|
1174
|
+
const args = length !== void 0 ? [start + 1, length] : [start + 1];
|
|
1175
|
+
return stringFunction(this.functionInput(), "SUBSTRING" /* SUBSTRING */, "Substring " + this.functionLabel(), void 0, args);
|
|
1176
|
+
}
|
|
1177
|
+
};
|
|
1178
|
+
var NumericFunctions = class {
|
|
1179
|
+
/** Absolute value (distance from zero, always non-negative). */
|
|
1180
|
+
abs() {
|
|
1181
|
+
return numberFunction(this.functionInput(), "ABS" /* ABS */, "Abs " + this.functionLabel());
|
|
1182
|
+
}
|
|
1183
|
+
/** Round up to the nearest integer. */
|
|
1184
|
+
ceil() {
|
|
1185
|
+
return numberFunction(this.functionInput(), "CEILING" /* CEILING */, "Ceil " + this.functionLabel());
|
|
1186
|
+
}
|
|
1187
|
+
/** Round down to the nearest integer. */
|
|
1188
|
+
floor() {
|
|
1189
|
+
return numberFunction(this.functionInput(), "FLOOR" /* FLOOR */, "Floor " + this.functionLabel());
|
|
1190
|
+
}
|
|
1191
|
+
/** Square root. */
|
|
1192
|
+
sqrt() {
|
|
1193
|
+
return numberFunction(this.functionInput(), "SQRT" /* SQRT */, "Sqrt " + this.functionLabel());
|
|
1194
|
+
}
|
|
1195
|
+
/** Remainder after dividing by `n`. */
|
|
1196
|
+
mod(n) {
|
|
1197
|
+
return numberFunction(this.functionInput(), "MOD" /* MOD */, "Mod " + this.functionLabel(), n);
|
|
1198
|
+
}
|
|
1199
|
+
/** Raise to the power of `n`. */
|
|
1200
|
+
power(n) {
|
|
1201
|
+
return numberFunction(this.functionInput(), "POWER" /* POWER */, "Power " + this.functionLabel(), n);
|
|
1202
|
+
}
|
|
1203
|
+
/** Round to `d` decimal places, or to the nearest integer when `d` is omitted. */
|
|
1204
|
+
round(d) {
|
|
1205
|
+
return numberFunction(this.functionInput(), "ROUND" /* ROUND */, "Round " + this.functionLabel(), d);
|
|
1206
|
+
}
|
|
1207
|
+
};
|
|
1208
|
+
applyMixins(StringFunctionOperation, [StringFunctions]);
|
|
1209
|
+
applyMixins(NumericFunctionOperation, [NumericFunctions]);
|
|
1210
|
+
|
|
488
1211
|
// src/datafinder/typed-attributes.ts
|
|
1212
|
+
var MinMax = class {
|
|
1213
|
+
/** Smallest value in the group. */
|
|
1214
|
+
min() {
|
|
1215
|
+
return new AggregateOperation(this.cwj(), "MIN" /* MIN */, "Min " + this.displayName());
|
|
1216
|
+
}
|
|
1217
|
+
/** Largest value in the group. */
|
|
1218
|
+
max() {
|
|
1219
|
+
return new AggregateOperation(this.cwj(), "MAX" /* MAX */, "Max " + this.displayName());
|
|
1220
|
+
}
|
|
1221
|
+
};
|
|
1222
|
+
var StringAttribute = class extends Attribute {
|
|
1223
|
+
constructor(displayName, columnName, columnDbType, owner, parent, embedded, nullable = true, optional = false) {
|
|
1224
|
+
super(displayName, columnName, columnDbType, owner, parent, embedded, nullable, optional);
|
|
1225
|
+
}
|
|
1226
|
+
toConstant(value) {
|
|
1227
|
+
return new StringConstantOperation(String(value));
|
|
1228
|
+
}
|
|
1229
|
+
/**
|
|
1230
|
+
* Join the values of a group into one text with `separator` between them. `orderBy` is the order they are
|
|
1231
|
+
* joined in (`[f.name().ascending()]`); without it the order is not defined. Missing values are skipped.
|
|
1232
|
+
*/
|
|
1233
|
+
join(separator = "", orderBy = []) {
|
|
1234
|
+
return new AggregateOperation(this.cwj(), "STRING_AGG" /* STRING_AGG */, "Join " + this.displayName(), void 0, separator, orderBy);
|
|
1235
|
+
}
|
|
1236
|
+
/** Filter to rows where this attribute equals `value`. */
|
|
1237
|
+
eq(value) {
|
|
1238
|
+
return new ComparisonOperation(this.cwj(), "EQUAL" /* EQUAL */, new StringConstantOperation(value));
|
|
1239
|
+
}
|
|
1240
|
+
/** Filter to rows where this attribute does not equal `value`. */
|
|
1241
|
+
ne(value) {
|
|
1242
|
+
return new ComparisonOperation(this.cwj(), "NOT_EQUAL" /* NOT_EQUAL */, new StringConstantOperation(value));
|
|
1243
|
+
}
|
|
1244
|
+
/** Filter to rows where this attribute contains `value` as a substring. */
|
|
1245
|
+
contains(value) {
|
|
1246
|
+
return new ComparisonOperation(this.cwj(), "LIKE" /* LIKE */, new StringConstantOperation(`%${escapeLike(value)}%`));
|
|
1247
|
+
}
|
|
1248
|
+
/** Filter to rows where this attribute begins with `prefix`. */
|
|
1249
|
+
startsWith(prefix) {
|
|
1250
|
+
return new ComparisonOperation(this.cwj(), "LIKE" /* LIKE */, new StringConstantOperation(`${escapeLike(prefix)}%`));
|
|
1251
|
+
}
|
|
1252
|
+
/** Filter to rows where this attribute ends with `suffix`. */
|
|
1253
|
+
endsWith(suffix) {
|
|
1254
|
+
return new ComparisonOperation(this.cwj(), "LIKE" /* LIKE */, new StringConstantOperation(`%${escapeLike(suffix)}`));
|
|
1255
|
+
}
|
|
1256
|
+
/** Filter to rows where this attribute does not contain `value` as a substring. */
|
|
1257
|
+
notContains(value) {
|
|
1258
|
+
return new ComparisonOperation(this.cwj(), "NOT_LIKE" /* NOT_LIKE */, new StringConstantOperation(`%${escapeLike(value)}%`));
|
|
1259
|
+
}
|
|
1260
|
+
};
|
|
1261
|
+
applyMixins(StringAttribute, [MinMax, StringFunctions]);
|
|
1262
|
+
var NumericAttribute = class extends Attribute {
|
|
1263
|
+
constructor(displayName, columnName, columnDbType, owner, parent, embedded, nullable = true, optional = false) {
|
|
1264
|
+
super(displayName, columnName, columnDbType, owner, parent, embedded, nullable, optional);
|
|
1265
|
+
}
|
|
1266
|
+
/** Sum of all values in the group. */
|
|
1267
|
+
sum() {
|
|
1268
|
+
return new AggregateOperation(this.cwj(), "SUM" /* SUM */, "Sum " + this.displayName());
|
|
1269
|
+
}
|
|
1270
|
+
/** Arithmetic mean of all values in the group. */
|
|
1271
|
+
average() {
|
|
1272
|
+
return new AggregateOperation(this.cwj(), "AVERAGE" /* AVERAGE */, "Average " + this.displayName());
|
|
1273
|
+
}
|
|
1274
|
+
/** Standard deviation of the values in the group: the sample one by default, `ddof = 0` for the population one, as `Series.std`. */
|
|
1275
|
+
std(ddof = 1) {
|
|
1276
|
+
const operator = sample(ddof) ? "STDDEV_SAMP" /* STDDEV_SAMP */ : "STDDEV_POP" /* STDDEV_POP */;
|
|
1277
|
+
return new AggregateOperation(this.cwj(), operator, "Std " + this.displayName());
|
|
1278
|
+
}
|
|
1279
|
+
/** Variance of the values in the group: the sample one by default, `ddof = 0` for the population one, as `Series.var`. */
|
|
1280
|
+
var(ddof = 1) {
|
|
1281
|
+
const operator = sample(ddof) ? "VAR_SAMP" /* VAR_SAMP */ : "VAR_POP" /* VAR_POP */;
|
|
1282
|
+
return new AggregateOperation(this.cwj(), operator, "Var " + this.displayName());
|
|
1283
|
+
}
|
|
1284
|
+
};
|
|
1285
|
+
applyMixins(NumericAttribute, [MinMax, NumericFunctions, Arithmetic]);
|
|
489
1286
|
function parseDate(value) {
|
|
490
1287
|
if (value instanceof Date) return value;
|
|
491
1288
|
const d = new Date(value);
|
|
492
1289
|
if (isNaN(d.getTime())) throw new Error(`Cannot parse date: ${value}`);
|
|
493
1290
|
return d;
|
|
494
1291
|
}
|
|
1292
|
+
function temporalConstant(value) {
|
|
1293
|
+
if (typeof value === "string" && DATE_ONLY_PATTERN.test(value)) return new DateConstantOperation(new DateOnly(value));
|
|
1294
|
+
const date = parseDate(value);
|
|
1295
|
+
return date instanceof DateOnly ? new DateConstantOperation(date) : new DateTimeConstantOperation(date);
|
|
1296
|
+
}
|
|
495
1297
|
var DateAttribute = class extends Attribute {
|
|
496
|
-
constructor(displayName, columnName, columnDbType, owner, parent) {
|
|
497
|
-
super(displayName, columnName, columnDbType, owner, parent);
|
|
1298
|
+
constructor(displayName, columnName, columnDbType, owner, parent, embedded, nullable = true, optional = false) {
|
|
1299
|
+
super(displayName, columnName, columnDbType, owner, parent, embedded, nullable, optional);
|
|
498
1300
|
}
|
|
1301
|
+
toConstant(value) {
|
|
1302
|
+
return new DateConstantOperation(parseDate(value));
|
|
1303
|
+
}
|
|
1304
|
+
/** Filter to rows where this date equals `value`. */
|
|
499
1305
|
eq(value) {
|
|
500
1306
|
return new ComparisonOperation(this.cwj(), "EQUAL" /* EQUAL */, new DateConstantOperation(parseDate(value)));
|
|
501
1307
|
}
|
|
1308
|
+
/** Filter to rows where this date does not equal `value`. */
|
|
502
1309
|
ne(value) {
|
|
503
1310
|
return new ComparisonOperation(this.cwj(), "NOT_EQUAL" /* NOT_EQUAL */, new DateConstantOperation(parseDate(value)));
|
|
504
1311
|
}
|
|
1312
|
+
/** Filter to rows where this date is after `value`. */
|
|
505
1313
|
gt(value) {
|
|
506
1314
|
return new ComparisonOperation(this.cwj(), "GREATER_THAN" /* GREATER_THAN */, new DateConstantOperation(parseDate(value)));
|
|
507
1315
|
}
|
|
1316
|
+
/** Filter to rows where this date is before `value`. */
|
|
508
1317
|
lt(value) {
|
|
509
1318
|
return new ComparisonOperation(this.cwj(), "LESS_THAN" /* LESS_THAN */, new DateConstantOperation(parseDate(value)));
|
|
510
1319
|
}
|
|
1320
|
+
/** Filter to rows where this date is on or after `value`. */
|
|
511
1321
|
gte(value) {
|
|
512
1322
|
return new ComparisonOperation(this.cwj(), "GREATER_THAN_OR_EQUAL_TO" /* GREATER_THAN_OR_EQUAL_TO */, new DateConstantOperation(parseDate(value)));
|
|
513
1323
|
}
|
|
1324
|
+
/** Filter to rows where this date is on or before `value`. */
|
|
514
1325
|
lte(value) {
|
|
515
1326
|
return new ComparisonOperation(this.cwj(), "LESS_THAN_OR_EQUAL_TO" /* LESS_THAN_OR_EQUAL_TO */, new DateConstantOperation(parseDate(value)));
|
|
516
1327
|
}
|
|
1328
|
+
/** Extract the four-digit calendar year. */
|
|
517
1329
|
year() {
|
|
518
1330
|
return new DateExtractOperation(this.cwj(), "YEAR" /* YEAR */, "Year " + this.displayName());
|
|
519
1331
|
}
|
|
1332
|
+
/** Extract the month number (1–12). */
|
|
520
1333
|
month() {
|
|
521
1334
|
return new DateExtractOperation(this.cwj(), "MONTH" /* MONTH */, "Month " + this.displayName());
|
|
522
1335
|
}
|
|
1336
|
+
/** Extract the day of the month (1–31). */
|
|
523
1337
|
day() {
|
|
524
1338
|
return new DateExtractOperation(this.cwj(), "DAY" /* DAY */, "Day " + this.displayName());
|
|
525
1339
|
}
|
|
1340
|
+
/** Extract the quarter (1–4). */
|
|
526
1341
|
quarter() {
|
|
527
1342
|
return new DateExtractOperation(this.cwj(), "QUARTER" /* QUARTER */, "Quarter " + this.displayName());
|
|
528
1343
|
}
|
|
1344
|
+
/** Extract the ISO week number (1–53). */
|
|
529
1345
|
week() {
|
|
530
1346
|
return new DateExtractOperation(this.cwj(), "WEEK" /* WEEK */, "Week " + this.displayName());
|
|
531
1347
|
}
|
|
1348
|
+
/** Extract the day of the week (0 = Sunday through 6 = Saturday). */
|
|
532
1349
|
dayOfWeek() {
|
|
533
1350
|
return new DateExtractOperation(this.cwj(), "DOW" /* DOW */, "Day Of Week " + this.displayName());
|
|
534
1351
|
}
|
|
1352
|
+
/** The date of the first day of the week the date falls in (a Monday). */
|
|
1353
|
+
firstDayOfWeek() {
|
|
1354
|
+
return new DateTruncOperation(this.cwj(), "WEEK" /* WEEK */, "First Day Of Week " + this.displayName());
|
|
1355
|
+
}
|
|
1356
|
+
/** The date of the first day of the month the date falls in. */
|
|
1357
|
+
firstDayOfMonth() {
|
|
1358
|
+
return new DateTruncOperation(this.cwj(), "MONTH" /* MONTH */, "First Day Of Month " + this.displayName());
|
|
1359
|
+
}
|
|
1360
|
+
/** The date of the first day of the quarter the date falls in. */
|
|
1361
|
+
firstDayOfQuarter() {
|
|
1362
|
+
return new DateTruncOperation(this.cwj(), "QUARTER" /* QUARTER */, "First Day Of Quarter " + this.displayName());
|
|
1363
|
+
}
|
|
1364
|
+
/** The date of the first day of the year the date falls in. */
|
|
1365
|
+
firstDayOfYear() {
|
|
1366
|
+
return new DateTruncOperation(this.cwj(), "YEAR" /* YEAR */, "First Day Of Year " + this.displayName());
|
|
1367
|
+
}
|
|
1368
|
+
/** Add `n` days to this date. */
|
|
535
1369
|
addDays(n) {
|
|
536
1370
|
return new DateArithmeticOperation(this.cwj(), n, "DAY" /* DAY */, true, "Add Days " + this.displayName());
|
|
537
1371
|
}
|
|
1372
|
+
/** Add `n` months to this date. */
|
|
538
1373
|
addMonths(n) {
|
|
539
1374
|
return new DateArithmeticOperation(this.cwj(), n, "MONTH" /* MONTH */, true, "Add Months " + this.displayName());
|
|
540
1375
|
}
|
|
1376
|
+
/** Add `n` years to this date. */
|
|
541
1377
|
addYears(n) {
|
|
542
1378
|
return new DateArithmeticOperation(this.cwj(), n, "YEAR" /* YEAR */, true, "Add Years " + this.displayName());
|
|
543
1379
|
}
|
|
1380
|
+
/** Subtract `n` days from this date. */
|
|
544
1381
|
subtractDays(n) {
|
|
545
1382
|
return new DateArithmeticOperation(this.cwj(), n, "DAY" /* DAY */, false, "Subtract Days " + this.displayName());
|
|
546
1383
|
}
|
|
1384
|
+
/** Subtract `n` months from this date. */
|
|
547
1385
|
subtractMonths(n) {
|
|
548
1386
|
return new DateArithmeticOperation(this.cwj(), n, "MONTH" /* MONTH */, false, "Subtract Months " + this.displayName());
|
|
549
1387
|
}
|
|
1388
|
+
/** Subtract `n` years from this date. */
|
|
550
1389
|
subtractYears(n) {
|
|
551
1390
|
return new DateArithmeticOperation(this.cwj(), n, "YEAR" /* YEAR */, false, "Subtract Years " + this.displayName());
|
|
552
1391
|
}
|
|
1392
|
+
/** Number of whole days between this date and `other`. */
|
|
553
1393
|
diffDays(other) {
|
|
554
1394
|
return new DateDiffOperation(this.cwj(), other, "DAY" /* DAY */, "Diff Days " + this.displayName());
|
|
555
1395
|
}
|
|
1396
|
+
/** Number of whole months between this date and `other`. */
|
|
556
1397
|
diffMonths(other) {
|
|
557
1398
|
return new DateDiffOperation(this.cwj(), other, "MONTH" /* MONTH */, "Diff Months " + this.displayName());
|
|
558
1399
|
}
|
|
1400
|
+
/** Number of whole years between this date and `other`. */
|
|
559
1401
|
diffYears(other) {
|
|
560
1402
|
return new DateDiffOperation(this.cwj(), other, "YEAR" /* YEAR */, "Diff Years " + this.displayName());
|
|
561
1403
|
}
|
|
562
1404
|
};
|
|
563
1405
|
var DateTimeAttribute = class extends Attribute {
|
|
564
|
-
constructor(displayName, columnName, columnDbType, owner, parent) {
|
|
565
|
-
super(displayName, columnName, columnDbType, owner, parent);
|
|
1406
|
+
constructor(displayName, columnName, columnDbType, owner, parent, embedded, nullable = true, optional = false) {
|
|
1407
|
+
super(displayName, columnName, columnDbType, owner, parent, embedded, nullable, optional);
|
|
1408
|
+
}
|
|
1409
|
+
toConstant(value) {
|
|
1410
|
+
return temporalConstant(value);
|
|
566
1411
|
}
|
|
1412
|
+
/** Filter to rows where this timestamp equals `value`. */
|
|
567
1413
|
eq(value) {
|
|
568
|
-
return new ComparisonOperation(this.cwj(), "EQUAL" /* EQUAL */,
|
|
1414
|
+
return new ComparisonOperation(this.cwj(), "EQUAL" /* EQUAL */, temporalConstant(value));
|
|
569
1415
|
}
|
|
1416
|
+
/** Filter to rows where this timestamp does not equal `value`. */
|
|
570
1417
|
ne(value) {
|
|
571
|
-
return new ComparisonOperation(this.cwj(), "NOT_EQUAL" /* NOT_EQUAL */,
|
|
1418
|
+
return new ComparisonOperation(this.cwj(), "NOT_EQUAL" /* NOT_EQUAL */, temporalConstant(value));
|
|
572
1419
|
}
|
|
1420
|
+
/** Filter to rows where this timestamp is after `value`. */
|
|
573
1421
|
gt(value) {
|
|
574
|
-
return new ComparisonOperation(this.cwj(), "GREATER_THAN" /* GREATER_THAN */,
|
|
1422
|
+
return new ComparisonOperation(this.cwj(), "GREATER_THAN" /* GREATER_THAN */, temporalConstant(value));
|
|
575
1423
|
}
|
|
1424
|
+
/** Filter to rows where this timestamp is before `value`. */
|
|
576
1425
|
lt(value) {
|
|
577
|
-
return new ComparisonOperation(this.cwj(), "LESS_THAN" /* LESS_THAN */,
|
|
1426
|
+
return new ComparisonOperation(this.cwj(), "LESS_THAN" /* LESS_THAN */, temporalConstant(value));
|
|
578
1427
|
}
|
|
1428
|
+
/** Filter to rows where this timestamp is on or after `value`. */
|
|
579
1429
|
gte(value) {
|
|
580
|
-
return new ComparisonOperation(this.cwj(), "GREATER_THAN_OR_EQUAL_TO" /* GREATER_THAN_OR_EQUAL_TO */,
|
|
1430
|
+
return new ComparisonOperation(this.cwj(), "GREATER_THAN_OR_EQUAL_TO" /* GREATER_THAN_OR_EQUAL_TO */, temporalConstant(value));
|
|
581
1431
|
}
|
|
1432
|
+
/** Filter to rows where this timestamp is on or before `value`. */
|
|
582
1433
|
lte(value) {
|
|
583
|
-
return new ComparisonOperation(this.cwj(), "LESS_THAN_OR_EQUAL_TO" /* LESS_THAN_OR_EQUAL_TO */,
|
|
1434
|
+
return new ComparisonOperation(this.cwj(), "LESS_THAN_OR_EQUAL_TO" /* LESS_THAN_OR_EQUAL_TO */, temporalConstant(value));
|
|
584
1435
|
}
|
|
1436
|
+
/** Extract the four-digit calendar year. */
|
|
585
1437
|
year() {
|
|
586
1438
|
return new DateExtractOperation(this.cwj(), "YEAR" /* YEAR */, "Year " + this.displayName());
|
|
587
1439
|
}
|
|
1440
|
+
/** Extract the month number (1–12). */
|
|
588
1441
|
month() {
|
|
589
1442
|
return new DateExtractOperation(this.cwj(), "MONTH" /* MONTH */, "Month " + this.displayName());
|
|
590
1443
|
}
|
|
1444
|
+
/** Extract the day of the month (1–31). */
|
|
591
1445
|
day() {
|
|
592
1446
|
return new DateExtractOperation(this.cwj(), "DAY" /* DAY */, "Day " + this.displayName());
|
|
593
1447
|
}
|
|
1448
|
+
/** Extract the hour (0–23). */
|
|
594
1449
|
hour() {
|
|
595
1450
|
return new DateExtractOperation(this.cwj(), "HOUR" /* HOUR */, "Hour " + this.displayName());
|
|
596
1451
|
}
|
|
1452
|
+
/** Extract the minute (0–59). */
|
|
597
1453
|
minute() {
|
|
598
1454
|
return new DateExtractOperation(this.cwj(), "MINUTE" /* MINUTE */, "Minute " + this.displayName());
|
|
599
1455
|
}
|
|
1456
|
+
/** Extract the second (0–59). */
|
|
600
1457
|
second() {
|
|
601
1458
|
return new DateExtractOperation(this.cwj(), "SECOND" /* SECOND */, "Second " + this.displayName());
|
|
602
1459
|
}
|
|
1460
|
+
/** Extract the quarter (1–4). */
|
|
603
1461
|
quarter() {
|
|
604
1462
|
return new DateExtractOperation(this.cwj(), "QUARTER" /* QUARTER */, "Quarter " + this.displayName());
|
|
605
1463
|
}
|
|
1464
|
+
/** Extract the ISO week number (1–53). */
|
|
606
1465
|
week() {
|
|
607
1466
|
return new DateExtractOperation(this.cwj(), "WEEK" /* WEEK */, "Week " + this.displayName());
|
|
608
1467
|
}
|
|
1468
|
+
/** Extract the day of the week (0 = Sunday through 6 = Saturday). */
|
|
609
1469
|
dayOfWeek() {
|
|
610
1470
|
return new DateExtractOperation(this.cwj(), "DOW" /* DOW */, "Day Of Week " + this.displayName());
|
|
611
1471
|
}
|
|
1472
|
+
/** The date of the first day of the week the date falls in (a Monday). */
|
|
1473
|
+
firstDayOfWeek() {
|
|
1474
|
+
return new DateTruncOperation(this.cwj(), "WEEK" /* WEEK */, "First Day Of Week " + this.displayName());
|
|
1475
|
+
}
|
|
1476
|
+
/** The date of the first day of the month the date falls in. */
|
|
1477
|
+
firstDayOfMonth() {
|
|
1478
|
+
return new DateTruncOperation(this.cwj(), "MONTH" /* MONTH */, "First Day Of Month " + this.displayName());
|
|
1479
|
+
}
|
|
1480
|
+
/** The date of the first day of the quarter the date falls in. */
|
|
1481
|
+
firstDayOfQuarter() {
|
|
1482
|
+
return new DateTruncOperation(this.cwj(), "QUARTER" /* QUARTER */, "First Day Of Quarter " + this.displayName());
|
|
1483
|
+
}
|
|
1484
|
+
/** The date of the first day of the year the date falls in. */
|
|
1485
|
+
firstDayOfYear() {
|
|
1486
|
+
return new DateTruncOperation(this.cwj(), "YEAR" /* YEAR */, "First Day Of Year " + this.displayName());
|
|
1487
|
+
}
|
|
1488
|
+
/** Add `n` days to this timestamp. */
|
|
612
1489
|
addDays(n) {
|
|
613
1490
|
return new DateArithmeticOperation(this.cwj(), n, "DAY" /* DAY */, true, "Add Days " + this.displayName());
|
|
614
1491
|
}
|
|
1492
|
+
/** Add `n` months to this timestamp. */
|
|
615
1493
|
addMonths(n) {
|
|
616
1494
|
return new DateArithmeticOperation(this.cwj(), n, "MONTH" /* MONTH */, true, "Add Months " + this.displayName());
|
|
617
1495
|
}
|
|
1496
|
+
/** Add `n` years to this timestamp. */
|
|
618
1497
|
addYears(n) {
|
|
619
1498
|
return new DateArithmeticOperation(this.cwj(), n, "YEAR" /* YEAR */, true, "Add Years " + this.displayName());
|
|
620
1499
|
}
|
|
1500
|
+
/** Add `n` hours to this timestamp. */
|
|
621
1501
|
addHours(n) {
|
|
622
1502
|
return new DateArithmeticOperation(this.cwj(), n, "HOUR" /* HOUR */, true, "Add Hours " + this.displayName());
|
|
623
1503
|
}
|
|
1504
|
+
/** Add `n` minutes to this timestamp. */
|
|
624
1505
|
addMinutes(n) {
|
|
625
1506
|
return new DateArithmeticOperation(this.cwj(), n, "MINUTE" /* MINUTE */, true, "Add Minutes " + this.displayName());
|
|
626
1507
|
}
|
|
1508
|
+
/** Add `n` seconds to this timestamp. */
|
|
627
1509
|
addSeconds(n) {
|
|
628
1510
|
return new DateArithmeticOperation(this.cwj(), n, "SECOND" /* SECOND */, true, "Add Seconds " + this.displayName());
|
|
629
1511
|
}
|
|
1512
|
+
/** Subtract `n` days from this timestamp. */
|
|
630
1513
|
subtractDays(n) {
|
|
631
1514
|
return new DateArithmeticOperation(this.cwj(), n, "DAY" /* DAY */, false, "Subtract Days " + this.displayName());
|
|
632
1515
|
}
|
|
1516
|
+
/** Subtract `n` months from this timestamp. */
|
|
633
1517
|
subtractMonths(n) {
|
|
634
1518
|
return new DateArithmeticOperation(this.cwj(), n, "MONTH" /* MONTH */, false, "Subtract Months " + this.displayName());
|
|
635
1519
|
}
|
|
1520
|
+
/** Subtract `n` years from this timestamp. */
|
|
636
1521
|
subtractYears(n) {
|
|
637
1522
|
return new DateArithmeticOperation(this.cwj(), n, "YEAR" /* YEAR */, false, "Subtract Years " + this.displayName());
|
|
638
1523
|
}
|
|
1524
|
+
/** Subtract `n` hours from this timestamp. */
|
|
639
1525
|
subtractHours(n) {
|
|
640
1526
|
return new DateArithmeticOperation(this.cwj(), n, "HOUR" /* HOUR */, false, "Subtract Hours " + this.displayName());
|
|
641
1527
|
}
|
|
1528
|
+
/** Subtract `n` minutes from this timestamp. */
|
|
642
1529
|
subtractMinutes(n) {
|
|
643
1530
|
return new DateArithmeticOperation(this.cwj(), n, "MINUTE" /* MINUTE */, false, "Subtract Minutes " + this.displayName());
|
|
644
1531
|
}
|
|
1532
|
+
/** Subtract `n` seconds from this timestamp. */
|
|
645
1533
|
subtractSeconds(n) {
|
|
646
1534
|
return new DateArithmeticOperation(this.cwj(), n, "SECOND" /* SECOND */, false, "Subtract Seconds " + this.displayName());
|
|
647
1535
|
}
|
|
1536
|
+
/** Number of whole days between this timestamp and `other`. */
|
|
648
1537
|
diffDays(other) {
|
|
649
1538
|
return new DateDiffOperation(this.cwj(), other, "DAY" /* DAY */, "Diff Days " + this.displayName());
|
|
650
1539
|
}
|
|
1540
|
+
/** Number of whole months between this timestamp and `other`. */
|
|
651
1541
|
diffMonths(other) {
|
|
652
1542
|
return new DateDiffOperation(this.cwj(), other, "MONTH" /* MONTH */, "Diff Months " + this.displayName());
|
|
653
1543
|
}
|
|
1544
|
+
/** Number of whole years between this timestamp and `other`. */
|
|
654
1545
|
diffYears(other) {
|
|
655
1546
|
return new DateDiffOperation(this.cwj(), other, "YEAR" /* YEAR */, "Diff Years " + this.displayName());
|
|
656
1547
|
}
|
|
1548
|
+
/** Number of whole hours between this timestamp and `other`. */
|
|
657
1549
|
diffHours(other) {
|
|
658
1550
|
return new DateDiffOperation(this.cwj(), other, "HOUR" /* HOUR */, "Diff Hours " + this.displayName());
|
|
659
1551
|
}
|
|
1552
|
+
/** Number of whole minutes between this timestamp and `other`. */
|
|
660
1553
|
diffMinutes(other) {
|
|
661
1554
|
return new DateDiffOperation(this.cwj(), other, "MINUTE" /* MINUTE */, "Diff Minutes " + this.displayName());
|
|
662
1555
|
}
|
|
1556
|
+
/** Number of whole seconds between this timestamp and `other`. */
|
|
663
1557
|
diffSeconds(other) {
|
|
664
1558
|
return new DateDiffOperation(this.cwj(), other, "SECOND" /* SECOND */, "Diff Seconds " + this.displayName());
|
|
665
1559
|
}
|
|
666
1560
|
};
|
|
1561
|
+
applyMixins(DateAttribute, [MinMax]);
|
|
1562
|
+
applyMixins(DateTimeAttribute, [MinMax]);
|
|
667
1563
|
|
|
668
|
-
// src/datafinder/
|
|
669
|
-
var
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
1564
|
+
// src/datafinder/dialect.ts
|
|
1565
|
+
var doubleQuoted = (name) => '"' + name.replaceAll('"', '""') + '"';
|
|
1566
|
+
var quoted = (value) => "'" + value.replaceAll("'", "''") + "'";
|
|
1567
|
+
var SECONDS_PER = { ["HOUR" /* HOUR */]: 3600, ["MINUTE" /* MINUTE */]: 60, ["SECOND" /* SECOND */]: 1 };
|
|
1568
|
+
var POSTGRES = {
|
|
1569
|
+
name: "postgres",
|
|
1570
|
+
quoteIdentifier: doubleQuoted,
|
|
1571
|
+
stringLiteral: quoted,
|
|
1572
|
+
orderDirection: (direction) => direction === "ASC" /* ASC */ ? " ASC" : " DESC",
|
|
1573
|
+
doubleType: "DOUBLE PRECISION",
|
|
1574
|
+
dayOfWeek: (expression) => `EXTRACT(DOW FROM ${expression})`,
|
|
1575
|
+
dateDiff(unit, from, to) {
|
|
1576
|
+
const start = `CAST(${from} AS TIMESTAMP)`;
|
|
1577
|
+
const end = `CAST(${to} AS TIMESTAMP)`;
|
|
1578
|
+
switch (unit) {
|
|
1579
|
+
case "DAY" /* DAY */:
|
|
1580
|
+
return `(CAST(${to} AS DATE) - CAST(${from} AS DATE))`;
|
|
1581
|
+
case "MONTH" /* MONTH */:
|
|
1582
|
+
return `CAST(EXTRACT(YEAR FROM AGE(${end}, ${start})) * 12 + EXTRACT(MONTH FROM AGE(${end}, ${start})) AS BIGINT)`;
|
|
1583
|
+
case "YEAR" /* YEAR */:
|
|
1584
|
+
return `CAST(EXTRACT(YEAR FROM AGE(${end}, ${start})) AS BIGINT)`;
|
|
1585
|
+
default: {
|
|
1586
|
+
const seconds = SECONDS_PER[unit];
|
|
1587
|
+
if (seconds === void 0) throw new Error(`Cannot take the difference in ${unit}`);
|
|
1588
|
+
return `CAST(FLOOR(EXTRACT(EPOCH FROM (${end} - ${start})) / ${seconds}) AS BIGINT)`;
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
},
|
|
1592
|
+
stringAgg: (expression, separator, orderBy) => `STRING_AGG(${expression}, ${separator}${orderBy.length > 0 ? " ORDER BY " + orderBy.join(", ") : ""})`
|
|
678
1593
|
};
|
|
679
|
-
var
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
1594
|
+
var DUCKDB = {
|
|
1595
|
+
...POSTGRES,
|
|
1596
|
+
name: "duckdb",
|
|
1597
|
+
// DuckDB sorts nulls last whichever way the sort goes
|
|
1598
|
+
orderDirection: (direction) => direction === "ASC" /* ASC */ ? " ASC" : " DESC NULLS FIRST",
|
|
1599
|
+
doubleType: "DOUBLE",
|
|
1600
|
+
dateDiff: (unit, from, to) => `DATE_DIFF('${unit.toLowerCase()}', ${from}, ${to})`
|
|
1601
|
+
};
|
|
1602
|
+
var DATABRICKS = {
|
|
1603
|
+
name: "databricks",
|
|
1604
|
+
// a double-quoted token is a string in Databricks; identifiers take backticks
|
|
1605
|
+
quoteIdentifier: (name) => "`" + name.replaceAll("`", "``") + "`",
|
|
1606
|
+
// a backslash starts an escape in a Databricks string literal, and a doubled quote is not one: Spark reads
|
|
1607
|
+
// 'it''s' as the two literals 'it' and 's' and joins them, losing the quote. A quote is escaped with a backslash.
|
|
1608
|
+
stringLiteral: (value) => "'" + value.replaceAll("\\", "\\\\").replaceAll("'", "\\'") + "'",
|
|
1609
|
+
// Databricks sorts nulls first when ascending, last when descending
|
|
1610
|
+
orderDirection: (direction) => direction === "ASC" /* ASC */ ? " ASC NULLS LAST" : " DESC NULLS FIRST",
|
|
1611
|
+
doubleType: "DOUBLE",
|
|
1612
|
+
// DAYOFWEEK is 1 = Sunday through 7 = Saturday
|
|
1613
|
+
dayOfWeek: (expression) => `(DAYOFWEEK(${expression}) - 1)`,
|
|
1614
|
+
dateDiff: (unit, from, to) => `DATEDIFF(${unit}, ${from}, ${to})`,
|
|
1615
|
+
stringAgg: (expression, separator, orderBy) => `LISTAGG(${expression}, ${separator})${orderBy.length > 0 ? " WITHIN GROUP (ORDER BY " + orderBy.join(", ") + ")" : ""}`
|
|
688
1616
|
};
|
|
1617
|
+
var DIALECTS = { postgres: POSTGRES, duckdb: DUCKDB, databricks: DATABRICKS };
|
|
1618
|
+
function dialectOf(dialect) {
|
|
1619
|
+
if (typeof dialect !== "string") return dialect;
|
|
1620
|
+
const found = DIALECTS[dialect];
|
|
1621
|
+
if (found === void 0) throw new Error(`Unknown SQL dialect '${dialect}': one of ${Object.keys(DIALECTS).join(", ")}`);
|
|
1622
|
+
return found;
|
|
1623
|
+
}
|
|
689
1624
|
|
|
690
1625
|
// src/datafinder/sql-generator.ts
|
|
691
|
-
var Alias = class {
|
|
692
|
-
constructor(element, name) {
|
|
693
|
-
this.element = element;
|
|
694
|
-
this.name = name;
|
|
695
|
-
}
|
|
696
|
-
element;
|
|
697
|
-
name;
|
|
698
|
-
};
|
|
699
1626
|
var TableAlias = class {
|
|
700
1627
|
constructor(table, alias) {
|
|
701
1628
|
this.table = table;
|
|
@@ -722,22 +1649,12 @@ var Join = class {
|
|
|
722
1649
|
source;
|
|
723
1650
|
target;
|
|
724
1651
|
filterOp;
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
this.orderBy = orderBy;
|
|
731
|
-
this.groupBy = groupBy;
|
|
732
|
-
this.limit = limit;
|
|
733
|
-
this.table = table;
|
|
1652
|
+
/** `source = target`, written with the key column first as Legend writes a join defined as key = foreign key. */
|
|
1653
|
+
condition() {
|
|
1654
|
+
let [first, second] = [this.source, this.target];
|
|
1655
|
+
if (second.column.primaryKey && !first.column.primaryKey) [first, second] = [second, first];
|
|
1656
|
+
return first.tableAlias.alias + "." + first.column.name + " = " + second.tableAlias.alias + "." + second.column.name;
|
|
734
1657
|
}
|
|
735
|
-
display;
|
|
736
|
-
filter;
|
|
737
|
-
orderBy;
|
|
738
|
-
groupBy;
|
|
739
|
-
limit;
|
|
740
|
-
table;
|
|
741
1658
|
};
|
|
742
1659
|
function sqlFormatDatetime(value) {
|
|
743
1660
|
const pad = (n, w = 2) => String(n).padStart(w, "0");
|
|
@@ -764,6 +1681,13 @@ var COMPARISON_OPERATOR_STR = {
|
|
|
764
1681
|
var AGGREGATE_SQL_NAMES = {
|
|
765
1682
|
["AVERAGE" /* AVERAGE */]: "AVG"
|
|
766
1683
|
};
|
|
1684
|
+
var GUARDED_COMPARISONS = /* @__PURE__ */ new Set([
|
|
1685
|
+
"LESS_THAN" /* LESS_THAN */,
|
|
1686
|
+
"GREATER_THAN" /* GREATER_THAN */,
|
|
1687
|
+
"LESS_THAN_OR_EQUAL_TO" /* LESS_THAN_OR_EQUAL_TO */,
|
|
1688
|
+
"GREATER_THAN_OR_EQUAL_TO" /* GREATER_THAN_OR_EQUAL_TO */,
|
|
1689
|
+
"LIKE" /* LIKE */
|
|
1690
|
+
]);
|
|
767
1691
|
var WINDOW_SQL_NAMES = {
|
|
768
1692
|
["ROW_NUMBER" /* ROW_NUMBER */]: "ROW_NUMBER",
|
|
769
1693
|
["RANK" /* RANK */]: "RANK",
|
|
@@ -795,31 +1719,63 @@ var SCALAR_SQL_NAMES = {
|
|
|
795
1719
|
["RIGHT" /* RIGHT */]: "RIGHT",
|
|
796
1720
|
["REPEAT" /* REPEAT */]: "REPEAT",
|
|
797
1721
|
["REPLACE" /* REPLACE */]: "REPLACE",
|
|
798
|
-
["SUBSTRING" /* SUBSTRING */]: "SUBSTRING"
|
|
1722
|
+
["SUBSTRING" /* SUBSTRING */]: "SUBSTRING",
|
|
1723
|
+
["COALESCE" /* COALESCE */]: "COALESCE"
|
|
799
1724
|
};
|
|
800
|
-
function constantValueString(op) {
|
|
801
|
-
if (op instanceof StringConstantOperation) return
|
|
1725
|
+
function constantValueString(op, d) {
|
|
1726
|
+
if (op instanceof StringConstantOperation) return d.stringLiteral(op.value);
|
|
802
1727
|
if (op instanceof DateConstantOperation) return sqlFormatDate(op.value);
|
|
803
1728
|
if (op instanceof DateTimeConstantOperation) return sqlFormatDatetime(op.value);
|
|
804
1729
|
if (op instanceof IntegerConstantOperation) return String(op.value);
|
|
805
|
-
if (op instanceof FloatConstantOperation) return String(op.value);
|
|
1730
|
+
if (op instanceof FloatConstantOperation) return Number.isInteger(op.value) && Math.abs(op.value) < 1e21 ? op.value.toFixed(1) : String(op.value);
|
|
806
1731
|
if (op instanceof BooleanConstantOperation) return op.value ? "TRUE" : "FALSE";
|
|
807
1732
|
if (op instanceof DecimalConstantOperation) return String(op.value);
|
|
808
1733
|
throw new Error("Unknown constant operation");
|
|
809
1734
|
}
|
|
810
|
-
function
|
|
1735
|
+
function selectedConstantString(op, d) {
|
|
1736
|
+
if (op instanceof FloatConstantOperation) return "CAST(" + constantValueString(op, d) + " AS " + d.doubleType + ")";
|
|
1737
|
+
if (op instanceof DateTimeConstantOperation) return "TIMESTAMP " + constantValueString(op, d);
|
|
1738
|
+
if (op instanceof DateConstantOperation) return "DATE " + constantValueString(op, d);
|
|
1739
|
+
return constantValueString(op, d);
|
|
1740
|
+
}
|
|
1741
|
+
function windowSpecToString(window, d) {
|
|
811
1742
|
const parts = [];
|
|
812
1743
|
if (window.partitionBy.length > 0) {
|
|
813
|
-
parts.push("PARTITION BY " + window.partitionBy.map((p) => sqlOperationToString(p)).join(", "));
|
|
1744
|
+
parts.push("PARTITION BY " + window.partitionBy.map((p) => sqlOperationToString(p, d)).join(", "));
|
|
814
1745
|
}
|
|
815
1746
|
if (window.orderBy.length > 0) {
|
|
816
1747
|
parts.push("ORDER BY " + window.orderBy.map(
|
|
817
|
-
(s) => sqlOperationToString(s.column) + (s.direction
|
|
1748
|
+
(s) => sqlOperationToString(s.column, d) + d.orderDirection(s.direction)
|
|
818
1749
|
).join(", "));
|
|
819
1750
|
}
|
|
820
1751
|
return "OVER (" + parts.join(" ") + ")";
|
|
821
1752
|
}
|
|
822
|
-
|
|
1753
|
+
var ARITHMETIC_PRECEDENCE = {
|
|
1754
|
+
["+" /* ADD */]: 1,
|
|
1755
|
+
["-" /* SUBTRACT */]: 1,
|
|
1756
|
+
["*" /* MULTIPLY */]: 2,
|
|
1757
|
+
["/" /* DIVIDE */]: 2
|
|
1758
|
+
};
|
|
1759
|
+
function arithmeticNeedsParentheses(parent, child, onRight) {
|
|
1760
|
+
if (!(child instanceof ArithmeticOperation)) return false;
|
|
1761
|
+
const here = ARITHMETIC_PRECEDENCE[parent.operator];
|
|
1762
|
+
const there = ARITHMETIC_PRECEDENCE[child.operator];
|
|
1763
|
+
return there < here || there === here && onRight && (parent.operator === "-" /* SUBTRACT */ || parent.operator === "/" /* DIVIDE */);
|
|
1764
|
+
}
|
|
1765
|
+
function operandString(operation, d) {
|
|
1766
|
+
return operation instanceof ConstantOperation ? constantValueString(operation, d) : sqlOperationToString(operation, d);
|
|
1767
|
+
}
|
|
1768
|
+
var RenderedSql = class extends RelationalOperationElement {
|
|
1769
|
+
constructor(sql) {
|
|
1770
|
+
super();
|
|
1771
|
+
this.sql = sql;
|
|
1772
|
+
}
|
|
1773
|
+
sql;
|
|
1774
|
+
};
|
|
1775
|
+
function isCondition(op) {
|
|
1776
|
+
return op instanceof ComparisonOperation || op instanceof LogicalOperation || op instanceof IsNullOperation || op instanceof IsNotNullOperation || op instanceof InOperation || op instanceof NotInOperation || op instanceof ExistsOperation || op instanceof NotExistsOperation;
|
|
1777
|
+
}
|
|
1778
|
+
function sqlOperationToString(operation, d) {
|
|
823
1779
|
if (operation instanceof TableAliasColumn) {
|
|
824
1780
|
return operation.tableAlias.alias + "." + operation.column.name;
|
|
825
1781
|
}
|
|
@@ -827,49 +1783,77 @@ function sqlOperationToString(operation) {
|
|
|
827
1783
|
const fn = WINDOW_SQL_NAMES[operation.func];
|
|
828
1784
|
const parts = [];
|
|
829
1785
|
if (operation.element !== null && operation.element !== void 0) {
|
|
830
|
-
parts.push(sqlOperationToString(operation.element));
|
|
1786
|
+
parts.push(sqlOperationToString(operation.element, d));
|
|
831
1787
|
}
|
|
832
1788
|
if (operation.secondArg !== void 0) parts.push(String(operation.secondArg));
|
|
833
1789
|
for (const arg of operation.extraArgs) {
|
|
834
|
-
parts.push(typeof arg === "string" ?
|
|
1790
|
+
parts.push(typeof arg === "string" ? d.stringLiteral(arg) : String(arg));
|
|
835
1791
|
}
|
|
836
1792
|
const sql = fn + "(" + parts.join(", ") + ")";
|
|
837
|
-
return sql + (operation.window !== void 0 ? " " + windowSpecToString(operation.window) : " OVER ()");
|
|
1793
|
+
return sql + (operation.window !== void 0 ? " " + windowSpecToString(operation.window, d) : " OVER ()");
|
|
1794
|
+
}
|
|
1795
|
+
if (operation instanceof AggregateOperation && operation.operator === "COUNT_DISTINCT" /* COUNT_DISTINCT */) {
|
|
1796
|
+
return "COUNT(DISTINCT " + sqlOperationToString(operation.element, d) + ")";
|
|
1797
|
+
}
|
|
1798
|
+
if (operation instanceof AggregateOperation && operation.operator === "STRING_AGG" /* STRING_AGG */) {
|
|
1799
|
+
let sql = d.stringAgg(
|
|
1800
|
+
sqlOperationToString(operation.element, d),
|
|
1801
|
+
d.stringLiteral(operation.separator ?? ""),
|
|
1802
|
+
operation.orderBy.map((s) => sqlOperationToString(s.column, d) + d.orderDirection(s.direction))
|
|
1803
|
+
);
|
|
1804
|
+
if (operation.window !== void 0) sql += " " + windowSpecToString(operation.window, d);
|
|
1805
|
+
return sql;
|
|
838
1806
|
}
|
|
839
1807
|
if (operation instanceof AggregateOperation) {
|
|
840
1808
|
const fn = AGGREGATE_SQL_NAMES[operation.operator] ?? operation.operator;
|
|
841
|
-
let sql = fn + "(" + sqlOperationToString(operation.element) + ")";
|
|
1809
|
+
let sql = fn + "(" + sqlOperationToString(operation.element, d) + ")";
|
|
842
1810
|
if (operation.window !== void 0) {
|
|
843
|
-
sql += " " + windowSpecToString(operation.window);
|
|
1811
|
+
sql += " " + windowSpecToString(operation.window, d);
|
|
844
1812
|
}
|
|
845
1813
|
return sql;
|
|
846
1814
|
}
|
|
847
1815
|
if (operation instanceof ScalarFunctionOperation) {
|
|
848
1816
|
const fn = SCALAR_SQL_NAMES[operation.func];
|
|
849
|
-
const parts = [sqlOperationToString(operation.element)];
|
|
1817
|
+
const parts = [sqlOperationToString(operation.element, d)];
|
|
850
1818
|
if (operation.secondArg !== void 0) parts.push(String(operation.secondArg));
|
|
851
1819
|
for (const arg of operation.extraArgs) {
|
|
852
|
-
parts.push(typeof arg === "string" ?
|
|
1820
|
+
parts.push(typeof arg === "string" ? d.stringLiteral(arg) : String(arg));
|
|
853
1821
|
}
|
|
854
1822
|
return fn + "(" + parts.join(", ") + ")";
|
|
855
1823
|
}
|
|
856
1824
|
if (operation instanceof DateExtractOperation) {
|
|
857
|
-
|
|
1825
|
+
const element = sqlOperationToString(operation.element, d);
|
|
1826
|
+
return operation.part === "DOW" /* DOW */ ? d.dayOfWeek(element) : "EXTRACT(" + operation.part + " FROM " + element + ")";
|
|
1827
|
+
}
|
|
1828
|
+
if (operation instanceof DateTruncOperation) {
|
|
1829
|
+
return "CAST(DATE_TRUNC('" + operation.part.toLowerCase() + "', " + sqlOperationToString(operation.element, d) + ") AS DATE)";
|
|
858
1830
|
}
|
|
859
1831
|
if (operation instanceof DateArithmeticOperation) {
|
|
860
1832
|
const op = operation.isAdd ? "+" : "-";
|
|
861
|
-
return sqlOperationToString(operation.element) + " " + op + " INTERVAL " + operation.n + " " + operation.unit;
|
|
1833
|
+
return sqlOperationToString(operation.element, d) + " " + op + " INTERVAL '" + operation.n + "' " + operation.unit;
|
|
862
1834
|
}
|
|
863
1835
|
if (operation instanceof DateDiffOperation) {
|
|
864
|
-
|
|
865
|
-
return "DATE_DIFF('" + operation.unit.toLowerCase() + "', " + sqlOperationToString(operation.element) + ", " + otherSql + ")";
|
|
1836
|
+
return d.dateDiff(operation.unit, sqlOperationToString(operation.element, d), "TIMESTAMP " + sqlFormatDatetime(operation.other));
|
|
866
1837
|
}
|
|
867
1838
|
if (operation instanceof CountAllOperation) return "COUNT(*)";
|
|
1839
|
+
if (operation instanceof ConstantOperation) return selectedConstantString(operation, d);
|
|
1840
|
+
if (operation instanceof RenderedSql) return operation.sql;
|
|
1841
|
+
if (operation instanceof ConcatOperation) return operation.parts.map((part) => operandString(part, d)).join(" || ");
|
|
1842
|
+
if (operation instanceof ArithmeticOperation) {
|
|
1843
|
+
let left = operandString(operation.left, d);
|
|
1844
|
+
let right = operandString(operation.right, d);
|
|
1845
|
+
if (arithmeticNeedsParentheses(operation, operation.left, false)) left = "(" + left + ")";
|
|
1846
|
+
if (arithmeticNeedsParentheses(operation, operation.right, true)) right = "(" + right + ")";
|
|
1847
|
+
return left + " " + operation.operator + " " + right;
|
|
1848
|
+
}
|
|
868
1849
|
if (operation instanceof Alias) {
|
|
869
|
-
return sqlOperationToString(operation.element) +
|
|
1850
|
+
return sqlOperationToString(operation.element, d) + " AS " + d.quoteIdentifier(operation.name);
|
|
870
1851
|
}
|
|
871
1852
|
throw new TypeError("Unknown operation in sqlOperationToString: " + operation.constructor.name);
|
|
872
1853
|
}
|
|
1854
|
+
function embeddedOf(ref) {
|
|
1855
|
+
return ref instanceof Attribute ? ref.embedded() : ref.embedded;
|
|
1856
|
+
}
|
|
873
1857
|
function findColumn(operation) {
|
|
874
1858
|
if (operation instanceof UnaryOperation) return findColumn(operation.element);
|
|
875
1859
|
if (operation instanceof ColumnWithJoin) return operation;
|
|
@@ -883,89 +1867,195 @@ function openEndClause(endAttr, value, infiniteDatetime) {
|
|
|
883
1867
|
}
|
|
884
1868
|
return gtOp;
|
|
885
1869
|
}
|
|
1870
|
+
function andAll(ops) {
|
|
1871
|
+
const present = ops.filter((op) => op !== null);
|
|
1872
|
+
if (present.length === 0) return null;
|
|
1873
|
+
return present.slice(1).reduce((left, right) => new LogicalOperation(left, "AND" /* AND */, right), present[0]);
|
|
1874
|
+
}
|
|
1875
|
+
function processingPredicate(mc, processingDatetime, joinNode) {
|
|
1876
|
+
if (!(mc instanceof ProcessingTemporalColumns || mc instanceof BusinessDateAndProcessingTemporalColumns || mc instanceof BiTemporalColumns) || processingDatetime === null) return null;
|
|
1877
|
+
const startAt = new DateTimeAttribute("start_at", mc.startAtColumn.name, mc.startAtColumn.type, mc.startAtColumn.table.qualifiedName, joinNode);
|
|
1878
|
+
const endAt = new DateTimeAttribute("end_at", mc.endAtColumn.name, mc.endAtColumn.type, mc.endAtColumn.table.qualifiedName, joinNode);
|
|
1879
|
+
return new LogicalOperation(startAt.lte(processingDatetime), "AND" /* AND */, openEndClause(endAt, processingDatetime, mc.infiniteDatetime));
|
|
1880
|
+
}
|
|
1881
|
+
function businessPredicate(mc, businessDate, joinNode) {
|
|
1882
|
+
if (businessDate === null) return null;
|
|
1883
|
+
if (mc instanceof BiTemporalColumns) {
|
|
1884
|
+
const dateFrom = new DateAttribute("business_date_from", mc.businessDateFromColumn.name, mc.businessDateFromColumn.type, mc.businessDateFromColumn.table.qualifiedName, joinNode);
|
|
1885
|
+
const dateTo = new DateAttribute("business_date_to", mc.businessDateToColumn.name, mc.businessDateToColumn.type, mc.businessDateToColumn.table.qualifiedName, joinNode);
|
|
1886
|
+
return new LogicalOperation(dateFrom.lte(businessDate), "AND" /* AND */, openEndClause(dateTo, businessDate, mc.infiniteDatetime));
|
|
1887
|
+
}
|
|
1888
|
+
if (mc instanceof BusinessDateAndProcessingTemporalColumns || mc instanceof SingleBusinessDateColumn) {
|
|
1889
|
+
const businessAtt = new DateAttribute("business_date", mc.businessDateColumn.name, mc.businessDateColumn.type, mc.businessDateColumn.table.qualifiedName, joinNode);
|
|
1890
|
+
return businessAtt.eq(businessDate);
|
|
1891
|
+
}
|
|
1892
|
+
return null;
|
|
1893
|
+
}
|
|
1894
|
+
function businessRangePredicate(mc, businessDateFrom, businessDateTo, joinNode) {
|
|
1895
|
+
if (businessDateFrom === null || businessDateTo === null) return null;
|
|
1896
|
+
if (mc instanceof BiTemporalColumns) {
|
|
1897
|
+
const dateFrom = new DateAttribute("business_date_from", mc.businessDateFromColumn.name, mc.businessDateFromColumn.type, mc.businessDateFromColumn.table.qualifiedName, joinNode);
|
|
1898
|
+
const dateTo = new DateAttribute("business_date_to", mc.businessDateToColumn.name, mc.businessDateToColumn.type, mc.businessDateToColumn.table.qualifiedName, joinNode);
|
|
1899
|
+
return new LogicalOperation(dateFrom.lte(businessDateTo), "AND" /* AND */, openEndClause(dateTo, businessDateFrom, mc.infiniteDatetime));
|
|
1900
|
+
}
|
|
1901
|
+
if (mc instanceof BusinessDateAndProcessingTemporalColumns || mc instanceof SingleBusinessDateColumn) {
|
|
1902
|
+
const businessAtt = new DateAttribute("business_date", mc.businessDateColumn.name, mc.businessDateColumn.type, mc.businessDateColumn.table.qualifiedName, joinNode);
|
|
1903
|
+
return new LogicalOperation(businessAtt.gte(businessDateFrom), "AND" /* AND */, businessAtt.lte(businessDateTo));
|
|
1904
|
+
}
|
|
1905
|
+
return null;
|
|
1906
|
+
}
|
|
886
1907
|
function buildMilestoningFilterOperation(businessDate, processingDatetime, table, joinNode) {
|
|
887
1908
|
const mc = table.milestoningColumns;
|
|
1909
|
+
return andAll([processingPredicate(mc, processingDatetime, joinNode), businessPredicate(mc, businessDate, joinNode)]);
|
|
1910
|
+
}
|
|
1911
|
+
function buildMilestoningFilterOperationForDateRange(businessDateFrom, businessDateTo, processingDatetime, table, joinNode) {
|
|
1912
|
+
const mc = table.milestoningColumns;
|
|
1913
|
+
return andAll([
|
|
1914
|
+
processingPredicate(mc, processingDatetime, joinNode),
|
|
1915
|
+
businessRangePredicate(mc, businessDateFrom, businessDateTo, joinNode)
|
|
1916
|
+
]);
|
|
1917
|
+
}
|
|
1918
|
+
function walkRefs(op, visit, visitExists) {
|
|
1919
|
+
if (op === null || op === void 0) return;
|
|
1920
|
+
if (op instanceof Attribute || op instanceof ColumnWithJoin) {
|
|
1921
|
+
visit(op);
|
|
1922
|
+
} else if (op instanceof ExistsOperation || op instanceof NotExistsOperation) {
|
|
1923
|
+
visitExists?.(op.node);
|
|
1924
|
+
} else if (op instanceof AggregateOperation) {
|
|
1925
|
+
walkRefs(op.element, visit, visitExists);
|
|
1926
|
+
if (op.window) walkWindowSpec(op.window, visit, visitExists);
|
|
1927
|
+
for (const sort of op.orderBy) walkRefs(sort, visit, visitExists);
|
|
1928
|
+
} else if (op instanceof WindowFunctionOperation) {
|
|
1929
|
+
if (op.element) walkRefs(op.element, visit, visitExists);
|
|
1930
|
+
if (op.window) walkWindowSpec(op.window, visit, visitExists);
|
|
1931
|
+
} else if (op instanceof ScalarFunctionOperation || op instanceof DateExtractOperation || op instanceof DateTruncOperation || op instanceof DateArithmeticOperation || op instanceof DateDiffOperation || op instanceof IsNullOperation || op instanceof IsNotNullOperation || op instanceof InOperation || op instanceof NotInOperation) {
|
|
1932
|
+
walkRefs(op.element, visit, visitExists);
|
|
1933
|
+
} else if (op instanceof Alias) {
|
|
1934
|
+
walkRefs(op.element, visit, visitExists);
|
|
1935
|
+
} else if (op instanceof ConcatOperation) {
|
|
1936
|
+
for (const part of op.parts) walkRefs(part, visit, visitExists);
|
|
1937
|
+
} else if (op instanceof ArithmeticOperation) {
|
|
1938
|
+
walkRefs(op.left, visit, visitExists);
|
|
1939
|
+
walkRefs(op.right, visit, visitExists);
|
|
1940
|
+
} else if (op instanceof CaseOperation) {
|
|
1941
|
+
walkRefs(op.condition, visit, visitExists);
|
|
1942
|
+
walkRefs(op.then, visit, visitExists);
|
|
1943
|
+
walkRefs(op.fallback, visit, visitExists);
|
|
1944
|
+
} else if (op instanceof SortOperation) {
|
|
1945
|
+
walkRefs(op.column, visit, visitExists);
|
|
1946
|
+
} else if (op instanceof LogicalOperation || op instanceof ComparisonOperation) {
|
|
1947
|
+
walkRefs(op.left, visit, visitExists);
|
|
1948
|
+
walkRefs(op.right, visit, visitExists);
|
|
1949
|
+
}
|
|
1950
|
+
}
|
|
1951
|
+
function walkWindowSpec(window, visit, visitExists) {
|
|
1952
|
+
for (const p of window.partitionBy) walkRefs(p, visit, visitExists);
|
|
1953
|
+
for (const s of window.orderBy) walkRefs(s.column, visit, visitExists);
|
|
1954
|
+
}
|
|
1955
|
+
function buildJoinFilterFromProperties(node, filter, columnMap) {
|
|
888
1956
|
const ops = [];
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
ops.push(new LogicalOperation(dateFrom.lte(businessDate), "AND" /* AND */, openEndClause(dateTo, businessDate, mc.infiniteDatetime)));
|
|
894
|
-
}
|
|
895
|
-
if (processingDatetime !== null) {
|
|
896
|
-
const startAt = new DateTimeAttribute("start_at", mc.startAtColumn.name, mc.startAtColumn.type, mc.startAtColumn.table.qualifiedName, joinNode);
|
|
897
|
-
const endAt = new DateTimeAttribute("end_at", mc.endAtColumn.name, mc.endAtColumn.type, mc.endAtColumn.table.qualifiedName, joinNode);
|
|
898
|
-
ops.push(new LogicalOperation(startAt.lte(processingDatetime), "AND" /* AND */, openEndClause(endAt, processingDatetime, mc.infiniteDatetime)));
|
|
899
|
-
}
|
|
900
|
-
} else if (mc instanceof BusinessDateAndProcessingTemporalColumns) {
|
|
901
|
-
if (businessDate !== null) {
|
|
902
|
-
const businessAtt = new DateAttribute("business_date", mc.businessDateColumn.name, mc.businessDateColumn.type, mc.businessDateColumn.table.qualifiedName, joinNode);
|
|
903
|
-
ops.push(businessAtt.eq(businessDate));
|
|
1957
|
+
for (const [key, value] of Object.entries(filter)) {
|
|
1958
|
+
const entry = columnMap[key];
|
|
1959
|
+
if (entry === void 0) {
|
|
1960
|
+
throw new Error(`Unknown property '${key}' \u2014 valid properties are: ${Object.keys(columnMap).sort().join(", ")}`);
|
|
904
1961
|
}
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
const businessAtt = new DateAttribute("business_date", mc.businessDateColumn.name, mc.businessDateColumn.type, mc.businessDateColumn.table.qualifiedName, joinNode);
|
|
916
|
-
ops.push(businessAtt.eq(businessDate));
|
|
917
|
-
}
|
|
918
|
-
if (ops.length === 0) return null;
|
|
919
|
-
if (ops.length === 1) return ops[0];
|
|
920
|
-
return new LogicalOperation(ops[0], "AND" /* AND */, ops[1]);
|
|
1962
|
+
const [name, type, table] = entry;
|
|
1963
|
+
const col = new ColumnWithJoin(new Column(name, type, table), node);
|
|
1964
|
+
let constant;
|
|
1965
|
+
if (typeof value === "boolean") constant = new BooleanConstantOperation(value);
|
|
1966
|
+
else if (typeof value === "number") constant = Number.isInteger(value) ? new IntegerConstantOperation(value) : new FloatConstantOperation(value);
|
|
1967
|
+
else if (value instanceof Date) constant = type.toUpperCase() === "DATE" ? new DateConstantOperation(value) : new DateTimeConstantOperation(value);
|
|
1968
|
+
else constant = new StringConstantOperation(String(value));
|
|
1969
|
+
ops.push(new ComparisonOperation(col, "EQUAL" /* EQUAL */, constant));
|
|
1970
|
+
}
|
|
1971
|
+
return ops.reduce((acc, op) => new LogicalOperation(acc, "AND" /* AND */, op));
|
|
921
1972
|
}
|
|
922
|
-
function
|
|
1973
|
+
function withAncestors(nodes) {
|
|
1974
|
+
const ordered = /* @__PURE__ */ new Set();
|
|
1975
|
+
const add = (node) => {
|
|
1976
|
+
if (ordered.has(node)) return;
|
|
1977
|
+
if (node.parent !== void 0) add(node.parent);
|
|
1978
|
+
ordered.add(node);
|
|
1979
|
+
};
|
|
1980
|
+
for (const node of nodes) add(node);
|
|
1981
|
+
return [...ordered];
|
|
1982
|
+
}
|
|
1983
|
+
function buildQueryOperation(businessDate, processingDatetime, columns, table, op, orderBy = [], groupBy = [], limit, businessDateTo = null, distinct = false, offset, having) {
|
|
923
1984
|
let filter = op;
|
|
1985
|
+
const milestoningFor = (t, node) => businessDateTo !== null ? buildMilestoningFilterOperationForDateRange(businessDate, businessDateTo, processingDatetime, t, node) : buildMilestoningFilterOperation(businessDate, processingDatetime, t, node);
|
|
924
1986
|
if (table instanceof MilestonedTable) {
|
|
925
|
-
const milestonedOp =
|
|
1987
|
+
const milestonedOp = milestoningFor(table);
|
|
926
1988
|
if (milestonedOp !== null) {
|
|
927
1989
|
filter = filter instanceof NoOperation ? milestonedOp : new LogicalOperation(filter, "AND" /* AND */, milestonedOp);
|
|
928
1990
|
}
|
|
929
1991
|
}
|
|
930
|
-
const requiredJoins =
|
|
931
|
-
const
|
|
932
|
-
|
|
933
|
-
if (
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
1992
|
+
const requiredJoins = /* @__PURE__ */ new Set();
|
|
1993
|
+
const collect = (ref) => {
|
|
1994
|
+
const parent = ref instanceof Attribute ? ref.parent() : ref.parent;
|
|
1995
|
+
if (parent !== void 0) requiredJoins.add(parent);
|
|
1996
|
+
};
|
|
1997
|
+
const collectNode = (node) => requiredJoins.add(node);
|
|
1998
|
+
for (const col of columns) walkRefs(col, collect, collectNode);
|
|
1999
|
+
for (const expr of groupBy) walkRefs(expr, collect, collectNode);
|
|
2000
|
+
for (const sort of orderBy) walkRefs(sort, collect, collectNode);
|
|
2001
|
+
walkRefs(op, collect, collectNode);
|
|
2002
|
+
const joinFilters = /* @__PURE__ */ new Map();
|
|
2003
|
+
for (const node of withAncestors(requiredJoins)) {
|
|
2004
|
+
let combined;
|
|
2005
|
+
if (Object.keys(node.join.filterKwargs).length > 0) {
|
|
2006
|
+
combined = buildJoinFilterFromProperties(node, node.join.filterKwargs, node.join.filterColumnMap);
|
|
943
2007
|
}
|
|
944
|
-
}
|
|
945
|
-
for (const node of requiredJoins) {
|
|
946
2008
|
if (node.join.target instanceof MilestonedTable) {
|
|
947
|
-
const milestonedOp =
|
|
2009
|
+
const milestonedOp = milestoningFor(node.join.target, node);
|
|
948
2010
|
if (milestonedOp !== null) {
|
|
949
|
-
|
|
2011
|
+
combined = combined === void 0 ? milestonedOp : new LogicalOperation(combined, "AND" /* AND */, milestonedOp);
|
|
950
2012
|
}
|
|
951
2013
|
}
|
|
2014
|
+
if (combined !== void 0) joinFilters.set(node, combined);
|
|
952
2015
|
}
|
|
953
|
-
return new SelectOperation(columns, filter, orderBy, groupBy, limit, table);
|
|
2016
|
+
return new SelectOperation(columns, filter, orderBy, groupBy, limit, table, joinFilters, distinct, offset, having);
|
|
2017
|
+
}
|
|
2018
|
+
function needsParentheses(parent, child) {
|
|
2019
|
+
return child instanceof LogicalOperation && child.operator !== parent.operator;
|
|
2020
|
+
}
|
|
2021
|
+
function reachesToMany(op) {
|
|
2022
|
+
if (op instanceof ColumnWithJoin) {
|
|
2023
|
+
for (let node = op.parent; node !== void 0; node = node.parent) if (node.many) return true;
|
|
2024
|
+
return false;
|
|
2025
|
+
}
|
|
2026
|
+
if (op instanceof UnaryOperation || op instanceof Alias) return reachesToMany(op.element);
|
|
2027
|
+
if (op instanceof BinaryOperation) return reachesToMany(op.left) || reachesToMany(op.right);
|
|
2028
|
+
return false;
|
|
2029
|
+
}
|
|
2030
|
+
function unaliased(op) {
|
|
2031
|
+
return op instanceof Alias ? unaliased(op.element) : op;
|
|
954
2032
|
}
|
|
955
2033
|
var SQLQueryGenerator = class {
|
|
2034
|
+
constructor(_dialect) {
|
|
2035
|
+
this._dialect = _dialect;
|
|
2036
|
+
}
|
|
2037
|
+
_dialect;
|
|
956
2038
|
_select = [];
|
|
957
2039
|
_from = /* @__PURE__ */ new Set();
|
|
958
2040
|
_join = [];
|
|
959
2041
|
_groupByParts = [];
|
|
2042
|
+
_having = "";
|
|
960
2043
|
_orderByParts = [];
|
|
961
2044
|
_where = "";
|
|
962
2045
|
_limit;
|
|
2046
|
+
_distinct = false;
|
|
2047
|
+
_offset;
|
|
963
2048
|
_tableAliasIncr = 0;
|
|
964
2049
|
_tableAliasesByTable = /* @__PURE__ */ new Map();
|
|
965
2050
|
_addedJoinIds = /* @__PURE__ */ new Set();
|
|
966
2051
|
_rootTable;
|
|
2052
|
+
_elidableNodes = /* @__PURE__ */ new Set();
|
|
2053
|
+
_joinFilters = /* @__PURE__ */ new Map();
|
|
2054
|
+
_guardOptional = true;
|
|
967
2055
|
generate(select) {
|
|
968
2056
|
this._rootTable = select.table;
|
|
2057
|
+
this._elidableNodes = this._computeElidableNodes(select);
|
|
2058
|
+
this._joinFilters = select.joinFilters;
|
|
969
2059
|
if (this._rootTable !== void 0) {
|
|
970
2060
|
this._from.add(this._tableAliasForTable(this._rootTable.qualifiedName, this._rootTable.qualifiedName));
|
|
971
2061
|
}
|
|
@@ -978,46 +2068,104 @@ var SQLQueryGenerator = class {
|
|
|
978
2068
|
for (const node of groupByJoins.values()) {
|
|
979
2069
|
this._addJoin(node);
|
|
980
2070
|
}
|
|
981
|
-
this._groupByParts =
|
|
2071
|
+
this._groupByParts = this._groupByPartsFor(select);
|
|
2072
|
+
this._having = "";
|
|
2073
|
+
if (select.having !== void 0) {
|
|
2074
|
+
const havingJoins = /* @__PURE__ */ new Map();
|
|
2075
|
+
this._collectRequiredJoins(select.having, havingJoins);
|
|
2076
|
+
for (const node of havingJoins.values()) this._addJoin(node);
|
|
2077
|
+
this._guardOptional = false;
|
|
2078
|
+
try {
|
|
2079
|
+
this._having = this.buildFilter(select.having);
|
|
2080
|
+
} finally {
|
|
2081
|
+
this._guardOptional = true;
|
|
2082
|
+
}
|
|
2083
|
+
}
|
|
982
2084
|
this._orderByParts = select.orderBy.map(
|
|
983
|
-
(s) => this.
|
|
2085
|
+
(s) => this._sortExpression(s.column) + this._dialect.orderDirection(s.direction)
|
|
984
2086
|
);
|
|
985
2087
|
this._limit = select.limit;
|
|
2088
|
+
this._distinct = select.distinct;
|
|
2089
|
+
this._offset = select.offset;
|
|
2090
|
+
}
|
|
2091
|
+
/**
|
|
2092
|
+
* The GROUP BY of a query: the grouping it was given, else the grouping its columns imply.
|
|
2093
|
+
*
|
|
2094
|
+
* Columns that are not aggregated are what the aggregates are computed for, so a query that selects both is
|
|
2095
|
+
* grouped by those columns (as a DataFrame's `groupby(columns).agg(...)` does). An aggregate read through a
|
|
2096
|
+
* to-many association is computed for each row of the root table, as Legend does, so the root's primary key
|
|
2097
|
+
* is grouped by too. A query that selects only aggregates over the root's own columns is not grouped: the
|
|
2098
|
+
* aggregate covers every row. A constant needs no grouping: a bare
|
|
2099
|
+
* `GROUP BY 7` would be a column position.
|
|
2100
|
+
*/
|
|
2101
|
+
_groupByPartsFor(select) {
|
|
2102
|
+
if (select.groupBy.length > 0) return select.groupBy.map((a) => this._attrToColString(a));
|
|
2103
|
+
const aggregates = select.display.filter(containsAggregate);
|
|
2104
|
+
if (aggregates.length === 0) return [];
|
|
2105
|
+
const perRoot = select.table !== void 0 && aggregates.some(reachesToMany);
|
|
2106
|
+
const keys = perRoot ? select.table.columns.filter((c) => c.primaryKey).map((c) => this._columnToString(c)) : [];
|
|
2107
|
+
const grouped = select.display.map((column, i) => ({ column, shown: this._select[i] })).filter(({ column }) => !containsAggregateOrWindow(column) && !(unaliased(column) instanceof ConstantOperation)).map(({ shown }) => sqlOperationToString(shown.element, this._dialect));
|
|
2108
|
+
return [.../* @__PURE__ */ new Set([...keys, ...grouped])];
|
|
2109
|
+
}
|
|
2110
|
+
/** What a sort orders by: a column, or an expression such as an aggregate. */
|
|
2111
|
+
_sortExpression(expression) {
|
|
2112
|
+
if (expression instanceof ColumnWithJoin || expression instanceof Attribute) return this.buildFilter(expression);
|
|
2113
|
+
return sqlOperationToString(this._rewriteOperation(expression), this._dialect);
|
|
2114
|
+
}
|
|
2115
|
+
_columnToString(column) {
|
|
2116
|
+
return this._tableAliasForTable(column.owner, column.owner).alias + "." + column.name;
|
|
986
2117
|
}
|
|
987
2118
|
_attrToColString(attr) {
|
|
988
|
-
const
|
|
989
|
-
const ta = this._tableAliasForTable(
|
|
990
|
-
return ta.alias + "." +
|
|
2119
|
+
const { column, parent } = this._resolve(attr);
|
|
2120
|
+
const ta = this._tableAliasForTable(column.owner, parent ?? column.owner);
|
|
2121
|
+
return ta.alias + "." + column.name;
|
|
991
2122
|
}
|
|
992
2123
|
_collectRequiredJoins(op, out) {
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
2124
|
+
walkRefs(op, (ref) => {
|
|
2125
|
+
const { parent } = this._resolve(ref);
|
|
2126
|
+
if (parent !== void 0) out.set(parent, parent);
|
|
2127
|
+
});
|
|
2128
|
+
}
|
|
2129
|
+
/**
|
|
2130
|
+
* Determine upfront which join nodes can be satisfied entirely by embedded (join-less) alternates:
|
|
2131
|
+
* a node is elidable when every reference to it has an embedded alternate. A reference without one
|
|
2132
|
+
* (e.g. a milestoning column) keeps the join for every reference to that node.
|
|
2133
|
+
*/
|
|
2134
|
+
_computeElidableNodes(select) {
|
|
2135
|
+
const refsByNode = /* @__PURE__ */ new Map();
|
|
2136
|
+
const record = (ref) => {
|
|
2137
|
+
const parent = ref instanceof Attribute ? ref.parent() : ref.parent;
|
|
2138
|
+
if (parent === void 0) return;
|
|
2139
|
+
const refs = refsByNode.get(parent);
|
|
2140
|
+
if (refs) refs.push(ref);
|
|
2141
|
+
else refsByNode.set(parent, [ref]);
|
|
2142
|
+
};
|
|
2143
|
+
for (const col of select.display) walkRefs(col, record);
|
|
2144
|
+
for (const expr of select.groupBy) walkRefs(expr, record);
|
|
2145
|
+
for (const sort of select.orderBy) walkRefs(sort, record);
|
|
2146
|
+
walkRefs(select.filter, record);
|
|
2147
|
+
const elidable = /* @__PURE__ */ new Set();
|
|
2148
|
+
for (const [node, refs] of refsByNode) {
|
|
2149
|
+
if (refs.every((ref) => embeddedOf(ref) !== void 0)) elidable.add(node);
|
|
1012
2150
|
}
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
2151
|
+
return elidable;
|
|
2152
|
+
}
|
|
2153
|
+
/** The (column, parent) a reference should resolve to, substituting its embedded alternate when its join is elided. */
|
|
2154
|
+
_resolve(ref) {
|
|
2155
|
+
const column = ref instanceof Attribute ? ref.column() : ref.column;
|
|
2156
|
+
const parent = ref instanceof Attribute ? ref.parent() : ref.parent;
|
|
2157
|
+
if (parent !== void 0 && this._elidableNodes.has(parent)) {
|
|
2158
|
+
const embedded = embeddedOf(ref);
|
|
2159
|
+
if (embedded !== void 0) return this._resolve(embedded);
|
|
1017
2160
|
}
|
|
1018
|
-
|
|
1019
|
-
|
|
2161
|
+
return { column, parent };
|
|
2162
|
+
}
|
|
2163
|
+
/** Whether the value `op` reads can be missing, in the join or embedded form that is used for it. */
|
|
2164
|
+
_resolveOptional(op) {
|
|
2165
|
+
if (op.parent !== void 0 && this._elidableNodes.has(op.parent) && op.embedded !== void 0) {
|
|
2166
|
+
return this._resolveOptional(op.embedded);
|
|
1020
2167
|
}
|
|
2168
|
+
return op.optional;
|
|
1021
2169
|
}
|
|
1022
2170
|
_rewriteWindowSpec(window) {
|
|
1023
2171
|
const partitionBy = window.partitionBy.map((p) => this._rewriteOperation(p));
|
|
@@ -1025,13 +2173,9 @@ var SQLQueryGenerator = class {
|
|
|
1025
2173
|
return new WindowSpecification(partitionBy, orderBy);
|
|
1026
2174
|
}
|
|
1027
2175
|
_rewriteOperation(op) {
|
|
1028
|
-
if (op instanceof Attribute) {
|
|
1029
|
-
const
|
|
1030
|
-
return new TableAliasColumn(
|
|
1031
|
-
}
|
|
1032
|
-
if (op instanceof ColumnWithJoin) {
|
|
1033
|
-
const ta = op.parent !== void 0 ? this._tableAliasForTable(op.column.owner, op.parent) : this._tableAliasForTable(op.column.owner, op.column.owner);
|
|
1034
|
-
return new TableAliasColumn(op.column, ta);
|
|
2176
|
+
if (op instanceof Attribute || op instanceof ColumnWithJoin) {
|
|
2177
|
+
const { column, parent } = this._resolve(op);
|
|
2178
|
+
return new TableAliasColumn(column, this._tableAliasForTable(column.owner, parent ?? column.owner));
|
|
1035
2179
|
}
|
|
1036
2180
|
if (op instanceof Column) {
|
|
1037
2181
|
const ta = this._tableAliasForTable(op.owner, op.owner);
|
|
@@ -1042,9 +2186,17 @@ var SQLQueryGenerator = class {
|
|
|
1042
2186
|
this._rewriteOperation(op.element),
|
|
1043
2187
|
op.operator,
|
|
1044
2188
|
op.displayName,
|
|
1045
|
-
op.window ? this._rewriteWindowSpec(op.window) : void 0
|
|
2189
|
+
op.window ? this._rewriteWindowSpec(op.window) : void 0,
|
|
2190
|
+
op.separator,
|
|
2191
|
+
op.orderBy.map((s) => new SortOperation(this._rewriteOperation(s.column), s.direction))
|
|
1046
2192
|
);
|
|
1047
2193
|
}
|
|
2194
|
+
if (op instanceof CaseOperation) return new RenderedSql(this._caseSql(op));
|
|
2195
|
+
if (isCondition(op)) return new RenderedSql(this.buildFilter(op));
|
|
2196
|
+
if (op instanceof ConcatOperation) return new ConcatOperation(op.parts.map((part) => this._rewriteOperation(part)), op.displayName);
|
|
2197
|
+
if (op instanceof ArithmeticOperation) {
|
|
2198
|
+
return new ArithmeticOperation(this._rewriteOperation(op.left), op.operator, this._rewriteOperation(op.right), op.displayName);
|
|
2199
|
+
}
|
|
1048
2200
|
if (op instanceof WindowFunctionOperation) {
|
|
1049
2201
|
const el = op.element ? this._rewriteOperation(op.element) : null;
|
|
1050
2202
|
return new WindowFunctionOperation(
|
|
@@ -1062,6 +2214,9 @@ var SQLQueryGenerator = class {
|
|
|
1062
2214
|
if (op instanceof DateExtractOperation) {
|
|
1063
2215
|
return new DateExtractOperation(this._rewriteOperation(op.element), op.part, op.displayName);
|
|
1064
2216
|
}
|
|
2217
|
+
if (op instanceof DateTruncOperation) {
|
|
2218
|
+
return new DateTruncOperation(this._rewriteOperation(op.element), op.part, op.displayName);
|
|
2219
|
+
}
|
|
1065
2220
|
if (op instanceof DateArithmeticOperation) {
|
|
1066
2221
|
return new DateArithmeticOperation(this._rewriteOperation(op.element), op.n, op.unit, op.isAdd, op.displayName);
|
|
1067
2222
|
}
|
|
@@ -1070,6 +2225,13 @@ var SQLQueryGenerator = class {
|
|
|
1070
2225
|
}
|
|
1071
2226
|
return op;
|
|
1072
2227
|
}
|
|
2228
|
+
/** The CASE written out now: its condition can only be rendered while the query is being built. */
|
|
2229
|
+
_caseSql(op) {
|
|
2230
|
+
const branch = (value) => value instanceof ConstantOperation ? constantValueString(value, this._dialect) : sqlOperationToString(this._rewriteOperation(value), this._dialect);
|
|
2231
|
+
let sql = "CASE WHEN " + this.buildFilter(op.condition) + " THEN " + branch(op.then);
|
|
2232
|
+
if (op.fallback !== void 0) sql += " ELSE " + branch(op.fallback);
|
|
2233
|
+
return sql + " END";
|
|
2234
|
+
}
|
|
1073
2235
|
processSelect(cols) {
|
|
1074
2236
|
const requiredJoins = /* @__PURE__ */ new Map();
|
|
1075
2237
|
for (const col of cols) {
|
|
@@ -1078,88 +2240,96 @@ var SQLQueryGenerator = class {
|
|
|
1078
2240
|
for (const node of requiredJoins.values()) {
|
|
1079
2241
|
this._addJoin(node);
|
|
1080
2242
|
}
|
|
1081
|
-
for (const col of cols)
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
);
|
|
1122
|
-
this.
|
|
1123
|
-
}
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
} else {
|
|
1145
|
-
ta = this._tableAliasForTable(colNested.column.owner, colNested.column.owner);
|
|
1146
|
-
this._from.add(ta);
|
|
1147
|
-
}
|
|
1148
|
-
const alias = col.displayName ?? colNested.column.name;
|
|
1149
|
-
let aliasedOp;
|
|
1150
|
-
if (col instanceof DateExtractOperation) {
|
|
1151
|
-
aliasedOp = new DateExtractOperation(new TableAliasColumn(colNested.column, ta), col.part);
|
|
1152
|
-
} else if (col instanceof DateArithmeticOperation) {
|
|
1153
|
-
aliasedOp = new DateArithmeticOperation(new TableAliasColumn(colNested.column, ta), col.n, col.unit, col.isAdd);
|
|
1154
|
-
} else {
|
|
1155
|
-
aliasedOp = new DateDiffOperation(new TableAliasColumn(colNested.column, ta), col.other, col.unit);
|
|
1156
|
-
}
|
|
1157
|
-
this._select.push(new Alias(aliasedOp, alias));
|
|
1158
|
-
} else if (col instanceof CountAllOperation) {
|
|
1159
|
-
const ta = this._tableAliasForTable(col.table, col.table);
|
|
2243
|
+
for (const col of cols) this._selectColumn(col);
|
|
2244
|
+
}
|
|
2245
|
+
/** Add one column to the select list. An alias reads the column it wraps, then names the entry. */
|
|
2246
|
+
_selectColumn(col) {
|
|
2247
|
+
if (col instanceof Alias) {
|
|
2248
|
+
this._selectColumn(col.element);
|
|
2249
|
+
const read = this._select.pop();
|
|
2250
|
+
this._select.push(new Alias(read.element, col.name));
|
|
2251
|
+
} else if (col instanceof Attribute) {
|
|
2252
|
+
const { column, parent: node } = this._resolve(col);
|
|
2253
|
+
let ta;
|
|
2254
|
+
if (node !== void 0) {
|
|
2255
|
+
ta = this._tableAliasForTable(column.owner, node);
|
|
2256
|
+
} else {
|
|
2257
|
+
ta = this._tableAliasForTable(column.owner, column.owner);
|
|
2258
|
+
this._from.add(ta);
|
|
2259
|
+
}
|
|
2260
|
+
this._select.push(new Alias(new TableAliasColumn(column, ta), col.displayName()));
|
|
2261
|
+
} else if (col instanceof WindowFunctionOperation) {
|
|
2262
|
+
const rewritten = this._rewriteOperation(col);
|
|
2263
|
+
let alias;
|
|
2264
|
+
if (col.displayName) {
|
|
2265
|
+
alias = col.displayName;
|
|
2266
|
+
} else if (["ROW_NUMBER" /* ROW_NUMBER */, "RANK" /* RANK */, "DENSE_RANK" /* DENSE_RANK */].includes(col.func)) {
|
|
2267
|
+
alias = col.func.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
2268
|
+
} else if (col.element) {
|
|
2269
|
+
alias = col.func + " " + findColumn(col).column.name;
|
|
2270
|
+
} else {
|
|
2271
|
+
alias = col.func;
|
|
2272
|
+
}
|
|
2273
|
+
this._select.push(new Alias(rewritten, alias));
|
|
2274
|
+
} else if (col instanceof AggregateOperation && !(col.element instanceof ColumnWithJoin)) {
|
|
2275
|
+
this._select.push(new Alias(this._rewriteOperation(col), col.displayName ?? "Expression"));
|
|
2276
|
+
} else if (col instanceof AggregateOperation) {
|
|
2277
|
+
const colNested = this._resolve(findColumn(col));
|
|
2278
|
+
const node = colNested.parent;
|
|
2279
|
+
let ta;
|
|
2280
|
+
if (node !== void 0) {
|
|
2281
|
+
ta = this._tableAliasForTable(colNested.column.owner, node);
|
|
2282
|
+
} else {
|
|
2283
|
+
ta = this._tableAliasForTable(colNested.column.owner, colNested.column.owner);
|
|
2284
|
+
this._from.add(ta);
|
|
2285
|
+
}
|
|
2286
|
+
const alias = col.displayName ?? col.operator + " " + findColumn(col).column.name;
|
|
2287
|
+
const rewrittenAgg = new AggregateOperation(
|
|
2288
|
+
new TableAliasColumn(colNested.column, ta),
|
|
2289
|
+
col.operator,
|
|
2290
|
+
void 0,
|
|
2291
|
+
col.window ? this._rewriteWindowSpec(col.window) : void 0,
|
|
2292
|
+
col.separator,
|
|
2293
|
+
col.orderBy.map((s) => new SortOperation(this._rewriteOperation(s.column), s.direction))
|
|
2294
|
+
);
|
|
2295
|
+
this._select.push(new Alias(rewrittenAgg, alias));
|
|
2296
|
+
} else if (col instanceof ScalarFunctionOperation) {
|
|
2297
|
+
this._select.push(new Alias(this._rewriteOperation(col), col.displayName ?? col.func + " " + findColumn(col).column.name));
|
|
2298
|
+
} else if (col instanceof DateExtractOperation || col instanceof DateArithmeticOperation || col instanceof DateDiffOperation) {
|
|
2299
|
+
const colNested = this._resolve(findColumn(col));
|
|
2300
|
+
const node = colNested.parent;
|
|
2301
|
+
let ta;
|
|
2302
|
+
if (node !== void 0) {
|
|
2303
|
+
ta = this._tableAliasForTable(colNested.column.owner, node);
|
|
2304
|
+
} else {
|
|
2305
|
+
ta = this._tableAliasForTable(colNested.column.owner, colNested.column.owner);
|
|
1160
2306
|
this._from.add(ta);
|
|
1161
|
-
this._select.push(new Alias(col, "Count"));
|
|
1162
2307
|
}
|
|
2308
|
+
const alias = col.displayName ?? findColumn(col).column.name;
|
|
2309
|
+
let aliasedOp;
|
|
2310
|
+
if (col instanceof DateExtractOperation) {
|
|
2311
|
+
aliasedOp = new DateExtractOperation(new TableAliasColumn(colNested.column, ta), col.part);
|
|
2312
|
+
} else if (col instanceof DateArithmeticOperation) {
|
|
2313
|
+
aliasedOp = new DateArithmeticOperation(new TableAliasColumn(colNested.column, ta), col.n, col.unit, col.isAdd);
|
|
2314
|
+
} else {
|
|
2315
|
+
aliasedOp = new DateDiffOperation(new TableAliasColumn(colNested.column, ta), col.other, col.unit);
|
|
2316
|
+
}
|
|
2317
|
+
this._select.push(new Alias(aliasedOp, alias));
|
|
2318
|
+
} else if (col instanceof CaseOperation) {
|
|
2319
|
+
this._select.push(new Alias(this._rewriteOperation(col), col.displayName ?? "Expression"));
|
|
2320
|
+
} else if (col instanceof ConcatOperation) {
|
|
2321
|
+
this._select.push(new Alias(this._rewriteOperation(col), col.displayName ?? "Expression"));
|
|
2322
|
+
} else if (col instanceof ArithmeticOperation) {
|
|
2323
|
+
this._select.push(new Alias(this._rewriteOperation(col), col.displayName ?? "Expression"));
|
|
2324
|
+
} else if (col instanceof DateTruncOperation) {
|
|
2325
|
+
this._select.push(new Alias(this._rewriteOperation(col), col.displayName ?? findColumn(col).column.name));
|
|
2326
|
+
} else if (isCondition(col)) {
|
|
2327
|
+
this._select.push(new Alias(new RenderedSql(this.buildFilter(col)), "Expression"));
|
|
2328
|
+
} else if (col instanceof ConstantOperation) {
|
|
2329
|
+
this._select.push(new Alias(col, "Constant"));
|
|
2330
|
+
} else if (col instanceof CountAllOperation) {
|
|
2331
|
+
if (col.table !== "") this._from.add(this._tableAliasForTable(col.table, col.table));
|
|
2332
|
+
this._select.push(new Alias(col, "Count"));
|
|
1163
2333
|
}
|
|
1164
2334
|
}
|
|
1165
2335
|
_addJoin(node) {
|
|
@@ -1173,7 +2343,9 @@ var SQLQueryGenerator = class {
|
|
|
1173
2343
|
const sc = new TableAliasColumn(left, srcTa);
|
|
1174
2344
|
const right = join.right;
|
|
1175
2345
|
const tc = new TableAliasColumn(right, this._tableAliasForTable(right.owner, node));
|
|
1176
|
-
this.
|
|
2346
|
+
const queryFilter = this._joinFilters.get(node);
|
|
2347
|
+
const filterOp = join.filter !== void 0 && queryFilter !== void 0 ? new LogicalOperation(join.filter, "AND" /* AND */, queryFilter) : join.filter ?? queryFilter;
|
|
2348
|
+
this._join.push(new Join(sc, tc, filterOp));
|
|
1177
2349
|
}
|
|
1178
2350
|
buildFilter(op) {
|
|
1179
2351
|
if (op instanceof NoOperation) return "";
|
|
@@ -1185,29 +2357,53 @@ var SQLQueryGenerator = class {
|
|
|
1185
2357
|
const col = op.node.join.right;
|
|
1186
2358
|
return this.buildFilter(new ColumnWithJoin(col, op.node)) + " IS NULL";
|
|
1187
2359
|
}
|
|
2360
|
+
if (op instanceof InOperation) {
|
|
2361
|
+
return this.buildFilter(op.element) + " IN (" + op.values.map((value) => constantValueString(value, this._dialect)).join(", ") + ")";
|
|
2362
|
+
}
|
|
2363
|
+
if (op instanceof NotInOperation) {
|
|
2364
|
+
const column = this.buildFilter(op.element);
|
|
2365
|
+
const sql = column + " NOT IN (" + op.values.map((value) => constantValueString(value, this._dialect)).join(", ") + ")";
|
|
2366
|
+
if (op.element instanceof ColumnWithJoin && this._resolve(op.element).column.nullable) {
|
|
2367
|
+
return "(" + sql + " OR " + column + " IS NULL)";
|
|
2368
|
+
}
|
|
2369
|
+
return sql;
|
|
2370
|
+
}
|
|
1188
2371
|
if (op instanceof IsNotNullOperation) return this.buildFilter(op.element) + " IS NOT NULL";
|
|
1189
2372
|
if (op instanceof IsNullOperation) return this.buildFilter(op.element) + " IS NULL";
|
|
1190
2373
|
if (op instanceof LogicalOperation) {
|
|
1191
2374
|
let left = this.buildFilter(op.left);
|
|
1192
2375
|
let right = this.buildFilter(op.right);
|
|
1193
|
-
if (op.left
|
|
1194
|
-
if (op.right
|
|
2376
|
+
if (needsParentheses(op, op.left)) left = "(" + left + ")";
|
|
2377
|
+
if (needsParentheses(op, op.right)) right = "(" + right + ")";
|
|
1195
2378
|
return left + LOGICAL_OPERATOR_STR[op.operator] + right;
|
|
1196
2379
|
}
|
|
1197
2380
|
if (op instanceof ComparisonOperation) {
|
|
1198
|
-
|
|
2381
|
+
let sql = this.buildFilter(op.left) + COMPARISON_OPERATOR_STR[op.operator] + this.buildFilter(op.right);
|
|
2382
|
+
if ((op.operator === "LIKE" /* LIKE */ || op.operator === "NOT_LIKE" /* NOT_LIKE */) && op.right instanceof StringConstantOperation && (op.right.value.includes(LIKE_ESCAPE) || op.right.value.includes("\\"))) {
|
|
2383
|
+
sql += " ESCAPE '" + LIKE_ESCAPE + "'";
|
|
2384
|
+
}
|
|
2385
|
+
if (this._guardOptional && GUARDED_COMPARISONS.has(op.operator) && op.left instanceof ColumnWithJoin && this._resolveOptional(op.left)) {
|
|
2386
|
+
sql = "(" + this.buildFilter(op.left) + " IS NOT NULL AND " + sql + ")";
|
|
2387
|
+
}
|
|
2388
|
+
return sql;
|
|
2389
|
+
}
|
|
2390
|
+
if (op instanceof ConstantOperation) return constantValueString(op, this._dialect);
|
|
2391
|
+
if (op instanceof ScalarFunctionOperation || op instanceof ArithmeticOperation || op instanceof ConcatOperation || op instanceof DateTruncOperation || op instanceof AggregateOperation || op instanceof CountAllOperation) {
|
|
2392
|
+
const required = /* @__PURE__ */ new Map();
|
|
2393
|
+
this._collectRequiredJoins(op, required);
|
|
2394
|
+
for (const node of required.values()) this._addJoin(node);
|
|
2395
|
+
return sqlOperationToString(this._rewriteOperation(op), this._dialect);
|
|
1199
2396
|
}
|
|
1200
|
-
if (op instanceof ConstantOperation) return constantValueString(op);
|
|
1201
2397
|
if (op instanceof ColumnWithJoin) {
|
|
1202
|
-
const node = op
|
|
2398
|
+
const { column, parent: node } = this._resolve(op);
|
|
1203
2399
|
let ta;
|
|
1204
2400
|
if (node !== void 0) {
|
|
1205
|
-
ta = this._tableAliasForTable(
|
|
2401
|
+
ta = this._tableAliasForTable(column.owner, node);
|
|
1206
2402
|
this._addJoin(node);
|
|
1207
2403
|
} else {
|
|
1208
|
-
ta = this._tableAliasForTable(
|
|
2404
|
+
ta = this._tableAliasForTable(column.owner, column.owner);
|
|
1209
2405
|
}
|
|
1210
|
-
return ta.alias + "." +
|
|
2406
|
+
return ta.alias + "." + column.name;
|
|
1211
2407
|
}
|
|
1212
2408
|
if (op instanceof Column) {
|
|
1213
2409
|
const ta = this._tableAliasForTable(op.owner, op.owner);
|
|
@@ -1225,9 +2421,9 @@ var SQLQueryGenerator = class {
|
|
|
1225
2421
|
}
|
|
1226
2422
|
buildQueryString() {
|
|
1227
2423
|
const joins = this._join.map(
|
|
1228
|
-
(j) => " LEFT OUTER JOIN " + j.target.tableAlias.table + " AS " + j.target.tableAlias.alias + " ON " + j.
|
|
2424
|
+
(j) => " LEFT OUTER JOIN " + j.target.tableAlias.table + " AS " + j.target.tableAlias.alias + " ON (" + j.condition() + (j.filterOp ? " AND " + this.buildFilter(j.filterOp) : "") + ")"
|
|
1229
2425
|
);
|
|
1230
|
-
return "SELECT " + this._select.map((ca) => sqlOperationToString(ca)).join(",") + " FROM " + Array.from(this._from).map((ta) => ta.table + " AS " + ta.alias).join(",") + joins.join("") + this._buildWhere() + this._buildGroupBy() + this._buildOrderBy() + this._buildLimit();
|
|
2426
|
+
return (this._distinct ? "SELECT DISTINCT " : "SELECT ") + this._select.map((ca) => sqlOperationToString(ca, this._dialect)).join(",") + " FROM " + Array.from(this._from).map((ta) => ta.table + " AS " + ta.alias).join(",") + joins.join("") + this._buildWhere() + this._buildGroupBy() + this._buildHaving() + this._buildOrderBy() + this._buildLimit() + this._buildOffset();
|
|
1231
2427
|
}
|
|
1232
2428
|
_buildWhere() {
|
|
1233
2429
|
return this._where.length > 0 ? " WHERE " + this._where : "";
|
|
@@ -1235,26 +2431,33 @@ var SQLQueryGenerator = class {
|
|
|
1235
2431
|
_buildGroupBy() {
|
|
1236
2432
|
return this._groupByParts.length > 0 ? " GROUP BY " + this._groupByParts.join(", ") : "";
|
|
1237
2433
|
}
|
|
2434
|
+
_buildHaving() {
|
|
2435
|
+
return this._having.length > 0 ? " HAVING " + this._having : "";
|
|
2436
|
+
}
|
|
1238
2437
|
_buildOrderBy() {
|
|
1239
2438
|
return this._orderByParts.length > 0 ? " ORDER BY " + this._orderByParts.join(", ") : "";
|
|
1240
2439
|
}
|
|
2440
|
+
_buildOffset() {
|
|
2441
|
+
return this._offset !== void 0 ? " OFFSET " + this._offset : "";
|
|
2442
|
+
}
|
|
1241
2443
|
_buildLimit() {
|
|
1242
2444
|
return this._limit !== void 0 ? " LIMIT " + this._limit : "";
|
|
1243
2445
|
}
|
|
1244
2446
|
};
|
|
1245
|
-
function selectSqlToString(selectOperation) {
|
|
1246
|
-
const qg = new SQLQueryGenerator();
|
|
2447
|
+
function selectSqlToString(selectOperation, dialect = "postgres") {
|
|
2448
|
+
const qg = new SQLQueryGenerator(dialectOf(dialect));
|
|
1247
2449
|
qg.generate(selectOperation);
|
|
1248
2450
|
return qg.buildQueryString();
|
|
1249
2451
|
}
|
|
1250
|
-
function toSql(businessDate, processingDatetime, columns, table, op, orderBy = [], groupBy = [], limit) {
|
|
1251
|
-
const selectOp = buildQueryOperation(businessDate, processingDatetime, columns, table, op, orderBy, groupBy, limit);
|
|
1252
|
-
return selectSqlToString(selectOp);
|
|
2452
|
+
function toSql(businessDate, processingDatetime, columns, table, op, orderBy = [], groupBy = [], limit, businessDateTo = null, distinct = false, offset, having, dialect = "postgres") {
|
|
2453
|
+
const selectOp = buildQueryOperation(businessDate, processingDatetime, columns, table, op, orderBy, groupBy, limit, businessDateTo, distinct, offset, having);
|
|
2454
|
+
return selectSqlToString(selectOp, dialect);
|
|
1253
2455
|
}
|
|
1254
2456
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1255
2457
|
0 && (module.exports = {
|
|
1256
|
-
|
|
2458
|
+
arithmeticNeedsParentheses,
|
|
1257
2459
|
buildQueryOperation,
|
|
2460
|
+
needsParentheses,
|
|
1258
2461
|
selectSqlToString,
|
|
1259
2462
|
toSql
|
|
1260
2463
|
});
|