data-finder-ts 0.1.4 → 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/dist/{chunk-4JVW4TAB.js → chunk-BGEX377Q.js} +58 -8
- 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-PMPLCEWQ.js → chunk-GPHWC533.js} +2 -2
- package/dist/{chunk-FJYA2ASS.js → chunk-KAK75RVS.js} +74 -12
- package/dist/chunk-KAK75RVS.js.map +1 -0
- package/dist/{chunk-4LNZV6EN.js → chunk-MGEL5RWM.js} +206 -78
- 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 +537 -11
- package/dist/datafinder/attribute.cjs.map +1 -1
- package/dist/datafinder/attribute.d.cts +29 -7
- package/dist/datafinder/attribute.d.ts +29 -7
- package/dist/datafinder/attribute.js +2 -2
- package/dist/datafinder/runner.cjs +1267 -215
- package/dist/datafinder/runner.cjs.map +1 -1
- package/dist/datafinder/runner.d.cts +28 -5
- package/dist/datafinder/runner.d.ts +28 -5
- package/dist/datafinder/runner.js +6 -6
- package/dist/datafinder/sql-generator.cjs +1203 -206
- package/dist/datafinder/sql-generator.cjs.map +1 -1
- package/dist/datafinder/sql-generator.d.cts +19 -5
- package/dist/datafinder/sql-generator.d.ts +19 -5
- package/dist/datafinder/sql-generator.js +9 -5
- package/dist/datafinder/typed-attributes.cjs +693 -88
- package/dist/datafinder/typed-attributes.cjs.map +1 -1
- package/dist/datafinder/typed-attributes.d.cts +3 -242
- package/dist/datafinder/typed-attributes.d.ts +3 -242
- 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 +1677 -408
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +109 -5
- package/dist/index.d.ts +109 -5
- package/dist/index.js +321 -11
- 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 +547 -16
- package/dist/model/relational.cjs.map +1 -1
- package/dist/model/relational.d.cts +421 -57
- package/dist/model/relational.d.ts +421 -57
- package/dist/model/relational.js +53 -3
- package/dist/typed-attributes-CUTf_6Ru.d.ts +328 -0
- package/dist/typed-attributes-CdWXq_78.d.cts +328 -0
- package/package.json +3 -2
- package/dist/chunk-4JVW4TAB.js.map +0 -1
- package/dist/chunk-4LNZV6EN.js.map +0 -1
- package/dist/chunk-FJYA2ASS.js.map +0 -1
- package/dist/chunk-MH4XMYVB.js +0 -696
- package/dist/chunk-MH4XMYVB.js.map +0 -1
- package/dist/chunk-UYMOE6YU.js +0 -509
- package/dist/chunk-UYMOE6YU.js.map +0 -1
- /package/dist/{chunk-PMPLCEWQ.js.map → chunk-GPHWC533.js.map} +0 -0
|
@@ -20,35 +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
|
+
arithmeticNeedsParentheses: () => arithmeticNeedsParentheses,
|
|
23
24
|
buildQueryOperation: () => buildQueryOperation,
|
|
25
|
+
needsParentheses: () => needsParentheses,
|
|
24
26
|
selectSqlToString: () => selectSqlToString,
|
|
25
27
|
toSql: () => toSql
|
|
26
28
|
});
|
|
27
29
|
module.exports = __toCommonJS(sql_generator_exports);
|
|
28
30
|
|
|
29
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
|
+
}
|
|
30
36
|
var RelationalOperationElement = class {
|
|
31
37
|
};
|
|
32
38
|
var Operation = class extends RelationalOperationElement {
|
|
33
|
-
|
|
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) {
|
|
34
44
|
return new LogicalOperation(this, "AND" /* AND */, other);
|
|
35
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
|
+
}
|
|
36
50
|
};
|
|
37
51
|
var NoOperation = class extends Operation {
|
|
38
|
-
|
|
52
|
+
and(other) {
|
|
39
53
|
return other;
|
|
40
54
|
}
|
|
55
|
+
/** No filter matches every row, so OR-ing anything with it still matches every row. */
|
|
56
|
+
or(_other) {
|
|
57
|
+
return this;
|
|
58
|
+
}
|
|
41
59
|
};
|
|
42
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
|
+
}
|
|
73
|
+
};
|
|
74
|
+
var NumericConstantOperation = class extends ConstantOperation {
|
|
75
|
+
arithmeticOperand() {
|
|
76
|
+
return this;
|
|
77
|
+
}
|
|
43
78
|
};
|
|
44
|
-
var IntegerConstantOperation = class extends
|
|
79
|
+
var IntegerConstantOperation = class extends NumericConstantOperation {
|
|
45
80
|
constructor(value) {
|
|
46
81
|
super();
|
|
47
82
|
this.value = value;
|
|
48
83
|
}
|
|
49
84
|
value;
|
|
50
85
|
};
|
|
51
|
-
var FloatConstantOperation = class extends
|
|
86
|
+
var FloatConstantOperation = class extends NumericConstantOperation {
|
|
52
87
|
constructor(value) {
|
|
53
88
|
super();
|
|
54
89
|
this.value = value;
|
|
@@ -62,6 +97,9 @@ var StringConstantOperation = class extends ConstantOperation {
|
|
|
62
97
|
}
|
|
63
98
|
value;
|
|
64
99
|
};
|
|
100
|
+
var DATE_ONLY_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
|
|
101
|
+
var DateOnly = class extends Date {
|
|
102
|
+
};
|
|
65
103
|
var DateConstantOperation = class extends ConstantOperation {
|
|
66
104
|
constructor(value) {
|
|
67
105
|
super();
|
|
@@ -76,7 +114,7 @@ var DateTimeConstantOperation = class extends ConstantOperation {
|
|
|
76
114
|
}
|
|
77
115
|
value;
|
|
78
116
|
};
|
|
79
|
-
var DecimalConstantOperation = class extends
|
|
117
|
+
var DecimalConstantOperation = class extends NumericConstantOperation {
|
|
80
118
|
constructor(value) {
|
|
81
119
|
super();
|
|
82
120
|
this.value = value;
|
|
@@ -110,6 +148,20 @@ var IsNullOperation = class extends UnaryOperation {
|
|
|
110
148
|
};
|
|
111
149
|
var IsNotNullOperation = class extends UnaryOperation {
|
|
112
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
|
+
};
|
|
113
165
|
var ComparisonOperation = class extends BinaryOperation {
|
|
114
166
|
constructor(left, operator, right) {
|
|
115
167
|
super(left, right);
|
|
@@ -133,21 +185,41 @@ var WindowSpecification = class {
|
|
|
133
185
|
orderBy;
|
|
134
186
|
};
|
|
135
187
|
var AggregateOperation = class _AggregateOperation extends UnaryOperation {
|
|
136
|
-
constructor(element, operator, displayName, window) {
|
|
188
|
+
constructor(element, operator, displayName, window, separator, orderBy = []) {
|
|
137
189
|
super(element);
|
|
138
190
|
this.operator = operator;
|
|
139
191
|
this.displayName = displayName;
|
|
140
192
|
this.window = window;
|
|
193
|
+
this.separator = separator;
|
|
194
|
+
this.orderBy = orderBy;
|
|
141
195
|
}
|
|
142
196
|
operator;
|
|
143
197
|
displayName;
|
|
144
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
|
+
}
|
|
145
215
|
over(partitionBy, orderBy) {
|
|
146
216
|
return new _AggregateOperation(
|
|
147
217
|
this.element,
|
|
148
218
|
this.operator,
|
|
149
219
|
this.displayName,
|
|
150
|
-
new WindowSpecification(partitionBy ?? [], orderBy ?? [])
|
|
220
|
+
new WindowSpecification(partitionBy ?? [], orderBy ?? []),
|
|
221
|
+
this.separator,
|
|
222
|
+
this.orderBy
|
|
151
223
|
);
|
|
152
224
|
}
|
|
153
225
|
};
|
|
@@ -165,6 +237,14 @@ var WindowFunctionOperation = class _WindowFunctionOperation extends UnaryOperat
|
|
|
165
237
|
secondArg;
|
|
166
238
|
extraArgs;
|
|
167
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
|
+
}
|
|
168
248
|
over(partitionBy, orderBy) {
|
|
169
249
|
return new _WindowFunctionOperation(
|
|
170
250
|
this.element,
|
|
@@ -188,7 +268,38 @@ var ScalarFunctionOperation = class extends UnaryOperation {
|
|
|
188
268
|
displayName;
|
|
189
269
|
secondArg;
|
|
190
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
|
+
}
|
|
191
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
|
+
]);
|
|
192
303
|
var DateExtractOperation = class extends UnaryOperation {
|
|
193
304
|
constructor(element, part, displayName) {
|
|
194
305
|
super(element);
|
|
@@ -197,6 +308,34 @@ var DateExtractOperation = class extends UnaryOperation {
|
|
|
197
308
|
}
|
|
198
309
|
part;
|
|
199
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
|
+
}
|
|
200
339
|
};
|
|
201
340
|
var DateArithmeticOperation = class extends UnaryOperation {
|
|
202
341
|
constructor(element, n, unit, isAdd = true, displayName) {
|
|
@@ -210,6 +349,14 @@ var DateArithmeticOperation = class extends UnaryOperation {
|
|
|
210
349
|
unit;
|
|
211
350
|
isAdd;
|
|
212
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
|
+
}
|
|
213
360
|
};
|
|
214
361
|
var DateDiffOperation = class extends UnaryOperation {
|
|
215
362
|
constructor(element, other, unit, displayName) {
|
|
@@ -221,20 +368,31 @@ var DateDiffOperation = class extends UnaryOperation {
|
|
|
221
368
|
other;
|
|
222
369
|
unit;
|
|
223
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
|
+
}
|
|
224
379
|
};
|
|
225
380
|
var Column = class extends RelationalOperationElement {
|
|
226
|
-
constructor(name, type, owner, primaryKey = false) {
|
|
381
|
+
constructor(name, type, owner, primaryKey = false, nullable = true) {
|
|
227
382
|
super();
|
|
228
383
|
this.name = name;
|
|
229
384
|
this.type = type;
|
|
230
385
|
this.owner = owner;
|
|
231
386
|
this.primaryKey = primaryKey;
|
|
387
|
+
this.nullable = nullable && !primaryKey;
|
|
232
388
|
}
|
|
233
389
|
name;
|
|
234
390
|
type;
|
|
235
391
|
owner;
|
|
236
392
|
primaryKey;
|
|
237
393
|
table;
|
|
394
|
+
/** Whether the column may hold NULL. As in Legend, a primary key is never null. */
|
|
395
|
+
nullable;
|
|
238
396
|
};
|
|
239
397
|
var Table = class {
|
|
240
398
|
constructor(name, columns, schema) {
|
|
@@ -267,15 +425,24 @@ var ColumnWithJoin = class extends RelationalOperationElement {
|
|
|
267
425
|
* `embedded` is an alternate reference to a flat (denormalized) column on the owning table that
|
|
268
426
|
* holds the same value without the join; the SQL generator uses it when the join can be elided.
|
|
269
427
|
*/
|
|
270
|
-
constructor(column, parent, embedded) {
|
|
428
|
+
constructor(column, parent, embedded, _optional = false) {
|
|
271
429
|
super();
|
|
272
430
|
this.column = column;
|
|
273
431
|
this.parent = parent;
|
|
274
432
|
this.embedded = embedded;
|
|
433
|
+
this._optional = _optional;
|
|
275
434
|
}
|
|
276
435
|
column;
|
|
277
436
|
parent;
|
|
278
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
|
+
}
|
|
279
446
|
};
|
|
280
447
|
var SortOperation = class {
|
|
281
448
|
constructor(column, direction) {
|
|
@@ -291,8 +458,23 @@ var CountAllOperation = class extends RelationalOperationElement {
|
|
|
291
458
|
this.table = table;
|
|
292
459
|
}
|
|
293
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
|
+
}
|
|
294
476
|
};
|
|
295
|
-
var Alias = class extends RelationalOperationElement {
|
|
477
|
+
var Alias = class _Alias extends RelationalOperationElement {
|
|
296
478
|
constructor(element, name) {
|
|
297
479
|
super();
|
|
298
480
|
this.element = element;
|
|
@@ -300,6 +482,30 @@ var Alias = class extends RelationalOperationElement {
|
|
|
300
482
|
}
|
|
301
483
|
element;
|
|
302
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;
|
|
303
509
|
};
|
|
304
510
|
var ExistsOperation = class extends RelationalOperationElement {
|
|
305
511
|
constructor(node) {
|
|
@@ -307,9 +513,16 @@ var ExistsOperation = class extends RelationalOperationElement {
|
|
|
307
513
|
this.node = node;
|
|
308
514
|
}
|
|
309
515
|
node;
|
|
310
|
-
|
|
516
|
+
/** Name this column in the result. */
|
|
517
|
+
alias(name) {
|
|
518
|
+
return new Alias(this, name);
|
|
519
|
+
}
|
|
520
|
+
and(other) {
|
|
311
521
|
return new LogicalOperation(this, "AND" /* AND */, other);
|
|
312
522
|
}
|
|
523
|
+
or(other) {
|
|
524
|
+
return new LogicalOperation(this, "OR" /* OR */, other);
|
|
525
|
+
}
|
|
313
526
|
};
|
|
314
527
|
var NotExistsOperation = class extends RelationalOperationElement {
|
|
315
528
|
constructor(node) {
|
|
@@ -317,12 +530,19 @@ var NotExistsOperation = class extends RelationalOperationElement {
|
|
|
317
530
|
this.node = node;
|
|
318
531
|
}
|
|
319
532
|
node;
|
|
320
|
-
|
|
533
|
+
/** Name this column in the result. */
|
|
534
|
+
alias(name) {
|
|
535
|
+
return new Alias(this, name);
|
|
536
|
+
}
|
|
537
|
+
and(other) {
|
|
321
538
|
return new LogicalOperation(this, "AND" /* AND */, other);
|
|
322
539
|
}
|
|
540
|
+
or(other) {
|
|
541
|
+
return new LogicalOperation(this, "OR" /* OR */, other);
|
|
542
|
+
}
|
|
323
543
|
};
|
|
324
544
|
var SelectOperation = class {
|
|
325
|
-
constructor(display, filter, orderBy = [], groupBy = [], limit, table, joinFilters = /* @__PURE__ */ new Map()) {
|
|
545
|
+
constructor(display, filter, orderBy = [], groupBy = [], limit, table, joinFilters = /* @__PURE__ */ new Map(), distinct = false, offset, having) {
|
|
326
546
|
this.display = display;
|
|
327
547
|
this.filter = filter;
|
|
328
548
|
this.orderBy = orderBy;
|
|
@@ -330,6 +550,9 @@ var SelectOperation = class {
|
|
|
330
550
|
this.limit = limit;
|
|
331
551
|
this.table = table;
|
|
332
552
|
this.joinFilters = joinFilters;
|
|
553
|
+
this.distinct = distinct;
|
|
554
|
+
this.offset = offset;
|
|
555
|
+
this.having = having;
|
|
333
556
|
}
|
|
334
557
|
display;
|
|
335
558
|
filter;
|
|
@@ -338,7 +561,247 @@ var SelectOperation = class {
|
|
|
338
561
|
limit;
|
|
339
562
|
table;
|
|
340
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
|
+
}
|
|
341
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
|
+
}
|
|
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]);
|
|
342
805
|
|
|
343
806
|
// src/datafinder/attribute.ts
|
|
344
807
|
var Attribute = class _Attribute {
|
|
@@ -347,9 +810,11 @@ var Attribute = class _Attribute {
|
|
|
347
810
|
_owner;
|
|
348
811
|
_parent;
|
|
349
812
|
_embedded;
|
|
350
|
-
|
|
813
|
+
_optional;
|
|
814
|
+
constructor(displayName, columnName, columnDbType, owner, parent, embedded, nullable = true, optional = false) {
|
|
815
|
+
this._optional = optional;
|
|
351
816
|
this._displayName = displayName;
|
|
352
|
-
this._column = new Column(columnName, columnDbType, owner);
|
|
817
|
+
this._column = new Column(columnName, columnDbType, owner, false, nullable);
|
|
353
818
|
this._owner = owner;
|
|
354
819
|
this._parent = parent;
|
|
355
820
|
this._embedded = embedded;
|
|
@@ -370,10 +835,22 @@ var Attribute = class _Attribute {
|
|
|
370
835
|
embedded() {
|
|
371
836
|
return this._embedded;
|
|
372
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
|
+
}
|
|
373
850
|
cwj() {
|
|
374
|
-
return new ColumnWithJoin(this._column, this._parent, this._embedded?.cwj());
|
|
851
|
+
return new ColumnWithJoin(this._column, this._parent, this._embedded?.cwj(), this._optional);
|
|
375
852
|
}
|
|
376
|
-
/** Count the number of non-null values. Use in a projection with `
|
|
853
|
+
/** Count the number of non-null values. Use in a projection with `groupBy` to aggregate per group. */
|
|
377
854
|
count() {
|
|
378
855
|
return new AggregateOperation(
|
|
379
856
|
this.cwj(),
|
|
@@ -381,11 +858,26 @@ var Attribute = class _Attribute {
|
|
|
381
858
|
this._displayName + " Count"
|
|
382
859
|
);
|
|
383
860
|
}
|
|
384
|
-
/**
|
|
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`. */
|
|
385
877
|
ascending() {
|
|
386
878
|
return new SortOperation(this.cwj(), "ASC" /* ASC */);
|
|
387
879
|
}
|
|
388
|
-
/** Sort this attribute in descending order. Pass to `
|
|
880
|
+
/** Sort this attribute in descending order. Pass to `orderBy` or a window function's `orderBy`. */
|
|
389
881
|
descending() {
|
|
390
882
|
return new SortOperation(this.cwj(), "DESC" /* DESC */);
|
|
391
883
|
}
|
|
@@ -397,6 +889,23 @@ var Attribute = class _Attribute {
|
|
|
397
889
|
isNotNull() {
|
|
398
890
|
return new IsNotNullOperation(this.cwj());
|
|
399
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));
|
|
908
|
+
}
|
|
400
909
|
_windowSpec(partitionBy, orderBy) {
|
|
401
910
|
const pbArr = partitionBy === void 0 ? [] : Array.isArray(partitionBy) ? partitionBy : [partitionBy];
|
|
402
911
|
const pb = pbArr.map((x) => x instanceof _Attribute ? x.cwj() : x);
|
|
@@ -582,16 +1091,215 @@ var MilestonedTable = class extends Table {
|
|
|
582
1091
|
milestoningColumns;
|
|
583
1092
|
};
|
|
584
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
|
+
|
|
585
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]);
|
|
586
1286
|
function parseDate(value) {
|
|
587
1287
|
if (value instanceof Date) return value;
|
|
588
1288
|
const d = new Date(value);
|
|
589
1289
|
if (isNaN(d.getTime())) throw new Error(`Cannot parse date: ${value}`);
|
|
590
1290
|
return d;
|
|
591
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
|
+
}
|
|
592
1297
|
var DateAttribute = class extends Attribute {
|
|
593
|
-
constructor(displayName, columnName, columnDbType, owner, parent, embedded) {
|
|
594
|
-
super(displayName, columnName, columnDbType, owner, parent, embedded);
|
|
1298
|
+
constructor(displayName, columnName, columnDbType, owner, parent, embedded, nullable = true, optional = false) {
|
|
1299
|
+
super(displayName, columnName, columnDbType, owner, parent, embedded, nullable, optional);
|
|
1300
|
+
}
|
|
1301
|
+
toConstant(value) {
|
|
1302
|
+
return new DateConstantOperation(parseDate(value));
|
|
595
1303
|
}
|
|
596
1304
|
/** Filter to rows where this date equals `value`. */
|
|
597
1305
|
eq(value) {
|
|
@@ -641,6 +1349,22 @@ var DateAttribute = class extends Attribute {
|
|
|
641
1349
|
dayOfWeek() {
|
|
642
1350
|
return new DateExtractOperation(this.cwj(), "DOW" /* DOW */, "Day Of Week " + this.displayName());
|
|
643
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
|
+
}
|
|
644
1368
|
/** Add `n` days to this date. */
|
|
645
1369
|
addDays(n) {
|
|
646
1370
|
return new DateArithmeticOperation(this.cwj(), n, "DAY" /* DAY */, true, "Add Days " + this.displayName());
|
|
@@ -679,32 +1403,35 @@ var DateAttribute = class extends Attribute {
|
|
|
679
1403
|
}
|
|
680
1404
|
};
|
|
681
1405
|
var DateTimeAttribute = class extends Attribute {
|
|
682
|
-
constructor(displayName, columnName, columnDbType, owner, parent, embedded) {
|
|
683
|
-
super(displayName, columnName, columnDbType, owner, parent, embedded);
|
|
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);
|
|
684
1411
|
}
|
|
685
1412
|
/** Filter to rows where this timestamp equals `value`. */
|
|
686
1413
|
eq(value) {
|
|
687
|
-
return new ComparisonOperation(this.cwj(), "EQUAL" /* EQUAL */,
|
|
1414
|
+
return new ComparisonOperation(this.cwj(), "EQUAL" /* EQUAL */, temporalConstant(value));
|
|
688
1415
|
}
|
|
689
1416
|
/** Filter to rows where this timestamp does not equal `value`. */
|
|
690
1417
|
ne(value) {
|
|
691
|
-
return new ComparisonOperation(this.cwj(), "NOT_EQUAL" /* NOT_EQUAL */,
|
|
1418
|
+
return new ComparisonOperation(this.cwj(), "NOT_EQUAL" /* NOT_EQUAL */, temporalConstant(value));
|
|
692
1419
|
}
|
|
693
1420
|
/** Filter to rows where this timestamp is after `value`. */
|
|
694
1421
|
gt(value) {
|
|
695
|
-
return new ComparisonOperation(this.cwj(), "GREATER_THAN" /* GREATER_THAN */,
|
|
1422
|
+
return new ComparisonOperation(this.cwj(), "GREATER_THAN" /* GREATER_THAN */, temporalConstant(value));
|
|
696
1423
|
}
|
|
697
1424
|
/** Filter to rows where this timestamp is before `value`. */
|
|
698
1425
|
lt(value) {
|
|
699
|
-
return new ComparisonOperation(this.cwj(), "LESS_THAN" /* LESS_THAN */,
|
|
1426
|
+
return new ComparisonOperation(this.cwj(), "LESS_THAN" /* LESS_THAN */, temporalConstant(value));
|
|
700
1427
|
}
|
|
701
1428
|
/** Filter to rows where this timestamp is on or after `value`. */
|
|
702
1429
|
gte(value) {
|
|
703
|
-
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));
|
|
704
1431
|
}
|
|
705
1432
|
/** Filter to rows where this timestamp is on or before `value`. */
|
|
706
1433
|
lte(value) {
|
|
707
|
-
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));
|
|
708
1435
|
}
|
|
709
1436
|
/** Extract the four-digit calendar year. */
|
|
710
1437
|
year() {
|
|
@@ -742,6 +1469,22 @@ var DateTimeAttribute = class extends Attribute {
|
|
|
742
1469
|
dayOfWeek() {
|
|
743
1470
|
return new DateExtractOperation(this.cwj(), "DOW" /* DOW */, "Day Of Week " + this.displayName());
|
|
744
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
|
+
}
|
|
745
1488
|
/** Add `n` days to this timestamp. */
|
|
746
1489
|
addDays(n) {
|
|
747
1490
|
return new DateArithmeticOperation(this.cwj(), n, "DAY" /* DAY */, true, "Add Days " + this.displayName());
|
|
@@ -815,6 +1558,69 @@ var DateTimeAttribute = class extends Attribute {
|
|
|
815
1558
|
return new DateDiffOperation(this.cwj(), other, "SECOND" /* SECOND */, "Diff Seconds " + this.displayName());
|
|
816
1559
|
}
|
|
817
1560
|
};
|
|
1561
|
+
applyMixins(DateAttribute, [MinMax]);
|
|
1562
|
+
applyMixins(DateTimeAttribute, [MinMax]);
|
|
1563
|
+
|
|
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(", ") : ""})`
|
|
1593
|
+
};
|
|
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(", ") + ")" : ""}`
|
|
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
|
+
}
|
|
818
1624
|
|
|
819
1625
|
// src/datafinder/sql-generator.ts
|
|
820
1626
|
var TableAlias = class {
|
|
@@ -843,6 +1649,12 @@ var Join = class {
|
|
|
843
1649
|
source;
|
|
844
1650
|
target;
|
|
845
1651
|
filterOp;
|
|
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;
|
|
1657
|
+
}
|
|
846
1658
|
};
|
|
847
1659
|
function sqlFormatDatetime(value) {
|
|
848
1660
|
const pad = (n, w = 2) => String(n).padStart(w, "0");
|
|
@@ -869,6 +1681,13 @@ var COMPARISON_OPERATOR_STR = {
|
|
|
869
1681
|
var AGGREGATE_SQL_NAMES = {
|
|
870
1682
|
["AVERAGE" /* AVERAGE */]: "AVG"
|
|
871
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
|
+
]);
|
|
872
1691
|
var WINDOW_SQL_NAMES = {
|
|
873
1692
|
["ROW_NUMBER" /* ROW_NUMBER */]: "ROW_NUMBER",
|
|
874
1693
|
["RANK" /* RANK */]: "RANK",
|
|
@@ -900,31 +1719,63 @@ var SCALAR_SQL_NAMES = {
|
|
|
900
1719
|
["RIGHT" /* RIGHT */]: "RIGHT",
|
|
901
1720
|
["REPEAT" /* REPEAT */]: "REPEAT",
|
|
902
1721
|
["REPLACE" /* REPLACE */]: "REPLACE",
|
|
903
|
-
["SUBSTRING" /* SUBSTRING */]: "SUBSTRING"
|
|
1722
|
+
["SUBSTRING" /* SUBSTRING */]: "SUBSTRING",
|
|
1723
|
+
["COALESCE" /* COALESCE */]: "COALESCE"
|
|
904
1724
|
};
|
|
905
|
-
function constantValueString(op) {
|
|
906
|
-
if (op instanceof StringConstantOperation) return
|
|
1725
|
+
function constantValueString(op, d) {
|
|
1726
|
+
if (op instanceof StringConstantOperation) return d.stringLiteral(op.value);
|
|
907
1727
|
if (op instanceof DateConstantOperation) return sqlFormatDate(op.value);
|
|
908
1728
|
if (op instanceof DateTimeConstantOperation) return sqlFormatDatetime(op.value);
|
|
909
1729
|
if (op instanceof IntegerConstantOperation) return String(op.value);
|
|
910
|
-
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);
|
|
911
1731
|
if (op instanceof BooleanConstantOperation) return op.value ? "TRUE" : "FALSE";
|
|
912
1732
|
if (op instanceof DecimalConstantOperation) return String(op.value);
|
|
913
1733
|
throw new Error("Unknown constant operation");
|
|
914
1734
|
}
|
|
915
|
-
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) {
|
|
916
1742
|
const parts = [];
|
|
917
1743
|
if (window.partitionBy.length > 0) {
|
|
918
|
-
parts.push("PARTITION BY " + window.partitionBy.map((p) => sqlOperationToString(p)).join(", "));
|
|
1744
|
+
parts.push("PARTITION BY " + window.partitionBy.map((p) => sqlOperationToString(p, d)).join(", "));
|
|
919
1745
|
}
|
|
920
1746
|
if (window.orderBy.length > 0) {
|
|
921
1747
|
parts.push("ORDER BY " + window.orderBy.map(
|
|
922
|
-
(s) => sqlOperationToString(s.column) + (s.direction
|
|
1748
|
+
(s) => sqlOperationToString(s.column, d) + d.orderDirection(s.direction)
|
|
923
1749
|
).join(", "));
|
|
924
1750
|
}
|
|
925
1751
|
return "OVER (" + parts.join(" ") + ")";
|
|
926
1752
|
}
|
|
927
|
-
|
|
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) {
|
|
928
1779
|
if (operation instanceof TableAliasColumn) {
|
|
929
1780
|
return operation.tableAlias.alias + "." + operation.column.name;
|
|
930
1781
|
}
|
|
@@ -932,46 +1783,71 @@ function sqlOperationToString(operation) {
|
|
|
932
1783
|
const fn = WINDOW_SQL_NAMES[operation.func];
|
|
933
1784
|
const parts = [];
|
|
934
1785
|
if (operation.element !== null && operation.element !== void 0) {
|
|
935
|
-
parts.push(sqlOperationToString(operation.element));
|
|
1786
|
+
parts.push(sqlOperationToString(operation.element, d));
|
|
936
1787
|
}
|
|
937
1788
|
if (operation.secondArg !== void 0) parts.push(String(operation.secondArg));
|
|
938
1789
|
for (const arg of operation.extraArgs) {
|
|
939
|
-
parts.push(typeof arg === "string" ?
|
|
1790
|
+
parts.push(typeof arg === "string" ? d.stringLiteral(arg) : String(arg));
|
|
940
1791
|
}
|
|
941
1792
|
const sql = fn + "(" + parts.join(", ") + ")";
|
|
942
|
-
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;
|
|
943
1806
|
}
|
|
944
1807
|
if (operation instanceof AggregateOperation) {
|
|
945
1808
|
const fn = AGGREGATE_SQL_NAMES[operation.operator] ?? operation.operator;
|
|
946
|
-
let sql = fn + "(" + sqlOperationToString(operation.element) + ")";
|
|
1809
|
+
let sql = fn + "(" + sqlOperationToString(operation.element, d) + ")";
|
|
947
1810
|
if (operation.window !== void 0) {
|
|
948
|
-
sql += " " + windowSpecToString(operation.window);
|
|
1811
|
+
sql += " " + windowSpecToString(operation.window, d);
|
|
949
1812
|
}
|
|
950
1813
|
return sql;
|
|
951
1814
|
}
|
|
952
1815
|
if (operation instanceof ScalarFunctionOperation) {
|
|
953
1816
|
const fn = SCALAR_SQL_NAMES[operation.func];
|
|
954
|
-
const parts = [sqlOperationToString(operation.element)];
|
|
1817
|
+
const parts = [sqlOperationToString(operation.element, d)];
|
|
955
1818
|
if (operation.secondArg !== void 0) parts.push(String(operation.secondArg));
|
|
956
1819
|
for (const arg of operation.extraArgs) {
|
|
957
|
-
parts.push(typeof arg === "string" ?
|
|
1820
|
+
parts.push(typeof arg === "string" ? d.stringLiteral(arg) : String(arg));
|
|
958
1821
|
}
|
|
959
1822
|
return fn + "(" + parts.join(", ") + ")";
|
|
960
1823
|
}
|
|
961
1824
|
if (operation instanceof DateExtractOperation) {
|
|
962
|
-
|
|
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)";
|
|
963
1830
|
}
|
|
964
1831
|
if (operation instanceof DateArithmeticOperation) {
|
|
965
1832
|
const op = operation.isAdd ? "+" : "-";
|
|
966
|
-
return sqlOperationToString(operation.element) + " " + op + " INTERVAL " + operation.n + " " + operation.unit;
|
|
1833
|
+
return sqlOperationToString(operation.element, d) + " " + op + " INTERVAL '" + operation.n + "' " + operation.unit;
|
|
967
1834
|
}
|
|
968
1835
|
if (operation instanceof DateDiffOperation) {
|
|
969
|
-
|
|
970
|
-
return "DATE_DIFF('" + operation.unit.toLowerCase() + "', " + sqlOperationToString(operation.element) + ", " + otherSql + ")";
|
|
1836
|
+
return d.dateDiff(operation.unit, sqlOperationToString(operation.element, d), "TIMESTAMP " + sqlFormatDatetime(operation.other));
|
|
971
1837
|
}
|
|
972
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
|
+
}
|
|
973
1849
|
if (operation instanceof Alias) {
|
|
974
|
-
return sqlOperationToString(operation.element) +
|
|
1850
|
+
return sqlOperationToString(operation.element, d) + " AS " + d.quoteIdentifier(operation.name);
|
|
975
1851
|
}
|
|
976
1852
|
throw new TypeError("Unknown operation in sqlOperationToString: " + operation.constructor.name);
|
|
977
1853
|
}
|
|
@@ -991,73 +1867,53 @@ function openEndClause(endAttr, value, infiniteDatetime) {
|
|
|
991
1867
|
}
|
|
992
1868
|
return gtOp;
|
|
993
1869
|
}
|
|
994
|
-
function
|
|
995
|
-
const
|
|
996
|
-
|
|
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;
|
|
997
1883
|
if (mc instanceof BiTemporalColumns) {
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
if (processingDatetime !== null) {
|
|
1004
|
-
const startAt = new DateTimeAttribute("start_at", mc.startAtColumn.name, mc.startAtColumn.type, mc.startAtColumn.table.qualifiedName, joinNode);
|
|
1005
|
-
const endAt = new DateTimeAttribute("end_at", mc.endAtColumn.name, mc.endAtColumn.type, mc.endAtColumn.table.qualifiedName, joinNode);
|
|
1006
|
-
ops.push(new LogicalOperation(startAt.lte(processingDatetime), "AND" /* AND */, openEndClause(endAt, processingDatetime, mc.infiniteDatetime)));
|
|
1007
|
-
}
|
|
1008
|
-
} else if (mc instanceof BusinessDateAndProcessingTemporalColumns) {
|
|
1009
|
-
if (businessDate !== null) {
|
|
1010
|
-
const businessAtt = new DateAttribute("business_date", mc.businessDateColumn.name, mc.businessDateColumn.type, mc.businessDateColumn.table.qualifiedName, joinNode);
|
|
1011
|
-
ops.push(businessAtt.eq(businessDate));
|
|
1012
|
-
}
|
|
1013
|
-
if (processingDatetime !== null) {
|
|
1014
|
-
const startAt = new DateTimeAttribute("start_at", mc.startAtColumn.name, mc.startAtColumn.type, mc.startAtColumn.table.qualifiedName, joinNode);
|
|
1015
|
-
const endAt = new DateTimeAttribute("end_at", mc.endAtColumn.name, mc.endAtColumn.type, mc.endAtColumn.table.qualifiedName, joinNode);
|
|
1016
|
-
ops.push(new LogicalOperation(startAt.lte(processingDatetime), "AND" /* AND */, openEndClause(endAt, processingDatetime, mc.infiniteDatetime)));
|
|
1017
|
-
}
|
|
1018
|
-
} else if (mc instanceof ProcessingTemporalColumns && processingDatetime !== null) {
|
|
1019
|
-
const startAt = new DateTimeAttribute("start_at", mc.startAtColumn.name, mc.startAtColumn.type, mc.startAtColumn.table.qualifiedName, joinNode);
|
|
1020
|
-
const endAt = new DateTimeAttribute("end_at", mc.endAtColumn.name, mc.endAtColumn.type, mc.endAtColumn.table.qualifiedName, joinNode);
|
|
1021
|
-
ops.push(new LogicalOperation(startAt.lte(processingDatetime), "AND" /* AND */, openEndClause(endAt, processingDatetime, mc.infiniteDatetime)));
|
|
1022
|
-
} else if (mc instanceof SingleBusinessDateColumn && businessDate !== null) {
|
|
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) {
|
|
1023
1889
|
const businessAtt = new DateAttribute("business_date", mc.businessDateColumn.name, mc.businessDateColumn.type, mc.businessDateColumn.table.qualifiedName, joinNode);
|
|
1024
|
-
|
|
1890
|
+
return businessAtt.eq(businessDate);
|
|
1025
1891
|
}
|
|
1026
|
-
|
|
1027
|
-
if (ops.length === 1) return ops[0];
|
|
1028
|
-
return new LogicalOperation(ops[0], "AND" /* AND */, ops[1]);
|
|
1892
|
+
return null;
|
|
1029
1893
|
}
|
|
1030
|
-
function
|
|
1031
|
-
|
|
1032
|
-
const ops = [];
|
|
1033
|
-
const hasRange = businessDateFrom !== null && businessDateTo !== null;
|
|
1034
|
-
const processingOp = (m) => {
|
|
1035
|
-
const startAt = new DateTimeAttribute("start_at", m.startAtColumn.name, m.startAtColumn.type, m.startAtColumn.table.qualifiedName, joinNode);
|
|
1036
|
-
const endAt = new DateTimeAttribute("end_at", m.endAtColumn.name, m.endAtColumn.type, m.endAtColumn.table.qualifiedName, joinNode);
|
|
1037
|
-
return new LogicalOperation(startAt.lte(processingDatetime), "AND" /* AND */, openEndClause(endAt, processingDatetime, m.infiniteDatetime));
|
|
1038
|
-
};
|
|
1894
|
+
function businessRangePredicate(mc, businessDateFrom, businessDateTo, joinNode) {
|
|
1895
|
+
if (businessDateFrom === null || businessDateTo === null) return null;
|
|
1039
1896
|
if (mc instanceof BiTemporalColumns) {
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
if (processingDatetime !== null) ops.push(processingOp(mc));
|
|
1046
|
-
} else if (mc instanceof BusinessDateAndProcessingTemporalColumns) {
|
|
1047
|
-
if (hasRange) {
|
|
1048
|
-
const businessAtt = new DateAttribute("business_date", mc.businessDateColumn.name, mc.businessDateColumn.type, mc.businessDateColumn.table.qualifiedName, joinNode);
|
|
1049
|
-
ops.push(new LogicalOperation(businessAtt.gte(businessDateFrom), "AND" /* AND */, businessAtt.lte(businessDateTo)));
|
|
1050
|
-
}
|
|
1051
|
-
if (processingDatetime !== null) ops.push(processingOp(mc));
|
|
1052
|
-
} else if (mc instanceof ProcessingTemporalColumns) {
|
|
1053
|
-
if (processingDatetime !== null) ops.push(processingOp(mc));
|
|
1054
|
-
} else if (mc instanceof SingleBusinessDateColumn && hasRange) {
|
|
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) {
|
|
1055
1902
|
const businessAtt = new DateAttribute("business_date", mc.businessDateColumn.name, mc.businessDateColumn.type, mc.businessDateColumn.table.qualifiedName, joinNode);
|
|
1056
|
-
|
|
1903
|
+
return new LogicalOperation(businessAtt.gte(businessDateFrom), "AND" /* AND */, businessAtt.lte(businessDateTo));
|
|
1057
1904
|
}
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1905
|
+
return null;
|
|
1906
|
+
}
|
|
1907
|
+
function buildMilestoningFilterOperation(businessDate, processingDatetime, table, joinNode) {
|
|
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
|
+
]);
|
|
1061
1917
|
}
|
|
1062
1918
|
function walkRefs(op, visit, visitExists) {
|
|
1063
1919
|
if (op === null || op === void 0) return;
|
|
@@ -1068,11 +1924,23 @@ function walkRefs(op, visit, visitExists) {
|
|
|
1068
1924
|
} else if (op instanceof AggregateOperation) {
|
|
1069
1925
|
walkRefs(op.element, visit, visitExists);
|
|
1070
1926
|
if (op.window) walkWindowSpec(op.window, visit, visitExists);
|
|
1927
|
+
for (const sort of op.orderBy) walkRefs(sort, visit, visitExists);
|
|
1071
1928
|
} else if (op instanceof WindowFunctionOperation) {
|
|
1072
1929
|
if (op.element) walkRefs(op.element, visit, visitExists);
|
|
1073
1930
|
if (op.window) walkWindowSpec(op.window, visit, visitExists);
|
|
1074
|
-
} else if (op instanceof ScalarFunctionOperation || op instanceof DateExtractOperation || op instanceof DateArithmeticOperation || op instanceof DateDiffOperation || op instanceof IsNullOperation || op instanceof IsNotNullOperation) {
|
|
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) {
|
|
1075
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);
|
|
1076
1944
|
} else if (op instanceof SortOperation) {
|
|
1077
1945
|
walkRefs(op.column, visit, visitExists);
|
|
1078
1946
|
} else if (op instanceof LogicalOperation || op instanceof ComparisonOperation) {
|
|
@@ -1112,7 +1980,7 @@ function withAncestors(nodes) {
|
|
|
1112
1980
|
for (const node of nodes) add(node);
|
|
1113
1981
|
return [...ordered];
|
|
1114
1982
|
}
|
|
1115
|
-
function buildQueryOperation(businessDate, processingDatetime, columns, table, op, orderBy = [], groupBy = [], limit, businessDateTo = null) {
|
|
1983
|
+
function buildQueryOperation(businessDate, processingDatetime, columns, table, op, orderBy = [], groupBy = [], limit, businessDateTo = null, distinct = false, offset, having) {
|
|
1116
1984
|
let filter = op;
|
|
1117
1985
|
const milestoningFor = (t, node) => businessDateTo !== null ? buildMilestoningFilterOperationForDateRange(businessDate, businessDateTo, processingDatetime, t, node) : buildMilestoningFilterOperation(businessDate, processingDatetime, t, node);
|
|
1118
1986
|
if (table instanceof MilestonedTable) {
|
|
@@ -1145,22 +2013,45 @@ function buildQueryOperation(businessDate, processingDatetime, columns, table, o
|
|
|
1145
2013
|
}
|
|
1146
2014
|
if (combined !== void 0) joinFilters.set(node, combined);
|
|
1147
2015
|
}
|
|
1148
|
-
return new SelectOperation(columns, filter, orderBy, groupBy, limit, table, joinFilters);
|
|
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;
|
|
1149
2032
|
}
|
|
1150
2033
|
var SQLQueryGenerator = class {
|
|
2034
|
+
constructor(_dialect) {
|
|
2035
|
+
this._dialect = _dialect;
|
|
2036
|
+
}
|
|
2037
|
+
_dialect;
|
|
1151
2038
|
_select = [];
|
|
1152
2039
|
_from = /* @__PURE__ */ new Set();
|
|
1153
2040
|
_join = [];
|
|
1154
2041
|
_groupByParts = [];
|
|
2042
|
+
_having = "";
|
|
1155
2043
|
_orderByParts = [];
|
|
1156
2044
|
_where = "";
|
|
1157
2045
|
_limit;
|
|
2046
|
+
_distinct = false;
|
|
2047
|
+
_offset;
|
|
1158
2048
|
_tableAliasIncr = 0;
|
|
1159
2049
|
_tableAliasesByTable = /* @__PURE__ */ new Map();
|
|
1160
2050
|
_addedJoinIds = /* @__PURE__ */ new Set();
|
|
1161
2051
|
_rootTable;
|
|
1162
2052
|
_elidableNodes = /* @__PURE__ */ new Set();
|
|
1163
2053
|
_joinFilters = /* @__PURE__ */ new Map();
|
|
2054
|
+
_guardOptional = true;
|
|
1164
2055
|
generate(select) {
|
|
1165
2056
|
this._rootTable = select.table;
|
|
1166
2057
|
this._elidableNodes = this._computeElidableNodes(select);
|
|
@@ -1177,11 +2068,52 @@ var SQLQueryGenerator = class {
|
|
|
1177
2068
|
for (const node of groupByJoins.values()) {
|
|
1178
2069
|
this._addJoin(node);
|
|
1179
2070
|
}
|
|
1180
|
-
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
|
+
}
|
|
1181
2084
|
this._orderByParts = select.orderBy.map(
|
|
1182
|
-
(s) => this.
|
|
2085
|
+
(s) => this._sortExpression(s.column) + this._dialect.orderDirection(s.direction)
|
|
1183
2086
|
);
|
|
1184
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;
|
|
1185
2117
|
}
|
|
1186
2118
|
_attrToColString(attr) {
|
|
1187
2119
|
const { column, parent } = this._resolve(attr);
|
|
@@ -1228,6 +2160,13 @@ var SQLQueryGenerator = class {
|
|
|
1228
2160
|
}
|
|
1229
2161
|
return { column, parent };
|
|
1230
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);
|
|
2167
|
+
}
|
|
2168
|
+
return op.optional;
|
|
2169
|
+
}
|
|
1231
2170
|
_rewriteWindowSpec(window) {
|
|
1232
2171
|
const partitionBy = window.partitionBy.map((p) => this._rewriteOperation(p));
|
|
1233
2172
|
const orderBy = window.orderBy.map((s) => new SortOperation(this._rewriteOperation(s.column), s.direction));
|
|
@@ -1247,9 +2186,17 @@ var SQLQueryGenerator = class {
|
|
|
1247
2186
|
this._rewriteOperation(op.element),
|
|
1248
2187
|
op.operator,
|
|
1249
2188
|
op.displayName,
|
|
1250
|
-
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))
|
|
1251
2192
|
);
|
|
1252
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
|
+
}
|
|
1253
2200
|
if (op instanceof WindowFunctionOperation) {
|
|
1254
2201
|
const el = op.element ? this._rewriteOperation(op.element) : null;
|
|
1255
2202
|
return new WindowFunctionOperation(
|
|
@@ -1267,6 +2214,9 @@ var SQLQueryGenerator = class {
|
|
|
1267
2214
|
if (op instanceof DateExtractOperation) {
|
|
1268
2215
|
return new DateExtractOperation(this._rewriteOperation(op.element), op.part, op.displayName);
|
|
1269
2216
|
}
|
|
2217
|
+
if (op instanceof DateTruncOperation) {
|
|
2218
|
+
return new DateTruncOperation(this._rewriteOperation(op.element), op.part, op.displayName);
|
|
2219
|
+
}
|
|
1270
2220
|
if (op instanceof DateArithmeticOperation) {
|
|
1271
2221
|
return new DateArithmeticOperation(this._rewriteOperation(op.element), op.n, op.unit, op.isAdd, op.displayName);
|
|
1272
2222
|
}
|
|
@@ -1275,6 +2225,13 @@ var SQLQueryGenerator = class {
|
|
|
1275
2225
|
}
|
|
1276
2226
|
return op;
|
|
1277
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
|
+
}
|
|
1278
2235
|
processSelect(cols) {
|
|
1279
2236
|
const requiredJoins = /* @__PURE__ */ new Map();
|
|
1280
2237
|
for (const col of cols) {
|
|
@@ -1283,88 +2240,96 @@ var SQLQueryGenerator = class {
|
|
|
1283
2240
|
for (const node of requiredJoins.values()) {
|
|
1284
2241
|
this._addJoin(node);
|
|
1285
2242
|
}
|
|
1286
|
-
for (const col of cols)
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
);
|
|
1327
|
-
this.
|
|
1328
|
-
}
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
} else {
|
|
1350
|
-
ta = this._tableAliasForTable(colNested.column.owner, colNested.column.owner);
|
|
1351
|
-
this._from.add(ta);
|
|
1352
|
-
}
|
|
1353
|
-
const alias = col.displayName ?? findColumn(col).column.name;
|
|
1354
|
-
let aliasedOp;
|
|
1355
|
-
if (col instanceof DateExtractOperation) {
|
|
1356
|
-
aliasedOp = new DateExtractOperation(new TableAliasColumn(colNested.column, ta), col.part);
|
|
1357
|
-
} else if (col instanceof DateArithmeticOperation) {
|
|
1358
|
-
aliasedOp = new DateArithmeticOperation(new TableAliasColumn(colNested.column, ta), col.n, col.unit, col.isAdd);
|
|
1359
|
-
} else {
|
|
1360
|
-
aliasedOp = new DateDiffOperation(new TableAliasColumn(colNested.column, ta), col.other, col.unit);
|
|
1361
|
-
}
|
|
1362
|
-
this._select.push(new Alias(aliasedOp, alias));
|
|
1363
|
-
} else if (col instanceof CountAllOperation) {
|
|
1364
|
-
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);
|
|
1365
2306
|
this._from.add(ta);
|
|
1366
|
-
this._select.push(new Alias(col, "Count"));
|
|
1367
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"));
|
|
1368
2333
|
}
|
|
1369
2334
|
}
|
|
1370
2335
|
_addJoin(node) {
|
|
@@ -1392,19 +2357,43 @@ var SQLQueryGenerator = class {
|
|
|
1392
2357
|
const col = op.node.join.right;
|
|
1393
2358
|
return this.buildFilter(new ColumnWithJoin(col, op.node)) + " IS NULL";
|
|
1394
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
|
+
}
|
|
1395
2371
|
if (op instanceof IsNotNullOperation) return this.buildFilter(op.element) + " IS NOT NULL";
|
|
1396
2372
|
if (op instanceof IsNullOperation) return this.buildFilter(op.element) + " IS NULL";
|
|
1397
2373
|
if (op instanceof LogicalOperation) {
|
|
1398
2374
|
let left = this.buildFilter(op.left);
|
|
1399
2375
|
let right = this.buildFilter(op.right);
|
|
1400
|
-
if (op.left
|
|
1401
|
-
if (op.right
|
|
2376
|
+
if (needsParentheses(op, op.left)) left = "(" + left + ")";
|
|
2377
|
+
if (needsParentheses(op, op.right)) right = "(" + right + ")";
|
|
1402
2378
|
return left + LOGICAL_OPERATOR_STR[op.operator] + right;
|
|
1403
2379
|
}
|
|
1404
2380
|
if (op instanceof ComparisonOperation) {
|
|
1405
|
-
|
|
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);
|
|
1406
2396
|
}
|
|
1407
|
-
if (op instanceof ConstantOperation) return constantValueString(op);
|
|
1408
2397
|
if (op instanceof ColumnWithJoin) {
|
|
1409
2398
|
const { column, parent: node } = this._resolve(op);
|
|
1410
2399
|
let ta;
|
|
@@ -1432,9 +2421,9 @@ var SQLQueryGenerator = class {
|
|
|
1432
2421
|
}
|
|
1433
2422
|
buildQueryString() {
|
|
1434
2423
|
const joins = this._join.map(
|
|
1435
|
-
(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) : "") + ")"
|
|
1436
2425
|
);
|
|
1437
|
-
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();
|
|
1438
2427
|
}
|
|
1439
2428
|
_buildWhere() {
|
|
1440
2429
|
return this._where.length > 0 ? " WHERE " + this._where : "";
|
|
@@ -1442,25 +2431,33 @@ var SQLQueryGenerator = class {
|
|
|
1442
2431
|
_buildGroupBy() {
|
|
1443
2432
|
return this._groupByParts.length > 0 ? " GROUP BY " + this._groupByParts.join(", ") : "";
|
|
1444
2433
|
}
|
|
2434
|
+
_buildHaving() {
|
|
2435
|
+
return this._having.length > 0 ? " HAVING " + this._having : "";
|
|
2436
|
+
}
|
|
1445
2437
|
_buildOrderBy() {
|
|
1446
2438
|
return this._orderByParts.length > 0 ? " ORDER BY " + this._orderByParts.join(", ") : "";
|
|
1447
2439
|
}
|
|
2440
|
+
_buildOffset() {
|
|
2441
|
+
return this._offset !== void 0 ? " OFFSET " + this._offset : "";
|
|
2442
|
+
}
|
|
1448
2443
|
_buildLimit() {
|
|
1449
2444
|
return this._limit !== void 0 ? " LIMIT " + this._limit : "";
|
|
1450
2445
|
}
|
|
1451
2446
|
};
|
|
1452
|
-
function selectSqlToString(selectOperation) {
|
|
1453
|
-
const qg = new SQLQueryGenerator();
|
|
2447
|
+
function selectSqlToString(selectOperation, dialect = "postgres") {
|
|
2448
|
+
const qg = new SQLQueryGenerator(dialectOf(dialect));
|
|
1454
2449
|
qg.generate(selectOperation);
|
|
1455
2450
|
return qg.buildQueryString();
|
|
1456
2451
|
}
|
|
1457
|
-
function toSql(businessDate, processingDatetime, columns, table, op, orderBy = [], groupBy = [], limit, businessDateTo = null) {
|
|
1458
|
-
const selectOp = buildQueryOperation(businessDate, processingDatetime, columns, table, op, orderBy, groupBy, limit, businessDateTo);
|
|
1459
|
-
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);
|
|
1460
2455
|
}
|
|
1461
2456
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1462
2457
|
0 && (module.exports = {
|
|
2458
|
+
arithmeticNeedsParentheses,
|
|
1463
2459
|
buildQueryOperation,
|
|
2460
|
+
needsParentheses,
|
|
1464
2461
|
selectSqlToString,
|
|
1465
2462
|
toSql
|
|
1466
2463
|
});
|