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.
Files changed (58) hide show
  1. package/dist/{chunk-4JVW4TAB.js → chunk-BGEX377Q.js} +58 -8
  2. package/dist/chunk-BGEX377Q.js.map +1 -0
  3. package/dist/chunk-BKPWV3OF.js +962 -0
  4. package/dist/chunk-BKPWV3OF.js.map +1 -0
  5. package/dist/{chunk-PMPLCEWQ.js → chunk-GPHWC533.js} +2 -2
  6. package/dist/{chunk-FJYA2ASS.js → chunk-KAK75RVS.js} +74 -12
  7. package/dist/chunk-KAK75RVS.js.map +1 -0
  8. package/dist/{chunk-4LNZV6EN.js → chunk-MGEL5RWM.js} +206 -78
  9. package/dist/chunk-MGEL5RWM.js.map +1 -0
  10. package/dist/chunk-PF6EJZHB.js +1015 -0
  11. package/dist/chunk-PF6EJZHB.js.map +1 -0
  12. package/dist/datafinder/attribute.cjs +537 -11
  13. package/dist/datafinder/attribute.cjs.map +1 -1
  14. package/dist/datafinder/attribute.d.cts +29 -7
  15. package/dist/datafinder/attribute.d.ts +29 -7
  16. package/dist/datafinder/attribute.js +2 -2
  17. package/dist/datafinder/runner.cjs +1267 -215
  18. package/dist/datafinder/runner.cjs.map +1 -1
  19. package/dist/datafinder/runner.d.cts +28 -5
  20. package/dist/datafinder/runner.d.ts +28 -5
  21. package/dist/datafinder/runner.js +6 -6
  22. package/dist/datafinder/sql-generator.cjs +1203 -206
  23. package/dist/datafinder/sql-generator.cjs.map +1 -1
  24. package/dist/datafinder/sql-generator.d.cts +19 -5
  25. package/dist/datafinder/sql-generator.d.ts +19 -5
  26. package/dist/datafinder/sql-generator.js +9 -5
  27. package/dist/datafinder/typed-attributes.cjs +693 -88
  28. package/dist/datafinder/typed-attributes.cjs.map +1 -1
  29. package/dist/datafinder/typed-attributes.d.cts +3 -242
  30. package/dist/datafinder/typed-attributes.d.ts +3 -242
  31. package/dist/datafinder/typed-attributes.js +3 -3
  32. package/dist/dialect-CogGPm_y.d.cts +38 -0
  33. package/dist/dialect-aaG1bDi5.d.ts +38 -0
  34. package/dist/index.cjs +1677 -408
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.cts +109 -5
  37. package/dist/index.d.ts +109 -5
  38. package/dist/index.js +321 -11
  39. package/dist/index.js.map +1 -1
  40. package/dist/model/milestoning.cjs +529 -0
  41. package/dist/model/milestoning.cjs.map +1 -1
  42. package/dist/model/milestoning.js +2 -2
  43. package/dist/model/relational.cjs +547 -16
  44. package/dist/model/relational.cjs.map +1 -1
  45. package/dist/model/relational.d.cts +421 -57
  46. package/dist/model/relational.d.ts +421 -57
  47. package/dist/model/relational.js +53 -3
  48. package/dist/typed-attributes-CUTf_6Ru.d.ts +328 -0
  49. package/dist/typed-attributes-CdWXq_78.d.cts +328 -0
  50. package/package.json +3 -2
  51. package/dist/chunk-4JVW4TAB.js.map +0 -1
  52. package/dist/chunk-4LNZV6EN.js.map +0 -1
  53. package/dist/chunk-FJYA2ASS.js.map +0 -1
  54. package/dist/chunk-MH4XMYVB.js +0 -696
  55. package/dist/chunk-MH4XMYVB.js.map +0 -1
  56. package/dist/chunk-UYMOE6YU.js +0 -509
  57. package/dist/chunk-UYMOE6YU.js.map +0 -1
  58. /package/dist/{chunk-PMPLCEWQ.js.map → chunk-GPHWC533.js.map} +0 -0
package/dist/index.cjs CHANGED
@@ -22,31 +22,46 @@ var src_exports = {};
22
22
  __export(src_exports, {
23
23
  AggregateOperation: () => AggregateOperation,
24
24
  AggregateOperator: () => AggregateOperator,
25
+ Aggregates: () => Aggregates,
25
26
  Alias: () => Alias,
27
+ Arithmetic: () => Arithmetic,
28
+ ArithmeticOperation: () => ArithmeticOperation,
29
+ ArithmeticOperator: () => ArithmeticOperator,
26
30
  Attribute: () => Attribute,
27
31
  BiTemporalColumns: () => BiTemporalColumns,
28
32
  BinaryOperation: () => BinaryOperation,
33
+ BooleanAggregates: () => BooleanAggregates,
29
34
  BooleanAttribute: () => BooleanAttribute,
30
35
  BooleanConstantOperation: () => BooleanConstantOperation,
31
36
  BusinessDateAndProcessingTemporalColumns: () => BusinessDateAndProcessingTemporalColumns,
37
+ CaseOperation: () => CaseOperation,
32
38
  Column: () => Column,
33
39
  ColumnWithJoin: () => ColumnWithJoin,
40
+ Comparable: () => Comparable,
34
41
  ComparisonOperation: () => ComparisonOperation,
35
42
  ComparisonOperator: () => ComparisonOperator,
43
+ ConcatOperation: () => ConcatOperation,
36
44
  ConstantOperation: () => ConstantOperation,
37
45
  CountAllOperation: () => CountAllOperation,
46
+ DATABRICKS: () => DATABRICKS,
47
+ DATE_ONLY_PATTERN: () => DATE_ONLY_PATTERN,
38
48
  DEFAULT_TIMEOUT_MS: () => DEFAULT_TIMEOUT_MS,
49
+ DUCKDB: () => DUCKDB,
39
50
  DataCatalog: () => DataCatalog,
40
51
  DataStore: () => DataStore,
41
52
  Database: () => Database,
53
+ DatabricksConnect: () => DatabricksConnect,
54
+ DatabricksQueryError: () => DatabricksQueryError,
42
55
  DateArithmeticOperation: () => DateArithmeticOperation,
43
56
  DateAttribute: () => DateAttribute,
44
57
  DateConstantOperation: () => DateConstantOperation,
45
58
  DateDiffOperation: () => DateDiffOperation,
46
59
  DateExtractOperation: () => DateExtractOperation,
60
+ DateOnly: () => DateOnly,
47
61
  DatePart: () => DatePart,
48
62
  DateTimeAttribute: () => DateTimeAttribute,
49
63
  DateTimeConstantOperation: () => DateTimeConstantOperation,
64
+ DateTruncOperation: () => DateTruncOperation,
50
65
  DecimalAttribute: () => DecimalAttribute,
51
66
  DecimalConstantOperation: () => DecimalConstantOperation,
52
67
  DoubleAttribute: () => DoubleAttribute,
@@ -55,20 +70,27 @@ __export(src_exports, {
55
70
  FloatAttribute: () => FloatAttribute,
56
71
  FloatConstantOperation: () => FloatConstantOperation,
57
72
  ForeignKey: () => ForeignKey,
73
+ InOperation: () => InOperation,
58
74
  IntegerAttribute: () => IntegerAttribute,
59
75
  IntegerConstantOperation: () => IntegerConstantOperation,
60
76
  IsNotNullOperation: () => IsNotNullOperation,
61
77
  IsNullOperation: () => IsNullOperation,
62
78
  JoinOperation: () => JoinOperation,
63
79
  JoinTreeNodeOperation: () => JoinTreeNodeOperation,
80
+ LIKE_ESCAPE: () => LIKE_ESCAPE,
64
81
  LogicalOperation: () => LogicalOperation,
65
82
  LogicalOperator: () => LogicalOperator,
66
83
  MilestonedTable: () => MilestonedTable,
67
84
  MilestoningColumns: () => MilestoningColumns,
85
+ NUMERIC_FUNCTIONS: () => NUMERIC_FUNCTIONS,
68
86
  NoOperation: () => NoOperation,
69
87
  NotExistsOperation: () => NotExistsOperation,
88
+ NotInOperation: () => NotInOperation,
70
89
  NumericAttribute: () => NumericAttribute,
90
+ NumericConstantOperation: () => NumericConstantOperation,
91
+ NumericFunctionOperation: () => NumericFunctionOperation,
71
92
  Operation: () => Operation,
93
+ POSTGRES: () => POSTGRES,
72
94
  ProcessingTemporalColumns: () => ProcessingTemporalColumns,
73
95
  QueryTimeoutError: () => QueryTimeoutError,
74
96
  RelatedFinder: () => RelatedFinder,
@@ -82,22 +104,36 @@ __export(src_exports, {
82
104
  SortOperation: () => SortOperation,
83
105
  StringAttribute: () => StringAttribute,
84
106
  StringConstantOperation: () => StringConstantOperation,
107
+ StringFunctionOperation: () => StringFunctionOperation,
108
+ StringPredicates: () => StringPredicates,
85
109
  Table: () => Table,
86
110
  UnaryOperation: () => UnaryOperation,
87
111
  WindowFunction: () => WindowFunction,
88
112
  WindowFunctionOperation: () => WindowFunctionOperation,
89
113
  WindowSpecification: () => WindowSpecification,
114
+ applyMixins: () => applyMixins,
90
115
  clearRunner: () => clearRunner,
116
+ concat: () => concat,
117
+ constant: () => constant,
118
+ containsAggregate: () => containsAggregate,
119
+ containsAggregateOrWindow: () => containsAggregateOrWindow,
91
120
  convertInputsAndSelect: () => convertInputsAndSelect,
92
121
  convertInputsAndSelectForDateRange: () => convertInputsAndSelectForDateRange,
122
+ countAll: () => countAll,
123
+ dialectOf: () => dialectOf,
93
124
  embeddedUnder: () => embeddedUnder,
125
+ escapeLike: () => escapeLike,
94
126
  getRelatedFinderClass: () => getRelatedFinderClass,
95
127
  getRunner: () => getRunner,
128
+ operandOf: () => operandOf,
96
129
  registerRelatedFinderClass: () => registerRelatedFinderClass,
97
130
  registerRunner: () => registerRunner,
131
+ sample: () => sample,
98
132
  selectSqlToString: () => selectSqlToString,
99
133
  titleCase: () => titleCase,
100
- toSql: () => toSql
134
+ toSql: () => toSql,
135
+ valueOperand: () => valueOperand,
136
+ when: () => when
101
137
  });
102
138
  module.exports = __toCommonJS(src_exports);
103
139
 
@@ -113,6 +149,10 @@ var ComparisonOperator = /* @__PURE__ */ ((ComparisonOperator2) => {
113
149
  ComparisonOperator2["NOT_LIKE"] = "NOT_LIKE";
114
150
  return ComparisonOperator2;
115
151
  })(ComparisonOperator || {});
152
+ var LIKE_ESCAPE = "!";
153
+ function escapeLike(value2) {
154
+ return value2.replaceAll(LIKE_ESCAPE, LIKE_ESCAPE + LIKE_ESCAPE).replaceAll("%", LIKE_ESCAPE + "%").replaceAll("_", LIKE_ESCAPE + "_");
155
+ }
116
156
  var LogicalOperator = /* @__PURE__ */ ((LogicalOperator2) => {
117
157
  LogicalOperator2["AND"] = "AND";
118
158
  LogicalOperator2["OR"] = "OR";
@@ -124,29 +164,38 @@ var AggregateOperator = /* @__PURE__ */ ((AggregateOperator2) => {
124
164
  AggregateOperator2["MIN"] = "MIN";
125
165
  AggregateOperator2["MAX"] = "MAX";
126
166
  AggregateOperator2["AVERAGE"] = "AVERAGE";
167
+ AggregateOperator2["STRING_AGG"] = "STRING_AGG";
168
+ AggregateOperator2["COUNT_DISTINCT"] = "COUNT_DISTINCT";
169
+ AggregateOperator2["STDDEV_SAMP"] = "STDDEV_SAMP";
170
+ AggregateOperator2["STDDEV_POP"] = "STDDEV_POP";
171
+ AggregateOperator2["VAR_SAMP"] = "VAR_SAMP";
172
+ AggregateOperator2["VAR_POP"] = "VAR_POP";
173
+ AggregateOperator2["BOOL_AND"] = "BOOL_AND";
174
+ AggregateOperator2["BOOL_OR"] = "BOOL_OR";
127
175
  return AggregateOperator2;
128
176
  })(AggregateOperator || {});
129
- var ScalarFunction = /* @__PURE__ */ ((ScalarFunction2) => {
130
- ScalarFunction2["ABS"] = "ABS";
131
- ScalarFunction2["CEILING"] = "CEILING";
132
- ScalarFunction2["FLOOR"] = "FLOOR";
133
- ScalarFunction2["MOD"] = "MOD";
134
- ScalarFunction2["POWER"] = "POWER";
135
- ScalarFunction2["SQRT"] = "SQRT";
136
- ScalarFunction2["ROUND"] = "ROUND";
137
- ScalarFunction2["UPPER"] = "UPPER";
138
- ScalarFunction2["LOWER"] = "LOWER";
139
- ScalarFunction2["TRIM"] = "TRIM";
140
- ScalarFunction2["LTRIM"] = "LTRIM";
141
- ScalarFunction2["RTRIM"] = "RTRIM";
142
- ScalarFunction2["LENGTH"] = "LENGTH";
143
- ScalarFunction2["REVERSE"] = "REVERSE";
144
- ScalarFunction2["LEFT"] = "LEFT";
145
- ScalarFunction2["RIGHT"] = "RIGHT";
146
- ScalarFunction2["REPEAT"] = "REPEAT";
147
- ScalarFunction2["REPLACE"] = "REPLACE";
148
- ScalarFunction2["SUBSTRING"] = "SUBSTRING";
149
- return ScalarFunction2;
177
+ var ScalarFunction = /* @__PURE__ */ ((ScalarFunction3) => {
178
+ ScalarFunction3["ABS"] = "ABS";
179
+ ScalarFunction3["CEILING"] = "CEILING";
180
+ ScalarFunction3["FLOOR"] = "FLOOR";
181
+ ScalarFunction3["MOD"] = "MOD";
182
+ ScalarFunction3["POWER"] = "POWER";
183
+ ScalarFunction3["SQRT"] = "SQRT";
184
+ ScalarFunction3["ROUND"] = "ROUND";
185
+ ScalarFunction3["UPPER"] = "UPPER";
186
+ ScalarFunction3["LOWER"] = "LOWER";
187
+ ScalarFunction3["TRIM"] = "TRIM";
188
+ ScalarFunction3["LTRIM"] = "LTRIM";
189
+ ScalarFunction3["RTRIM"] = "RTRIM";
190
+ ScalarFunction3["LENGTH"] = "LENGTH";
191
+ ScalarFunction3["REVERSE"] = "REVERSE";
192
+ ScalarFunction3["LEFT"] = "LEFT";
193
+ ScalarFunction3["RIGHT"] = "RIGHT";
194
+ ScalarFunction3["REPEAT"] = "REPEAT";
195
+ ScalarFunction3["REPLACE"] = "REPLACE";
196
+ ScalarFunction3["SUBSTRING"] = "SUBSTRING";
197
+ ScalarFunction3["COALESCE"] = "COALESCE";
198
+ return ScalarFunction3;
150
199
  })(ScalarFunction || {});
151
200
  var DatePart = /* @__PURE__ */ ((DatePart2) => {
152
201
  DatePart2["YEAR"] = "YEAR";
@@ -160,71 +209,103 @@ var DatePart = /* @__PURE__ */ ((DatePart2) => {
160
209
  DatePart2["DOW"] = "DOW";
161
210
  return DatePart2;
162
211
  })(DatePart || {});
163
- var SortDirection = /* @__PURE__ */ ((SortDirection2) => {
164
- SortDirection2["ASC"] = "ASC";
165
- SortDirection2["DESC"] = "DESC";
166
- return SortDirection2;
212
+ var SortDirection = /* @__PURE__ */ ((SortDirection3) => {
213
+ SortDirection3["ASC"] = "ASC";
214
+ SortDirection3["DESC"] = "DESC";
215
+ return SortDirection3;
167
216
  })(SortDirection || {});
168
217
  var RelationalOperationElement = class {
169
218
  };
170
219
  var Operation = class extends RelationalOperationElement {
171
- andOp(other) {
220
+ /** Name this column in the result: `f.price().sum().alias('Total')`, `f.age().gt(30).alias('Adult')`. */
221
+ alias(name) {
222
+ return new Alias(this, name);
223
+ }
224
+ and(other) {
172
225
  return new LogicalOperation(this, "AND" /* AND */, other);
173
226
  }
227
+ /** Combine with `other` using OR. A chain reads left to right: `a.or(b).and(c)` is `(a OR b) AND c`. */
228
+ or(other) {
229
+ return new LogicalOperation(this, "OR" /* OR */, other);
230
+ }
174
231
  };
175
232
  var NoOperation = class extends Operation {
176
- andOp(other) {
233
+ and(other) {
177
234
  return other;
178
235
  }
236
+ /** No filter matches every row, so OR-ing anything with it still matches every row. */
237
+ or(_other) {
238
+ return this;
239
+ }
179
240
  };
180
241
  var ConstantOperation = class extends RelationalOperationElement {
242
+ /** Name this column in the result. */
243
+ alias(name) {
244
+ return new Alias(this, name);
245
+ }
246
+ /** Sort by this expression, smallest first. */
247
+ ascending() {
248
+ return new SortOperation(this, "ASC" /* ASC */);
249
+ }
250
+ /** Sort by this expression, largest first. */
251
+ descending() {
252
+ return new SortOperation(this, "DESC" /* DESC */);
253
+ }
181
254
  };
182
- var IntegerConstantOperation = class extends ConstantOperation {
183
- constructor(value) {
255
+ var NumericConstantOperation = class extends ConstantOperation {
256
+ arithmeticOperand() {
257
+ return this;
258
+ }
259
+ };
260
+ var IntegerConstantOperation = class extends NumericConstantOperation {
261
+ constructor(value2) {
184
262
  super();
185
- this.value = value;
263
+ this.value = value2;
186
264
  }
187
265
  value;
188
266
  };
189
- var FloatConstantOperation = class extends ConstantOperation {
190
- constructor(value) {
267
+ var FloatConstantOperation = class extends NumericConstantOperation {
268
+ constructor(value2) {
191
269
  super();
192
- this.value = value;
270
+ this.value = value2;
193
271
  }
194
272
  value;
195
273
  };
196
274
  var StringConstantOperation = class extends ConstantOperation {
197
- constructor(value) {
275
+ constructor(value2) {
198
276
  super();
199
- this.value = value;
277
+ this.value = value2;
200
278
  }
201
279
  value;
202
280
  };
281
+ var DATE_ONLY_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
282
+ var DateOnly = class extends Date {
283
+ };
203
284
  var DateConstantOperation = class extends ConstantOperation {
204
- constructor(value) {
285
+ constructor(value2) {
205
286
  super();
206
- this.value = value;
287
+ this.value = value2;
207
288
  }
208
289
  value;
209
290
  };
210
291
  var DateTimeConstantOperation = class extends ConstantOperation {
211
- constructor(value) {
292
+ constructor(value2) {
212
293
  super();
213
- this.value = value;
294
+ this.value = value2;
214
295
  }
215
296
  value;
216
297
  };
217
- var DecimalConstantOperation = class extends ConstantOperation {
218
- constructor(value) {
298
+ var DecimalConstantOperation = class extends NumericConstantOperation {
299
+ constructor(value2) {
219
300
  super();
220
- this.value = value;
301
+ this.value = value2;
221
302
  }
222
303
  value;
223
304
  };
224
305
  var BooleanConstantOperation = class extends ConstantOperation {
225
- constructor(value) {
306
+ constructor(value2) {
226
307
  super();
227
- this.value = value;
308
+ this.value = value2;
228
309
  }
229
310
  value;
230
311
  };
@@ -248,6 +329,20 @@ var IsNullOperation = class extends UnaryOperation {
248
329
  };
249
330
  var IsNotNullOperation = class extends UnaryOperation {
250
331
  };
332
+ var InOperation = class extends UnaryOperation {
333
+ constructor(element, values) {
334
+ super(element);
335
+ this.values = values;
336
+ }
337
+ values;
338
+ };
339
+ var NotInOperation = class extends UnaryOperation {
340
+ constructor(element, values) {
341
+ super(element);
342
+ this.values = values;
343
+ }
344
+ values;
345
+ };
251
346
  var ComparisonOperation = class extends BinaryOperation {
252
347
  constructor(left, operator, right) {
253
348
  super(left, right);
@@ -271,21 +366,41 @@ var WindowSpecification = class {
271
366
  orderBy;
272
367
  };
273
368
  var AggregateOperation = class _AggregateOperation extends UnaryOperation {
274
- constructor(element, operator, displayName, window) {
369
+ constructor(element, operator, displayName, window, separator, orderBy = []) {
275
370
  super(element);
276
371
  this.operator = operator;
277
372
  this.displayName = displayName;
278
373
  this.window = window;
374
+ this.separator = separator;
375
+ this.orderBy = orderBy;
279
376
  }
280
377
  operator;
281
378
  displayName;
282
379
  window;
380
+ separator;
381
+ orderBy;
382
+ /** Sort by this expression, smallest first. */
383
+ ascending() {
384
+ return new SortOperation(this, "ASC" /* ASC */);
385
+ }
386
+ /** Sort by this expression, largest first. */
387
+ descending() {
388
+ return new SortOperation(this, "DESC" /* DESC */);
389
+ }
390
+ arithmeticOperand() {
391
+ return this;
392
+ }
393
+ comparisonOperand() {
394
+ return this;
395
+ }
283
396
  over(partitionBy, orderBy) {
284
397
  return new _AggregateOperation(
285
398
  this.element,
286
399
  this.operator,
287
400
  this.displayName,
288
- new WindowSpecification(partitionBy ?? [], orderBy ?? [])
401
+ new WindowSpecification(partitionBy ?? [], orderBy ?? []),
402
+ this.separator,
403
+ this.orderBy
289
404
  );
290
405
  }
291
406
  };
@@ -316,6 +431,14 @@ var WindowFunctionOperation = class _WindowFunctionOperation extends UnaryOperat
316
431
  secondArg;
317
432
  extraArgs;
318
433
  window;
434
+ /** Sort by this expression, smallest first. */
435
+ ascending() {
436
+ return new SortOperation(this, "ASC" /* ASC */);
437
+ }
438
+ /** Sort by this expression, largest first. */
439
+ descending() {
440
+ return new SortOperation(this, "DESC" /* DESC */);
441
+ }
319
442
  over(partitionBy, orderBy) {
320
443
  return new _WindowFunctionOperation(
321
444
  this.element,
@@ -339,7 +462,38 @@ var ScalarFunctionOperation = class extends UnaryOperation {
339
462
  displayName;
340
463
  secondArg;
341
464
  extraArgs;
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
+ /** This expression as an operand of a comparison. */
474
+ comparisonOperand() {
475
+ return this;
476
+ }
477
+ arithmeticOperand() {
478
+ return this;
479
+ }
480
+ /** Only a function that gives a number can be used in arithmetic. */
481
+ assertNumeric() {
482
+ if (!NUMERIC_FUNCTIONS.has(this.func)) {
483
+ throw new TypeError(`${this.func} does not give a number, so it cannot be used in arithmetic`);
484
+ }
485
+ }
342
486
  };
487
+ var NUMERIC_FUNCTIONS = /* @__PURE__ */ new Set([
488
+ "ABS" /* ABS */,
489
+ "CEILING" /* CEILING */,
490
+ "FLOOR" /* FLOOR */,
491
+ "MOD" /* MOD */,
492
+ "POWER" /* POWER */,
493
+ "SQRT" /* SQRT */,
494
+ "ROUND" /* ROUND */,
495
+ "LENGTH" /* LENGTH */
496
+ ]);
343
497
  var DateExtractOperation = class extends UnaryOperation {
344
498
  constructor(element, part, displayName) {
345
499
  super(element);
@@ -348,6 +502,34 @@ var DateExtractOperation = class extends UnaryOperation {
348
502
  }
349
503
  part;
350
504
  displayName;
505
+ /** Sort by this expression, smallest first. */
506
+ ascending() {
507
+ return new SortOperation(this, "ASC" /* ASC */);
508
+ }
509
+ /** Sort by this expression, largest first. */
510
+ descending() {
511
+ return new SortOperation(this, "DESC" /* DESC */);
512
+ }
513
+ };
514
+ var DateTruncOperation = class extends UnaryOperation {
515
+ constructor(element, part, displayName) {
516
+ super(element);
517
+ this.part = part;
518
+ this.displayName = displayName;
519
+ }
520
+ part;
521
+ displayName;
522
+ /** Sort by this expression, earliest first. */
523
+ ascending() {
524
+ return new SortOperation(this, "ASC" /* ASC */);
525
+ }
526
+ /** Sort by this expression, latest first. */
527
+ descending() {
528
+ return new SortOperation(this, "DESC" /* DESC */);
529
+ }
530
+ comparisonOperand() {
531
+ return this;
532
+ }
351
533
  };
352
534
  var DateArithmeticOperation = class extends UnaryOperation {
353
535
  constructor(element, n, unit, isAdd = true, displayName) {
@@ -361,6 +543,14 @@ var DateArithmeticOperation = class extends UnaryOperation {
361
543
  unit;
362
544
  isAdd;
363
545
  displayName;
546
+ /** Sort by this expression, smallest first. */
547
+ ascending() {
548
+ return new SortOperation(this, "ASC" /* ASC */);
549
+ }
550
+ /** Sort by this expression, largest first. */
551
+ descending() {
552
+ return new SortOperation(this, "DESC" /* DESC */);
553
+ }
364
554
  };
365
555
  var DateDiffOperation = class extends UnaryOperation {
366
556
  constructor(element, other, unit, displayName) {
@@ -372,20 +562,31 @@ var DateDiffOperation = class extends UnaryOperation {
372
562
  other;
373
563
  unit;
374
564
  displayName;
565
+ /** Sort by this expression, smallest first. */
566
+ ascending() {
567
+ return new SortOperation(this, "ASC" /* ASC */);
568
+ }
569
+ /** Sort by this expression, largest first. */
570
+ descending() {
571
+ return new SortOperation(this, "DESC" /* DESC */);
572
+ }
375
573
  };
376
574
  var Column = class extends RelationalOperationElement {
377
- constructor(name, type, owner, primaryKey = false) {
575
+ constructor(name, type, owner, primaryKey = false, nullable = true) {
378
576
  super();
379
577
  this.name = name;
380
578
  this.type = type;
381
579
  this.owner = owner;
382
580
  this.primaryKey = primaryKey;
581
+ this.nullable = nullable && !primaryKey;
383
582
  }
384
583
  name;
385
584
  type;
386
585
  owner;
387
586
  primaryKey;
388
587
  table;
588
+ /** Whether the column may hold NULL. As in Legend, a primary key is never null. */
589
+ nullable;
389
590
  };
390
591
  var ForeignKey = class {
391
592
  constructor(column, references) {
@@ -475,27 +676,40 @@ var JoinOperation = class {
475
676
  filterColumnMap = {};
476
677
  };
477
678
  var JoinTreeNodeOperation = class {
478
- constructor(join, parent) {
679
+ constructor(join, parent, many = false, optional = false) {
479
680
  this.join = join;
480
681
  this.parent = parent;
682
+ this.many = many;
683
+ this.optional = optional;
481
684
  }
482
685
  join;
483
686
  parent;
687
+ many;
688
+ optional;
484
689
  };
485
690
  var ColumnWithJoin = class extends RelationalOperationElement {
486
691
  /**
487
692
  * `embedded` is an alternate reference to a flat (denormalized) column on the owning table that
488
693
  * holds the same value without the join; the SQL generator uses it when the join can be elided.
489
694
  */
490
- constructor(column, parent, embedded) {
695
+ constructor(column, parent, embedded, _optional = false) {
491
696
  super();
492
697
  this.column = column;
493
698
  this.parent = parent;
494
699
  this.embedded = embedded;
700
+ this._optional = _optional;
495
701
  }
496
702
  column;
497
703
  parent;
498
704
  embedded;
705
+ _optional;
706
+ /** Whether the value can be missing: its property is optional, or a navigation on the way to it is. */
707
+ get optional() {
708
+ for (let node = this.parent; node !== void 0; node = node.parent) {
709
+ if (node.optional) return true;
710
+ }
711
+ return this._optional;
712
+ }
499
713
  };
500
714
  var SortOperation = class {
501
715
  constructor(column, direction) {
@@ -511,8 +725,23 @@ var CountAllOperation = class extends RelationalOperationElement {
511
725
  this.table = table;
512
726
  }
513
727
  table;
728
+ /** Name this column in the result. */
729
+ alias(name) {
730
+ return new Alias(this, name);
731
+ }
732
+ /** Sort by this expression, smallest first. */
733
+ ascending() {
734
+ return new SortOperation(this, "ASC" /* ASC */);
735
+ }
736
+ /** Sort by this expression, largest first. */
737
+ descending() {
738
+ return new SortOperation(this, "DESC" /* DESC */);
739
+ }
740
+ comparisonOperand() {
741
+ return this;
742
+ }
514
743
  };
515
- var Alias = class extends RelationalOperationElement {
744
+ var Alias = class _Alias extends RelationalOperationElement {
516
745
  constructor(element, name) {
517
746
  super();
518
747
  this.element = element;
@@ -520,6 +749,30 @@ var Alias = class extends RelationalOperationElement {
520
749
  }
521
750
  element;
522
751
  name;
752
+ alias(name) {
753
+ return new _Alias(this.element, name);
754
+ }
755
+ /** Sorts by the column the alias names. */
756
+ ascending() {
757
+ return new SortOperation(this.element, "ASC" /* ASC */);
758
+ }
759
+ /** Sorts by the column the alias names. */
760
+ descending() {
761
+ return new SortOperation(this.element, "DESC" /* DESC */);
762
+ }
763
+ };
764
+ var CaseOperation = class extends Operation {
765
+ constructor(condition, then, fallback, displayName) {
766
+ super();
767
+ this.condition = condition;
768
+ this.then = then;
769
+ this.fallback = fallback;
770
+ this.displayName = displayName;
771
+ }
772
+ condition;
773
+ then;
774
+ fallback;
775
+ displayName;
523
776
  };
524
777
  var ExistsOperation = class extends RelationalOperationElement {
525
778
  constructor(node) {
@@ -527,9 +780,16 @@ var ExistsOperation = class extends RelationalOperationElement {
527
780
  this.node = node;
528
781
  }
529
782
  node;
530
- andOp(other) {
783
+ /** Name this column in the result. */
784
+ alias(name) {
785
+ return new Alias(this, name);
786
+ }
787
+ and(other) {
531
788
  return new LogicalOperation(this, "AND" /* AND */, other);
532
789
  }
790
+ or(other) {
791
+ return new LogicalOperation(this, "OR" /* OR */, other);
792
+ }
533
793
  };
534
794
  var NotExistsOperation = class extends RelationalOperationElement {
535
795
  constructor(node) {
@@ -537,12 +797,19 @@ var NotExistsOperation = class extends RelationalOperationElement {
537
797
  this.node = node;
538
798
  }
539
799
  node;
540
- andOp(other) {
800
+ /** Name this column in the result. */
801
+ alias(name) {
802
+ return new Alias(this, name);
803
+ }
804
+ and(other) {
541
805
  return new LogicalOperation(this, "AND" /* AND */, other);
542
806
  }
807
+ or(other) {
808
+ return new LogicalOperation(this, "OR" /* OR */, other);
809
+ }
543
810
  };
544
811
  var SelectOperation = class {
545
- constructor(display, filter, orderBy = [], groupBy = [], limit, table, joinFilters = /* @__PURE__ */ new Map()) {
812
+ constructor(display, filter, orderBy = [], groupBy = [], limit, table, joinFilters = /* @__PURE__ */ new Map(), distinct = false, offset, having) {
546
813
  this.display = display;
547
814
  this.filter = filter;
548
815
  this.orderBy = orderBy;
@@ -550,6 +817,9 @@ var SelectOperation = class {
550
817
  this.limit = limit;
551
818
  this.table = table;
552
819
  this.joinFilters = joinFilters;
820
+ this.distinct = distinct;
821
+ this.offset = offset;
822
+ this.having = having;
553
823
  }
554
824
  display;
555
825
  filter;
@@ -558,7 +828,254 @@ var SelectOperation = class {
558
828
  limit;
559
829
  table;
560
830
  joinFilters;
831
+ distinct;
832
+ offset;
833
+ having;
834
+ };
835
+ function containsAggregateOrWindow(op) {
836
+ if (op instanceof AggregateOperation || op instanceof WindowFunctionOperation || op instanceof CountAllOperation) return true;
837
+ if (op instanceof BinaryOperation) return containsAggregateOrWindow(op.left) || containsAggregateOrWindow(op.right);
838
+ if (op instanceof UnaryOperation || op instanceof Alias) return containsAggregateOrWindow(op.element);
839
+ return false;
840
+ }
841
+ function containsAggregate(op) {
842
+ if (op instanceof AggregateOperation || op instanceof CountAllOperation) return true;
843
+ if (op instanceof BinaryOperation) return containsAggregate(op.left) || containsAggregate(op.right);
844
+ if (op instanceof UnaryOperation || op instanceof Alias) return containsAggregate(op.element);
845
+ return false;
846
+ }
847
+ function valueOperand(value2) {
848
+ if (typeof value2 === "boolean") return new BooleanConstantOperation(value2);
849
+ if (typeof value2 === "number" && Number.isFinite(value2)) {
850
+ return Number.isInteger(value2) ? new IntegerConstantOperation(value2) : new FloatConstantOperation(value2);
851
+ }
852
+ if (typeof value2 === "string") return new StringConstantOperation(value2);
853
+ if (value2 instanceof DateOnly) return new DateConstantOperation(value2);
854
+ if (value2 instanceof Date) return new DateTimeConstantOperation(value2);
855
+ throw new TypeError(`A value to compare with is a boolean, a finite number, a string or a date, not ${value2 === null ? "null" : typeof value2}`);
856
+ }
857
+ function operandOf(other) {
858
+ if (other instanceof RelationalOperationElement) return other;
859
+ if (typeof other?.cwj === "function") return other.cwj();
860
+ return valueOperand(other);
861
+ }
862
+ var Comparable = class {
863
+ _compared(operator, other) {
864
+ return new ComparisonOperation(this.comparisonOperand(), operator, operandOf(other));
865
+ }
866
+ /** Filter to rows where this expression equals `other`. */
867
+ eq(other) {
868
+ return this._compared("EQUAL" /* EQUAL */, other);
869
+ }
870
+ /** Filter to rows where this expression does not equal `other`. */
871
+ ne(other) {
872
+ return this._compared("NOT_EQUAL" /* NOT_EQUAL */, other);
873
+ }
874
+ /** Filter to rows where this expression is less than `other`. */
875
+ lt(other) {
876
+ return this._compared("LESS_THAN" /* LESS_THAN */, other);
877
+ }
878
+ /** Filter to rows where this expression is at most `other`. */
879
+ lte(other) {
880
+ return this._compared("LESS_THAN_OR_EQUAL_TO" /* LESS_THAN_OR_EQUAL_TO */, other);
881
+ }
882
+ /** Filter to rows where this expression is greater than `other`. */
883
+ gt(other) {
884
+ return this._compared("GREATER_THAN" /* GREATER_THAN */, other);
885
+ }
886
+ /** Filter to rows where this expression is at least `other`. */
887
+ gte(other) {
888
+ return this._compared("GREATER_THAN_OR_EQUAL_TO" /* GREATER_THAN_OR_EQUAL_TO */, other);
889
+ }
890
+ };
891
+ function sample(ddof) {
892
+ if (ddof !== 0 && ddof !== 1) throw new RangeError(`ddof is 0 (population) or 1 (sample), not ${ddof}`);
893
+ return ddof === 1;
894
+ }
895
+ var StringPredicates = class {
896
+ _like(pattern) {
897
+ return new ComparisonOperation(this.comparisonOperand(), "LIKE" /* LIKE */, new StringConstantOperation(pattern));
898
+ }
899
+ /** Filter to rows where this text contains `value`. */
900
+ contains(value2) {
901
+ return this._like(`%${escapeLike(value2)}%`);
902
+ }
903
+ /** Filter to rows where this text starts with `prefix`. */
904
+ startsWith(prefix) {
905
+ return this._like(`${escapeLike(prefix)}%`);
906
+ }
907
+ /** Filter to rows where this text ends with `suffix`. */
908
+ endsWith(suffix) {
909
+ return this._like(`%${escapeLike(suffix)}`);
910
+ }
911
+ };
912
+ var Aggregates = class {
913
+ _aggregate(operator, label) {
914
+ return new AggregateOperation(this, operator, label + " Expression");
915
+ }
916
+ /** Sum of the values in the group. */
917
+ sum() {
918
+ return this._aggregate("SUM" /* SUM */, "Sum");
919
+ }
920
+ /** Smallest value in the group. */
921
+ min() {
922
+ return this._aggregate("MIN" /* MIN */, "Min");
923
+ }
924
+ /** Largest value in the group. */
925
+ max() {
926
+ return this._aggregate("MAX" /* MAX */, "Max");
927
+ }
928
+ /** Arithmetic mean of the values in the group. */
929
+ average() {
930
+ return this._aggregate("AVERAGE" /* AVERAGE */, "Average");
931
+ }
932
+ /** Number of non-null values in the group. */
933
+ count() {
934
+ return this._aggregate("COUNT" /* COUNT */, "Count");
935
+ }
936
+ /** Standard deviation of the values in the group: the sample one by default, `ddof = 0` for the population one. */
937
+ std(ddof = 1) {
938
+ return this._aggregate(sample(ddof) ? "STDDEV_SAMP" /* STDDEV_SAMP */ : "STDDEV_POP" /* STDDEV_POP */, "Std");
939
+ }
940
+ /** Variance of the values in the group: the sample one by default, `ddof = 0` for the population one. */
941
+ var(ddof = 1) {
942
+ return this._aggregate(sample(ddof) ? "VAR_SAMP" /* VAR_SAMP */ : "VAR_POP" /* VAR_POP */, "Var");
943
+ }
944
+ };
945
+ var BooleanAggregates = class {
946
+ /** True for a group where every row satisfies the condition. */
947
+ all() {
948
+ return new AggregateOperation(this, "BOOL_AND" /* BOOL_AND */, "All Expression");
949
+ }
950
+ /** True for a group where at least one row satisfies the condition. */
951
+ any() {
952
+ return new AggregateOperation(this, "BOOL_OR" /* BOOL_OR */, "Any Expression");
953
+ }
954
+ };
955
+ function applyMixins(derived, bases) {
956
+ for (const base of bases) {
957
+ for (const name of Object.getOwnPropertyNames(base.prototype)) {
958
+ if (name === "constructor" || Object.prototype.hasOwnProperty.call(derived.prototype, name)) continue;
959
+ Object.defineProperty(derived.prototype, name, Object.getOwnPropertyDescriptor(base.prototype, name));
960
+ }
961
+ }
962
+ }
963
+ var ArithmeticOperator = /* @__PURE__ */ ((ArithmeticOperator2) => {
964
+ ArithmeticOperator2["ADD"] = "+";
965
+ ArithmeticOperator2["SUBTRACT"] = "-";
966
+ ArithmeticOperator2["MULTIPLY"] = "*";
967
+ ArithmeticOperator2["DIVIDE"] = "/";
968
+ return ArithmeticOperator2;
969
+ })(ArithmeticOperator || {});
970
+ var Arithmetic = class {
971
+ /** Raises if this expression is not a number. */
972
+ assertNumeric() {
973
+ }
974
+ _arithmetic(operator, other) {
975
+ this.assertNumeric();
976
+ let operand;
977
+ if (typeof other === "number") {
978
+ if (!Number.isFinite(other)) throw new TypeError("Arithmetic is between numbers and numeric columns, not a non-finite number");
979
+ operand = valueOperand(other);
980
+ } else if (other !== null && typeof other === "object" && typeof other.arithmeticOperand === "function") {
981
+ other.assertNumeric?.();
982
+ operand = other.arithmeticOperand();
983
+ } else {
984
+ throw new TypeError(`Arithmetic is between numbers and numeric columns, not ${other === null ? "null" : typeof other}`);
985
+ }
986
+ return new ArithmeticOperation(this.arithmeticOperand(), operator, operand);
987
+ }
988
+ /** `this + other`. */
989
+ plus(other) {
990
+ return this._arithmetic("+" /* ADD */, other);
991
+ }
992
+ /** `this - other`. */
993
+ minus(other) {
994
+ return this._arithmetic("-" /* SUBTRACT */, other);
995
+ }
996
+ /** `this * other`. */
997
+ times(other) {
998
+ return this._arithmetic("*" /* MULTIPLY */, other);
999
+ }
1000
+ /** `this / other`. */
1001
+ dividedBy(other) {
1002
+ return this._arithmetic("/" /* DIVIDE */, other);
1003
+ }
561
1004
  };
1005
+ var ArithmeticOperation = class extends BinaryOperation {
1006
+ constructor(left, operator, right, displayName) {
1007
+ super(left, right);
1008
+ this.operator = operator;
1009
+ this.displayName = displayName;
1010
+ }
1011
+ operator;
1012
+ displayName;
1013
+ /** Sort by this expression, smallest first. */
1014
+ ascending() {
1015
+ return new SortOperation(this, "ASC" /* ASC */);
1016
+ }
1017
+ /** Sort by this expression, largest first. */
1018
+ descending() {
1019
+ return new SortOperation(this, "DESC" /* DESC */);
1020
+ }
1021
+ arithmeticOperand() {
1022
+ return this;
1023
+ }
1024
+ comparisonOperand() {
1025
+ return this;
1026
+ }
1027
+ };
1028
+ var ConcatOperation = class extends Operation {
1029
+ constructor(parts, displayName) {
1030
+ super();
1031
+ this.parts = parts;
1032
+ this.displayName = displayName;
1033
+ }
1034
+ parts;
1035
+ displayName;
1036
+ /** Join more text on the end: `f.first().concat(' ', f.last())`. A concatenation joins into one. */
1037
+ concat(...more) {
1038
+ return concat(this, ...more);
1039
+ }
1040
+ /** Sort by this expression, smallest first. */
1041
+ ascending() {
1042
+ return new SortOperation(this, "ASC" /* ASC */);
1043
+ }
1044
+ /** Sort by this expression, largest first. */
1045
+ descending() {
1046
+ return new SortOperation(this, "DESC" /* DESC */);
1047
+ }
1048
+ comparisonOperand() {
1049
+ return this;
1050
+ }
1051
+ };
1052
+ function concat(...parts) {
1053
+ const partsOf = (part) => {
1054
+ if (part instanceof ConcatOperation) return part.parts;
1055
+ if (typeof part === "string") return [new StringConstantOperation(part)];
1056
+ if (part instanceof RelationalOperationElement) return [part];
1057
+ if (part !== null && typeof part === "object" && typeof part.functionInput === "function") return [part.functionInput()];
1058
+ throw new TypeError(`Text is joined with text, not ${part === null ? "null" : typeof part}`);
1059
+ };
1060
+ return new ConcatOperation(parts.flatMap(partsOf));
1061
+ }
1062
+ applyMixins(ConcatOperation, [Comparable, StringPredicates]);
1063
+ applyMixins(DateTruncOperation, [Comparable]);
1064
+ applyMixins(ArithmeticOperation, [Arithmetic, Comparable]);
1065
+ applyMixins(ScalarFunctionOperation, [Comparable, Arithmetic, StringPredicates]);
1066
+ applyMixins(AggregateOperation, [Arithmetic, Comparable, StringPredicates]);
1067
+ applyMixins(CountAllOperation, [Comparable]);
1068
+ applyMixins(NumericConstantOperation, [Arithmetic]);
1069
+ applyMixins(ConstantOperation, [Aggregates]);
1070
+ applyMixins(ArithmeticOperation, [Aggregates]);
1071
+ applyMixins(ScalarFunctionOperation, [Aggregates]);
1072
+ applyMixins(CaseOperation, [Aggregates]);
1073
+ applyMixins(IsNullOperation, [BooleanAggregates]);
1074
+ applyMixins(IsNotNullOperation, [BooleanAggregates]);
1075
+ applyMixins(InOperation, [BooleanAggregates]);
1076
+ applyMixins(NotInOperation, [BooleanAggregates]);
1077
+ applyMixins(ComparisonOperation, [BooleanAggregates]);
1078
+ applyMixins(LogicalOperation, [BooleanAggregates]);
562
1079
 
563
1080
  // src/datafinder/attribute.ts
564
1081
  var Attribute = class _Attribute {
@@ -567,9 +1084,11 @@ var Attribute = class _Attribute {
567
1084
  _owner;
568
1085
  _parent;
569
1086
  _embedded;
570
- constructor(displayName, columnName, columnDbType, owner, parent, embedded) {
1087
+ _optional;
1088
+ constructor(displayName, columnName, columnDbType, owner, parent, embedded, nullable = true, optional = false) {
1089
+ this._optional = optional;
571
1090
  this._displayName = displayName;
572
- this._column = new Column(columnName, columnDbType, owner);
1091
+ this._column = new Column(columnName, columnDbType, owner, false, nullable);
573
1092
  this._owner = owner;
574
1093
  this._parent = parent;
575
1094
  this._embedded = embedded;
@@ -590,10 +1109,22 @@ var Attribute = class _Attribute {
590
1109
  embedded() {
591
1110
  return this._embedded;
592
1111
  }
1112
+ /** @internal The expression a function of this attribute applies to: its column. */
1113
+ functionInput() {
1114
+ return this.cwj();
1115
+ }
1116
+ /** @internal What a function of this attribute is labelled after: its display name. */
1117
+ functionLabel() {
1118
+ return this._displayName;
1119
+ }
1120
+ /** @internal This attribute as an operand of arithmetic: its column. */
1121
+ arithmeticOperand() {
1122
+ return this.cwj();
1123
+ }
593
1124
  cwj() {
594
- return new ColumnWithJoin(this._column, this._parent, this._embedded?.cwj());
1125
+ return new ColumnWithJoin(this._column, this._parent, this._embedded?.cwj(), this._optional);
595
1126
  }
596
- /** Count the number of non-null values. Use in a projection with `groupByOp` to aggregate per group. */
1127
+ /** Count the number of non-null values. Use in a projection with `groupBy` to aggregate per group. */
597
1128
  count() {
598
1129
  return new AggregateOperation(
599
1130
  this.cwj(),
@@ -601,11 +1132,26 @@ var Attribute = class _Attribute {
601
1132
  this._displayName + " Count"
602
1133
  );
603
1134
  }
604
- /** Sort this attribute in ascending order. Pass to `orderByOp` or a window function's `orderBy`. */
1135
+ /** Name this column in the result: `f.price().sum().alias('Total')`. */
1136
+ alias(name) {
1137
+ return new Alias(this, name);
1138
+ }
1139
+ /** The number of different non-NULL values in the group: `COUNT(DISTINCT column)`. Use with `groupBy` to count per group. */
1140
+ countDistinct() {
1141
+ return new AggregateOperation(this.cwj(), "COUNT_DISTINCT" /* COUNT_DISTINCT */, this._displayName + " Count Distinct");
1142
+ }
1143
+ /** The value, or `defaultValue` when it is NULL: `name().orElse('N/A')`. Like `COALESCE` in SQL. */
1144
+ orElse(defaultValue) {
1145
+ if (!["string", "number", "boolean"].includes(typeof defaultValue)) {
1146
+ throw new TypeError(`An orElse default is a string, number or boolean, not ${defaultValue === null ? "null" : typeof defaultValue}`);
1147
+ }
1148
+ return new ScalarFunctionOperation(this.cwj(), "COALESCE" /* COALESCE */, "Or Else " + this._displayName, void 0, [defaultValue]);
1149
+ }
1150
+ /** Sort this attribute in ascending order. Pass to `orderBy` or a window function's `orderBy`. */
605
1151
  ascending() {
606
1152
  return new SortOperation(this.cwj(), "ASC" /* ASC */);
607
1153
  }
608
- /** Sort this attribute in descending order. Pass to `orderByOp` or a window function's `orderBy`. */
1154
+ /** Sort this attribute in descending order. Pass to `orderBy` or a window function's `orderBy`. */
609
1155
  descending() {
610
1156
  return new SortOperation(this.cwj(), "DESC" /* DESC */);
611
1157
  }
@@ -617,6 +1163,23 @@ var Attribute = class _Attribute {
617
1163
  isNotNull() {
618
1164
  return new IsNotNullOperation(this.cwj());
619
1165
  }
1166
+ /** Wrap a value as a constant of this attribute's type. Overridden by the typed attributes. */
1167
+ toConstant(_value) {
1168
+ throw new TypeError(`${this.constructor.name} does not support isIn / isNotIn`);
1169
+ }
1170
+ _constants(values) {
1171
+ const constants = values.map((v) => this.toConstant(v));
1172
+ if (constants.length === 0) throw new Error("isIn / isNotIn need at least one value");
1173
+ return constants;
1174
+ }
1175
+ /** Filter to rows where this attribute equals any of `values`. */
1176
+ isIn(values) {
1177
+ return new InOperation(this.cwj(), this._constants(values));
1178
+ }
1179
+ /** Filter to rows where this attribute equals none of `values`. Rows with no value are excluded, as in SQL. */
1180
+ isNotIn(values) {
1181
+ return new NotInOperation(this.cwj(), this._constants(values));
1182
+ }
620
1183
  _windowSpec(partitionBy, orderBy) {
621
1184
  const pbArr = partitionBy === void 0 ? [] : Array.isArray(partitionBy) ? partitionBy : [partitionBy];
622
1185
  const pb = pbArr.map((x) => x instanceof _Attribute ? x.cwj() : x);
@@ -734,54 +1297,80 @@ function getRelatedFinderClass(name) {
734
1297
  return _registry.get(name);
735
1298
  }
736
1299
 
737
- // src/datafinder/typed-attributes.ts
738
- var StringAttribute = class extends Attribute {
739
- constructor(displayName, columnName, columnDbType, owner, parent, embedded) {
740
- super(displayName, columnName, columnDbType, owner, parent, embedded);
1300
+ // src/datafinder/scalar-functions.ts
1301
+ var StringFunctionOperation = class extends ScalarFunctionOperation {
1302
+ functionInput() {
1303
+ return this;
1304
+ }
1305
+ functionLabel() {
1306
+ return labelOf(this);
1307
+ }
1308
+ };
1309
+ var NumericFunctionOperation = class extends ScalarFunctionOperation {
1310
+ functionInput() {
1311
+ return this;
1312
+ }
1313
+ functionLabel() {
1314
+ return labelOf(this);
1315
+ }
1316
+ };
1317
+ function labelOf(operation) {
1318
+ return operation.displayName ?? operation.func.charAt(0) + operation.func.slice(1).toLowerCase();
1319
+ }
1320
+ function stringFunction(element, func, label, secondArg, extraArgs = []) {
1321
+ return new StringFunctionOperation(element, func, label, secondArg, extraArgs);
1322
+ }
1323
+ function numberFunction(element, func, label, secondArg) {
1324
+ return new NumericFunctionOperation(element, func, label, secondArg);
1325
+ }
1326
+ var StringFunctions = class {
1327
+ /** Join text on the end: `f.first().concat(' ', f.last())`. A NULL part makes the whole NULL. */
1328
+ concat(...more) {
1329
+ return concat(this, ...more);
741
1330
  }
742
1331
  /** Convert every character to uppercase. */
743
1332
  toUpperCase() {
744
- return new ScalarFunctionOperation(this.cwj(), "UPPER" /* UPPER */, "Upper " + this.displayName());
1333
+ return stringFunction(this.functionInput(), "UPPER" /* UPPER */, "Upper " + this.functionLabel());
745
1334
  }
746
1335
  /** Convert every character to lowercase. */
747
1336
  toLowerCase() {
748
- return new ScalarFunctionOperation(this.cwj(), "LOWER" /* LOWER */, "Lower " + this.displayName());
1337
+ return stringFunction(this.functionInput(), "LOWER" /* LOWER */, "Lower " + this.functionLabel());
749
1338
  }
750
1339
  /** Remove leading and trailing whitespace. */
751
1340
  trim() {
752
- return new ScalarFunctionOperation(this.cwj(), "TRIM" /* TRIM */, "Trim " + this.displayName());
1341
+ return stringFunction(this.functionInput(), "TRIM" /* TRIM */, "Trim " + this.functionLabel());
753
1342
  }
754
1343
  /** Remove leading whitespace. */
755
1344
  trimStart() {
756
- return new ScalarFunctionOperation(this.cwj(), "LTRIM" /* LTRIM */, "Trim Start " + this.displayName());
1345
+ return stringFunction(this.functionInput(), "LTRIM" /* LTRIM */, "Trim Start " + this.functionLabel());
757
1346
  }
758
1347
  /** Remove trailing whitespace. */
759
1348
  trimEnd() {
760
- return new ScalarFunctionOperation(this.cwj(), "RTRIM" /* RTRIM */, "Trim End " + this.displayName());
1349
+ return stringFunction(this.functionInput(), "RTRIM" /* RTRIM */, "Trim End " + this.functionLabel());
761
1350
  }
762
1351
  /** Return the number of characters in the string. */
763
1352
  length() {
764
- return new ScalarFunctionOperation(this.cwj(), "LENGTH" /* LENGTH */, "Length " + this.displayName());
1353
+ return numberFunction(this.functionInput(), "LENGTH" /* LENGTH */, "Length " + this.functionLabel());
765
1354
  }
766
1355
  /** Return the string with characters in reverse order. */
767
1356
  reverse() {
768
- return new ScalarFunctionOperation(this.cwj(), "REVERSE" /* REVERSE */, "Reverse " + this.displayName());
1357
+ return stringFunction(this.functionInput(), "REVERSE" /* REVERSE */, "Reverse " + this.functionLabel());
769
1358
  }
770
1359
  /** Return the first `n` characters. */
771
1360
  left(n) {
772
- return new ScalarFunctionOperation(this.cwj(), "LEFT" /* LEFT */, "Left " + this.displayName(), n);
1361
+ return stringFunction(this.functionInput(), "LEFT" /* LEFT */, "Left " + this.functionLabel(), n);
773
1362
  }
774
1363
  /** Return the last `n` characters. */
775
1364
  right(n) {
776
- return new ScalarFunctionOperation(this.cwj(), "RIGHT" /* RIGHT */, "Right " + this.displayName(), n);
1365
+ return stringFunction(this.functionInput(), "RIGHT" /* RIGHT */, "Right " + this.functionLabel(), n);
777
1366
  }
778
1367
  /** Return the string repeated `n` times. */
779
1368
  repeat(n) {
780
- return new ScalarFunctionOperation(this.cwj(), "REPEAT" /* REPEAT */, "Repeat " + this.displayName(), n);
1369
+ return stringFunction(this.functionInput(), "REPEAT" /* REPEAT */, "Repeat " + this.functionLabel(), n);
781
1370
  }
782
1371
  /** Replace all occurrences of `fromStr` with `toStr`. */
783
1372
  replace(fromStr, toStr) {
784
- return new ScalarFunctionOperation(this.cwj(), "REPLACE" /* REPLACE */, "Replace " + this.displayName(), void 0, [fromStr, toStr]);
1373
+ return stringFunction(this.functionInput(), "REPLACE" /* REPLACE */, "Replace " + this.functionLabel(), void 0, [fromStr, toStr]);
785
1374
  }
786
1375
  /**
787
1376
  * Extract a portion of the string.
@@ -789,177 +1378,224 @@ var StringAttribute = class extends Attribute {
789
1378
  */
790
1379
  substring(start, length) {
791
1380
  const args = length !== void 0 ? [start + 1, length] : [start + 1];
792
- return new ScalarFunctionOperation(this.cwj(), "SUBSTRING" /* SUBSTRING */, "Substring " + this.displayName(), void 0, args);
1381
+ return stringFunction(this.functionInput(), "SUBSTRING" /* SUBSTRING */, "Substring " + this.functionLabel(), void 0, args);
1382
+ }
1383
+ };
1384
+ var NumericFunctions = class {
1385
+ /** Absolute value (distance from zero, always non-negative). */
1386
+ abs() {
1387
+ return numberFunction(this.functionInput(), "ABS" /* ABS */, "Abs " + this.functionLabel());
1388
+ }
1389
+ /** Round up to the nearest integer. */
1390
+ ceil() {
1391
+ return numberFunction(this.functionInput(), "CEILING" /* CEILING */, "Ceil " + this.functionLabel());
1392
+ }
1393
+ /** Round down to the nearest integer. */
1394
+ floor() {
1395
+ return numberFunction(this.functionInput(), "FLOOR" /* FLOOR */, "Floor " + this.functionLabel());
1396
+ }
1397
+ /** Square root. */
1398
+ sqrt() {
1399
+ return numberFunction(this.functionInput(), "SQRT" /* SQRT */, "Sqrt " + this.functionLabel());
1400
+ }
1401
+ /** Remainder after dividing by `n`. */
1402
+ mod(n) {
1403
+ return numberFunction(this.functionInput(), "MOD" /* MOD */, "Mod " + this.functionLabel(), n);
1404
+ }
1405
+ /** Raise to the power of `n`. */
1406
+ power(n) {
1407
+ return numberFunction(this.functionInput(), "POWER" /* POWER */, "Power " + this.functionLabel(), n);
1408
+ }
1409
+ /** Round to `d` decimal places, or to the nearest integer when `d` is omitted. */
1410
+ round(d) {
1411
+ return numberFunction(this.functionInput(), "ROUND" /* ROUND */, "Round " + this.functionLabel(), d);
1412
+ }
1413
+ };
1414
+ applyMixins(StringFunctionOperation, [StringFunctions]);
1415
+ applyMixins(NumericFunctionOperation, [NumericFunctions]);
1416
+
1417
+ // src/datafinder/typed-attributes.ts
1418
+ var MinMax = class {
1419
+ /** Smallest value in the group. */
1420
+ min() {
1421
+ return new AggregateOperation(this.cwj(), "MIN" /* MIN */, "Min " + this.displayName());
1422
+ }
1423
+ /** Largest value in the group. */
1424
+ max() {
1425
+ return new AggregateOperation(this.cwj(), "MAX" /* MAX */, "Max " + this.displayName());
1426
+ }
1427
+ };
1428
+ var StringAttribute = class extends Attribute {
1429
+ constructor(displayName, columnName, columnDbType, owner, parent, embedded, nullable = true, optional = false) {
1430
+ super(displayName, columnName, columnDbType, owner, parent, embedded, nullable, optional);
1431
+ }
1432
+ toConstant(value2) {
1433
+ return new StringConstantOperation(String(value2));
1434
+ }
1435
+ /**
1436
+ * Join the values of a group into one text with `separator` between them. `orderBy` is the order they are
1437
+ * joined in (`[f.name().ascending()]`); without it the order is not defined. Missing values are skipped.
1438
+ */
1439
+ join(separator = "", orderBy = []) {
1440
+ return new AggregateOperation(this.cwj(), "STRING_AGG" /* STRING_AGG */, "Join " + this.displayName(), void 0, separator, orderBy);
793
1441
  }
794
1442
  /** Filter to rows where this attribute equals `value`. */
795
- eq(value) {
796
- return new ComparisonOperation(this.cwj(), "EQUAL" /* EQUAL */, new StringConstantOperation(value));
1443
+ eq(value2) {
1444
+ return new ComparisonOperation(this.cwj(), "EQUAL" /* EQUAL */, new StringConstantOperation(value2));
797
1445
  }
798
1446
  /** Filter to rows where this attribute does not equal `value`. */
799
- ne(value) {
800
- return new ComparisonOperation(this.cwj(), "NOT_EQUAL" /* NOT_EQUAL */, new StringConstantOperation(value));
1447
+ ne(value2) {
1448
+ return new ComparisonOperation(this.cwj(), "NOT_EQUAL" /* NOT_EQUAL */, new StringConstantOperation(value2));
801
1449
  }
802
1450
  /** Filter to rows where this attribute contains `value` as a substring. */
803
- contains(value) {
804
- return new ComparisonOperation(this.cwj(), "LIKE" /* LIKE */, new StringConstantOperation(`%${value}%`));
1451
+ contains(value2) {
1452
+ return new ComparisonOperation(this.cwj(), "LIKE" /* LIKE */, new StringConstantOperation(`%${escapeLike(value2)}%`));
805
1453
  }
806
1454
  /** Filter to rows where this attribute begins with `prefix`. */
807
1455
  startsWith(prefix) {
808
- return new ComparisonOperation(this.cwj(), "LIKE" /* LIKE */, new StringConstantOperation(`${prefix}%`));
1456
+ return new ComparisonOperation(this.cwj(), "LIKE" /* LIKE */, new StringConstantOperation(`${escapeLike(prefix)}%`));
809
1457
  }
810
1458
  /** Filter to rows where this attribute ends with `suffix`. */
811
1459
  endsWith(suffix) {
812
- return new ComparisonOperation(this.cwj(), "LIKE" /* LIKE */, new StringConstantOperation(`%${suffix}`));
1460
+ return new ComparisonOperation(this.cwj(), "LIKE" /* LIKE */, new StringConstantOperation(`%${escapeLike(suffix)}`));
813
1461
  }
814
1462
  /** Filter to rows where this attribute does not contain `value` as a substring. */
815
- notContains(value) {
816
- return new ComparisonOperation(this.cwj(), "NOT_LIKE" /* NOT_LIKE */, new StringConstantOperation(`%${value}%`));
1463
+ notContains(value2) {
1464
+ return new ComparisonOperation(this.cwj(), "NOT_LIKE" /* NOT_LIKE */, new StringConstantOperation(`%${escapeLike(value2)}%`));
817
1465
  }
818
1466
  };
1467
+ applyMixins(StringAttribute, [MinMax, StringFunctions]);
819
1468
  var NumericAttribute = class extends Attribute {
820
- constructor(displayName, columnName, columnDbType, owner, parent, embedded) {
821
- super(displayName, columnName, columnDbType, owner, parent, embedded);
1469
+ constructor(displayName, columnName, columnDbType, owner, parent, embedded, nullable = true, optional = false) {
1470
+ super(displayName, columnName, columnDbType, owner, parent, embedded, nullable, optional);
822
1471
  }
823
1472
  /** Sum of all values in the group. */
824
1473
  sum() {
825
1474
  return new AggregateOperation(this.cwj(), "SUM" /* SUM */, "Sum " + this.displayName());
826
1475
  }
827
- /** Smallest value in the group. */
828
- min() {
829
- return new AggregateOperation(this.cwj(), "MIN" /* MIN */, "Min " + this.displayName());
830
- }
831
- /** Largest value in the group. */
832
- max() {
833
- return new AggregateOperation(this.cwj(), "MAX" /* MAX */, "Max " + this.displayName());
834
- }
835
1476
  /** Arithmetic mean of all values in the group. */
836
1477
  average() {
837
1478
  return new AggregateOperation(this.cwj(), "AVERAGE" /* AVERAGE */, "Average " + this.displayName());
838
1479
  }
839
- /** Absolute value (distance from zero, always non-negative). */
840
- abs() {
841
- return new ScalarFunctionOperation(this.cwj(), "ABS" /* ABS */, "Abs " + this.displayName());
842
- }
843
- /** Round up to the nearest integer. */
844
- ceil() {
845
- return new ScalarFunctionOperation(this.cwj(), "CEILING" /* CEILING */, "Ceil " + this.displayName());
1480
+ /** Standard deviation of the values in the group: the sample one by default, `ddof = 0` for the population one, as `Series.std`. */
1481
+ std(ddof = 1) {
1482
+ const operator = sample(ddof) ? "STDDEV_SAMP" /* STDDEV_SAMP */ : "STDDEV_POP" /* STDDEV_POP */;
1483
+ return new AggregateOperation(this.cwj(), operator, "Std " + this.displayName());
846
1484
  }
847
- /** Round down to the nearest integer. */
848
- floor() {
849
- return new ScalarFunctionOperation(this.cwj(), "FLOOR" /* FLOOR */, "Floor " + this.displayName());
850
- }
851
- /** Square root. */
852
- sqrt() {
853
- return new ScalarFunctionOperation(this.cwj(), "SQRT" /* SQRT */, "Sqrt " + this.displayName());
854
- }
855
- /** Remainder after dividing by `n`. */
856
- mod(n) {
857
- return new ScalarFunctionOperation(this.cwj(), "MOD" /* MOD */, "Mod " + this.displayName(), n);
858
- }
859
- /** Raise to the power of `n`. */
860
- power(n) {
861
- return new ScalarFunctionOperation(this.cwj(), "POWER" /* POWER */, "Power " + this.displayName(), n);
862
- }
863
- /** Round to `d` decimal places, or to the nearest integer when `d` is omitted. */
864
- round(d) {
865
- return new ScalarFunctionOperation(this.cwj(), "ROUND" /* ROUND */, "Round " + this.displayName(), d);
1485
+ /** Variance of the values in the group: the sample one by default, `ddof = 0` for the population one, as `Series.var`. */
1486
+ var(ddof = 1) {
1487
+ const operator = sample(ddof) ? "VAR_SAMP" /* VAR_SAMP */ : "VAR_POP" /* VAR_POP */;
1488
+ return new AggregateOperation(this.cwj(), operator, "Var " + this.displayName());
866
1489
  }
867
1490
  };
1491
+ applyMixins(NumericAttribute, [MinMax, NumericFunctions, Arithmetic]);
868
1492
  var DoubleAttribute = class extends NumericAttribute {
869
- constructor(displayName, columnName, columnDbType, owner, parent, embedded) {
870
- super(displayName, columnName, columnDbType, owner, parent, embedded);
1493
+ constructor(displayName, columnName, columnDbType, owner, parent, embedded, nullable = true, optional = false) {
1494
+ super(displayName, columnName, columnDbType, owner, parent, embedded, nullable, optional);
1495
+ }
1496
+ toConstant(value2) {
1497
+ return new FloatConstantOperation(Number(value2));
871
1498
  }
872
1499
  /** Filter to rows where this attribute equals `value`. */
873
- eq(value) {
874
- return new ComparisonOperation(this.cwj(), "EQUAL" /* EQUAL */, new FloatConstantOperation(value));
1500
+ eq(value2) {
1501
+ return new ComparisonOperation(this.cwj(), "EQUAL" /* EQUAL */, new FloatConstantOperation(value2));
875
1502
  }
876
1503
  /** Filter to rows where this attribute does not equal `value`. */
877
- ne(value) {
878
- return new ComparisonOperation(this.cwj(), "NOT_EQUAL" /* NOT_EQUAL */, new FloatConstantOperation(value));
1504
+ ne(value2) {
1505
+ return new ComparisonOperation(this.cwj(), "NOT_EQUAL" /* NOT_EQUAL */, new FloatConstantOperation(value2));
879
1506
  }
880
1507
  /** Filter to rows where this attribute is greater than `value`. */
881
- gt(value) {
882
- return new ComparisonOperation(this.cwj(), "GREATER_THAN" /* GREATER_THAN */, new FloatConstantOperation(value));
1508
+ gt(value2) {
1509
+ return new ComparisonOperation(this.cwj(), "GREATER_THAN" /* GREATER_THAN */, new FloatConstantOperation(value2));
883
1510
  }
884
1511
  /** Filter to rows where this attribute is less than `value`. */
885
- lt(value) {
886
- return new ComparisonOperation(this.cwj(), "LESS_THAN" /* LESS_THAN */, new FloatConstantOperation(value));
1512
+ lt(value2) {
1513
+ return new ComparisonOperation(this.cwj(), "LESS_THAN" /* LESS_THAN */, new FloatConstantOperation(value2));
887
1514
  }
888
1515
  /** Filter to rows where this attribute is greater than or equal to `value`. */
889
- gte(value) {
890
- return new ComparisonOperation(this.cwj(), "GREATER_THAN_OR_EQUAL_TO" /* GREATER_THAN_OR_EQUAL_TO */, new FloatConstantOperation(value));
1516
+ gte(value2) {
1517
+ return new ComparisonOperation(this.cwj(), "GREATER_THAN_OR_EQUAL_TO" /* GREATER_THAN_OR_EQUAL_TO */, new FloatConstantOperation(value2));
891
1518
  }
892
1519
  /** Filter to rows where this attribute is less than or equal to `value`. */
893
- lte(value) {
894
- return new ComparisonOperation(this.cwj(), "LESS_THAN_OR_EQUAL_TO" /* LESS_THAN_OR_EQUAL_TO */, new FloatConstantOperation(value));
1520
+ lte(value2) {
1521
+ return new ComparisonOperation(this.cwj(), "LESS_THAN_OR_EQUAL_TO" /* LESS_THAN_OR_EQUAL_TO */, new FloatConstantOperation(value2));
895
1522
  }
896
1523
  };
897
1524
  var FloatAttribute = DoubleAttribute;
898
1525
  var DecimalAttribute = class extends NumericAttribute {
899
- constructor(displayName, columnName, columnDbType, owner, parent, embedded) {
900
- super(displayName, columnName, columnDbType, owner, parent, embedded);
1526
+ constructor(displayName, columnName, columnDbType, owner, parent, embedded, nullable = true, optional = false) {
1527
+ super(displayName, columnName, columnDbType, owner, parent, embedded, nullable, optional);
1528
+ }
1529
+ toConstant(value2) {
1530
+ return new DecimalConstantOperation(Number(value2));
901
1531
  }
902
1532
  /** Filter to rows where this attribute equals `value`. */
903
- eq(value) {
904
- return new ComparisonOperation(this.cwj(), "EQUAL" /* EQUAL */, new DecimalConstantOperation(value));
1533
+ eq(value2) {
1534
+ return new ComparisonOperation(this.cwj(), "EQUAL" /* EQUAL */, new DecimalConstantOperation(value2));
905
1535
  }
906
1536
  /** Filter to rows where this attribute does not equal `value`. */
907
- ne(value) {
908
- return new ComparisonOperation(this.cwj(), "NOT_EQUAL" /* NOT_EQUAL */, new DecimalConstantOperation(value));
1537
+ ne(value2) {
1538
+ return new ComparisonOperation(this.cwj(), "NOT_EQUAL" /* NOT_EQUAL */, new DecimalConstantOperation(value2));
909
1539
  }
910
1540
  /** Filter to rows where this attribute is greater than `value`. */
911
- gt(value) {
912
- return new ComparisonOperation(this.cwj(), "GREATER_THAN" /* GREATER_THAN */, new DecimalConstantOperation(value));
1541
+ gt(value2) {
1542
+ return new ComparisonOperation(this.cwj(), "GREATER_THAN" /* GREATER_THAN */, new DecimalConstantOperation(value2));
913
1543
  }
914
1544
  /** Filter to rows where this attribute is less than `value`. */
915
- lt(value) {
916
- return new ComparisonOperation(this.cwj(), "LESS_THAN" /* LESS_THAN */, new DecimalConstantOperation(value));
1545
+ lt(value2) {
1546
+ return new ComparisonOperation(this.cwj(), "LESS_THAN" /* LESS_THAN */, new DecimalConstantOperation(value2));
917
1547
  }
918
1548
  /** Filter to rows where this attribute is greater than or equal to `value`. */
919
- gte(value) {
920
- return new ComparisonOperation(this.cwj(), "GREATER_THAN_OR_EQUAL_TO" /* GREATER_THAN_OR_EQUAL_TO */, new DecimalConstantOperation(value));
1549
+ gte(value2) {
1550
+ return new ComparisonOperation(this.cwj(), "GREATER_THAN_OR_EQUAL_TO" /* GREATER_THAN_OR_EQUAL_TO */, new DecimalConstantOperation(value2));
921
1551
  }
922
1552
  /** Filter to rows where this attribute is less than or equal to `value`. */
923
- lte(value) {
924
- return new ComparisonOperation(this.cwj(), "LESS_THAN_OR_EQUAL_TO" /* LESS_THAN_OR_EQUAL_TO */, new DecimalConstantOperation(value));
1553
+ lte(value2) {
1554
+ return new ComparisonOperation(this.cwj(), "LESS_THAN_OR_EQUAL_TO" /* LESS_THAN_OR_EQUAL_TO */, new DecimalConstantOperation(value2));
925
1555
  }
926
1556
  };
927
1557
  var IntegerAttribute = class extends NumericAttribute {
928
- constructor(displayName, columnName, columnDbType, owner, parent, embedded) {
929
- super(displayName, columnName, columnDbType, owner, parent, embedded);
1558
+ constructor(displayName, columnName, columnDbType, owner, parent, embedded, nullable = true, optional = false) {
1559
+ super(displayName, columnName, columnDbType, owner, parent, embedded, nullable, optional);
1560
+ }
1561
+ toConstant(value2) {
1562
+ return new IntegerConstantOperation(Number(value2));
930
1563
  }
931
1564
  /** Filter to rows where this attribute equals `value`. */
932
- eq(value) {
933
- return new ComparisonOperation(this.cwj(), "EQUAL" /* EQUAL */, new IntegerConstantOperation(value));
1565
+ eq(value2) {
1566
+ return new ComparisonOperation(this.cwj(), "EQUAL" /* EQUAL */, new IntegerConstantOperation(value2));
934
1567
  }
935
1568
  /** Filter to rows where this attribute does not equal `value`. */
936
- ne(value) {
937
- return new ComparisonOperation(this.cwj(), "NOT_EQUAL" /* NOT_EQUAL */, new IntegerConstantOperation(value));
1569
+ ne(value2) {
1570
+ return new ComparisonOperation(this.cwj(), "NOT_EQUAL" /* NOT_EQUAL */, new IntegerConstantOperation(value2));
938
1571
  }
939
1572
  /** Filter to rows where this attribute is greater than `value`. */
940
- gt(value) {
941
- return new ComparisonOperation(this.cwj(), "GREATER_THAN" /* GREATER_THAN */, new IntegerConstantOperation(value));
1573
+ gt(value2) {
1574
+ return new ComparisonOperation(this.cwj(), "GREATER_THAN" /* GREATER_THAN */, new IntegerConstantOperation(value2));
942
1575
  }
943
1576
  /** Filter to rows where this attribute is less than `value`. */
944
- lt(value) {
945
- return new ComparisonOperation(this.cwj(), "LESS_THAN" /* LESS_THAN */, new IntegerConstantOperation(value));
1577
+ lt(value2) {
1578
+ return new ComparisonOperation(this.cwj(), "LESS_THAN" /* LESS_THAN */, new IntegerConstantOperation(value2));
946
1579
  }
947
1580
  /** Filter to rows where this attribute is greater than or equal to `value`. */
948
- gte(value) {
949
- return new ComparisonOperation(this.cwj(), "GREATER_THAN_OR_EQUAL_TO" /* GREATER_THAN_OR_EQUAL_TO */, new IntegerConstantOperation(value));
1581
+ gte(value2) {
1582
+ return new ComparisonOperation(this.cwj(), "GREATER_THAN_OR_EQUAL_TO" /* GREATER_THAN_OR_EQUAL_TO */, new IntegerConstantOperation(value2));
950
1583
  }
951
1584
  /** Filter to rows where this attribute is less than or equal to `value`. */
952
- lte(value) {
953
- return new ComparisonOperation(this.cwj(), "LESS_THAN_OR_EQUAL_TO" /* LESS_THAN_OR_EQUAL_TO */, new IntegerConstantOperation(value));
1585
+ lte(value2) {
1586
+ return new ComparisonOperation(this.cwj(), "LESS_THAN_OR_EQUAL_TO" /* LESS_THAN_OR_EQUAL_TO */, new IntegerConstantOperation(value2));
954
1587
  }
955
1588
  };
956
1589
  var BooleanAttribute = class extends Attribute {
957
- constructor(displayName, columnName, columnDbType, owner, parent, embedded) {
958
- super(displayName, columnName, columnDbType, owner, parent, embedded);
1590
+ constructor(displayName, columnName, columnDbType, owner, parent, embedded, nullable = true, optional = false) {
1591
+ super(displayName, columnName, columnDbType, owner, parent, embedded, nullable, optional);
1592
+ }
1593
+ toConstant(value2) {
1594
+ return new BooleanConstantOperation(Boolean(value2));
959
1595
  }
960
1596
  /** Filter to rows where this attribute equals `value`. */
961
- eq(value) {
962
- return new ComparisonOperation(this.cwj(), "EQUAL" /* EQUAL */, new BooleanConstantOperation(value));
1597
+ eq(value2) {
1598
+ return new ComparisonOperation(this.cwj(), "EQUAL" /* EQUAL */, new BooleanConstantOperation(value2));
963
1599
  }
964
1600
  /** Filter to rows where this attribute is true. */
965
1601
  isTrue() {
@@ -970,39 +1606,47 @@ var BooleanAttribute = class extends Attribute {
970
1606
  return new ComparisonOperation(this.cwj(), "EQUAL" /* EQUAL */, new BooleanConstantOperation(false));
971
1607
  }
972
1608
  };
973
- function parseDate(value) {
974
- if (value instanceof Date) return value;
975
- const d = new Date(value);
976
- if (isNaN(d.getTime())) throw new Error(`Cannot parse date: ${value}`);
1609
+ function parseDate(value2) {
1610
+ if (value2 instanceof Date) return value2;
1611
+ const d = new Date(value2);
1612
+ if (isNaN(d.getTime())) throw new Error(`Cannot parse date: ${value2}`);
977
1613
  return d;
978
1614
  }
1615
+ function temporalConstant(value2) {
1616
+ if (typeof value2 === "string" && DATE_ONLY_PATTERN.test(value2)) return new DateConstantOperation(new DateOnly(value2));
1617
+ const date = parseDate(value2);
1618
+ return date instanceof DateOnly ? new DateConstantOperation(date) : new DateTimeConstantOperation(date);
1619
+ }
979
1620
  var DateAttribute = class extends Attribute {
980
- constructor(displayName, columnName, columnDbType, owner, parent, embedded) {
981
- super(displayName, columnName, columnDbType, owner, parent, embedded);
1621
+ constructor(displayName, columnName, columnDbType, owner, parent, embedded, nullable = true, optional = false) {
1622
+ super(displayName, columnName, columnDbType, owner, parent, embedded, nullable, optional);
1623
+ }
1624
+ toConstant(value2) {
1625
+ return new DateConstantOperation(parseDate(value2));
982
1626
  }
983
1627
  /** Filter to rows where this date equals `value`. */
984
- eq(value) {
985
- return new ComparisonOperation(this.cwj(), "EQUAL" /* EQUAL */, new DateConstantOperation(parseDate(value)));
1628
+ eq(value2) {
1629
+ return new ComparisonOperation(this.cwj(), "EQUAL" /* EQUAL */, new DateConstantOperation(parseDate(value2)));
986
1630
  }
987
1631
  /** Filter to rows where this date does not equal `value`. */
988
- ne(value) {
989
- return new ComparisonOperation(this.cwj(), "NOT_EQUAL" /* NOT_EQUAL */, new DateConstantOperation(parseDate(value)));
1632
+ ne(value2) {
1633
+ return new ComparisonOperation(this.cwj(), "NOT_EQUAL" /* NOT_EQUAL */, new DateConstantOperation(parseDate(value2)));
990
1634
  }
991
1635
  /** Filter to rows where this date is after `value`. */
992
- gt(value) {
993
- return new ComparisonOperation(this.cwj(), "GREATER_THAN" /* GREATER_THAN */, new DateConstantOperation(parseDate(value)));
1636
+ gt(value2) {
1637
+ return new ComparisonOperation(this.cwj(), "GREATER_THAN" /* GREATER_THAN */, new DateConstantOperation(parseDate(value2)));
994
1638
  }
995
1639
  /** Filter to rows where this date is before `value`. */
996
- lt(value) {
997
- return new ComparisonOperation(this.cwj(), "LESS_THAN" /* LESS_THAN */, new DateConstantOperation(parseDate(value)));
1640
+ lt(value2) {
1641
+ return new ComparisonOperation(this.cwj(), "LESS_THAN" /* LESS_THAN */, new DateConstantOperation(parseDate(value2)));
998
1642
  }
999
1643
  /** Filter to rows where this date is on or after `value`. */
1000
- gte(value) {
1001
- return new ComparisonOperation(this.cwj(), "GREATER_THAN_OR_EQUAL_TO" /* GREATER_THAN_OR_EQUAL_TO */, new DateConstantOperation(parseDate(value)));
1644
+ gte(value2) {
1645
+ return new ComparisonOperation(this.cwj(), "GREATER_THAN_OR_EQUAL_TO" /* GREATER_THAN_OR_EQUAL_TO */, new DateConstantOperation(parseDate(value2)));
1002
1646
  }
1003
1647
  /** Filter to rows where this date is on or before `value`. */
1004
- lte(value) {
1005
- return new ComparisonOperation(this.cwj(), "LESS_THAN_OR_EQUAL_TO" /* LESS_THAN_OR_EQUAL_TO */, new DateConstantOperation(parseDate(value)));
1648
+ lte(value2) {
1649
+ return new ComparisonOperation(this.cwj(), "LESS_THAN_OR_EQUAL_TO" /* LESS_THAN_OR_EQUAL_TO */, new DateConstantOperation(parseDate(value2)));
1006
1650
  }
1007
1651
  /** Extract the four-digit calendar year. */
1008
1652
  year() {
@@ -1028,6 +1672,22 @@ var DateAttribute = class extends Attribute {
1028
1672
  dayOfWeek() {
1029
1673
  return new DateExtractOperation(this.cwj(), "DOW" /* DOW */, "Day Of Week " + this.displayName());
1030
1674
  }
1675
+ /** The date of the first day of the week the date falls in (a Monday). */
1676
+ firstDayOfWeek() {
1677
+ return new DateTruncOperation(this.cwj(), "WEEK" /* WEEK */, "First Day Of Week " + this.displayName());
1678
+ }
1679
+ /** The date of the first day of the month the date falls in. */
1680
+ firstDayOfMonth() {
1681
+ return new DateTruncOperation(this.cwj(), "MONTH" /* MONTH */, "First Day Of Month " + this.displayName());
1682
+ }
1683
+ /** The date of the first day of the quarter the date falls in. */
1684
+ firstDayOfQuarter() {
1685
+ return new DateTruncOperation(this.cwj(), "QUARTER" /* QUARTER */, "First Day Of Quarter " + this.displayName());
1686
+ }
1687
+ /** The date of the first day of the year the date falls in. */
1688
+ firstDayOfYear() {
1689
+ return new DateTruncOperation(this.cwj(), "YEAR" /* YEAR */, "First Day Of Year " + this.displayName());
1690
+ }
1031
1691
  /** Add `n` days to this date. */
1032
1692
  addDays(n) {
1033
1693
  return new DateArithmeticOperation(this.cwj(), n, "DAY" /* DAY */, true, "Add Days " + this.displayName());
@@ -1066,32 +1726,35 @@ var DateAttribute = class extends Attribute {
1066
1726
  }
1067
1727
  };
1068
1728
  var DateTimeAttribute = class extends Attribute {
1069
- constructor(displayName, columnName, columnDbType, owner, parent, embedded) {
1070
- super(displayName, columnName, columnDbType, owner, parent, embedded);
1729
+ constructor(displayName, columnName, columnDbType, owner, parent, embedded, nullable = true, optional = false) {
1730
+ super(displayName, columnName, columnDbType, owner, parent, embedded, nullable, optional);
1731
+ }
1732
+ toConstant(value2) {
1733
+ return temporalConstant(value2);
1071
1734
  }
1072
1735
  /** Filter to rows where this timestamp equals `value`. */
1073
- eq(value) {
1074
- return new ComparisonOperation(this.cwj(), "EQUAL" /* EQUAL */, new DateTimeConstantOperation(parseDate(value)));
1736
+ eq(value2) {
1737
+ return new ComparisonOperation(this.cwj(), "EQUAL" /* EQUAL */, temporalConstant(value2));
1075
1738
  }
1076
1739
  /** Filter to rows where this timestamp does not equal `value`. */
1077
- ne(value) {
1078
- return new ComparisonOperation(this.cwj(), "NOT_EQUAL" /* NOT_EQUAL */, new DateTimeConstantOperation(parseDate(value)));
1740
+ ne(value2) {
1741
+ return new ComparisonOperation(this.cwj(), "NOT_EQUAL" /* NOT_EQUAL */, temporalConstant(value2));
1079
1742
  }
1080
1743
  /** Filter to rows where this timestamp is after `value`. */
1081
- gt(value) {
1082
- return new ComparisonOperation(this.cwj(), "GREATER_THAN" /* GREATER_THAN */, new DateTimeConstantOperation(parseDate(value)));
1744
+ gt(value2) {
1745
+ return new ComparisonOperation(this.cwj(), "GREATER_THAN" /* GREATER_THAN */, temporalConstant(value2));
1083
1746
  }
1084
1747
  /** Filter to rows where this timestamp is before `value`. */
1085
- lt(value) {
1086
- return new ComparisonOperation(this.cwj(), "LESS_THAN" /* LESS_THAN */, new DateTimeConstantOperation(parseDate(value)));
1748
+ lt(value2) {
1749
+ return new ComparisonOperation(this.cwj(), "LESS_THAN" /* LESS_THAN */, temporalConstant(value2));
1087
1750
  }
1088
1751
  /** Filter to rows where this timestamp is on or after `value`. */
1089
- gte(value) {
1090
- return new ComparisonOperation(this.cwj(), "GREATER_THAN_OR_EQUAL_TO" /* GREATER_THAN_OR_EQUAL_TO */, new DateTimeConstantOperation(parseDate(value)));
1752
+ gte(value2) {
1753
+ return new ComparisonOperation(this.cwj(), "GREATER_THAN_OR_EQUAL_TO" /* GREATER_THAN_OR_EQUAL_TO */, temporalConstant(value2));
1091
1754
  }
1092
1755
  /** Filter to rows where this timestamp is on or before `value`. */
1093
- lte(value) {
1094
- return new ComparisonOperation(this.cwj(), "LESS_THAN_OR_EQUAL_TO" /* LESS_THAN_OR_EQUAL_TO */, new DateTimeConstantOperation(parseDate(value)));
1756
+ lte(value2) {
1757
+ return new ComparisonOperation(this.cwj(), "LESS_THAN_OR_EQUAL_TO" /* LESS_THAN_OR_EQUAL_TO */, temporalConstant(value2));
1095
1758
  }
1096
1759
  /** Extract the four-digit calendar year. */
1097
1760
  year() {
@@ -1129,6 +1792,22 @@ var DateTimeAttribute = class extends Attribute {
1129
1792
  dayOfWeek() {
1130
1793
  return new DateExtractOperation(this.cwj(), "DOW" /* DOW */, "Day Of Week " + this.displayName());
1131
1794
  }
1795
+ /** The date of the first day of the week the date falls in (a Monday). */
1796
+ firstDayOfWeek() {
1797
+ return new DateTruncOperation(this.cwj(), "WEEK" /* WEEK */, "First Day Of Week " + this.displayName());
1798
+ }
1799
+ /** The date of the first day of the month the date falls in. */
1800
+ firstDayOfMonth() {
1801
+ return new DateTruncOperation(this.cwj(), "MONTH" /* MONTH */, "First Day Of Month " + this.displayName());
1802
+ }
1803
+ /** The date of the first day of the quarter the date falls in. */
1804
+ firstDayOfQuarter() {
1805
+ return new DateTruncOperation(this.cwj(), "QUARTER" /* QUARTER */, "First Day Of Quarter " + this.displayName());
1806
+ }
1807
+ /** The date of the first day of the year the date falls in. */
1808
+ firstDayOfYear() {
1809
+ return new DateTruncOperation(this.cwj(), "YEAR" /* YEAR */, "First Day Of Year " + this.displayName());
1810
+ }
1132
1811
  /** Add `n` days to this timestamp. */
1133
1812
  addDays(n) {
1134
1813
  return new DateArithmeticOperation(this.cwj(), n, "DAY" /* DAY */, true, "Add Days " + this.displayName());
@@ -1202,6 +1881,85 @@ var DateTimeAttribute = class extends Attribute {
1202
1881
  return new DateDiffOperation(this.cwj(), other, "SECOND" /* SECOND */, "Diff Seconds " + this.displayName());
1203
1882
  }
1204
1883
  };
1884
+ applyMixins(DateAttribute, [MinMax]);
1885
+ applyMixins(DateTimeAttribute, [MinMax]);
1886
+
1887
+ // src/datafinder/expressions.ts
1888
+ function constant(value2) {
1889
+ if (typeof value2 === "boolean") return new BooleanConstantOperation(value2);
1890
+ if (typeof value2 === "number" && Number.isFinite(value2)) {
1891
+ return Number.isInteger(value2) ? new IntegerConstantOperation(value2) : new FloatConstantOperation(value2);
1892
+ }
1893
+ if (typeof value2 === "string") return new StringConstantOperation(value2);
1894
+ if (value2 instanceof DateOnly) return new DateConstantOperation(value2);
1895
+ if (value2 instanceof Date) return new DateTimeConstantOperation(value2);
1896
+ throw new TypeError(`A constant column holds a boolean, a finite number, a string or a date, not ${value2 === null ? "null" : typeof value2}`);
1897
+ }
1898
+ function countAll() {
1899
+ return new CountAllOperation("");
1900
+ }
1901
+
1902
+ // src/datafinder/conditional.ts
1903
+ var CONDITIONS = [
1904
+ ComparisonOperation,
1905
+ LogicalOperation,
1906
+ IsNullOperation,
1907
+ IsNotNullOperation,
1908
+ InOperation,
1909
+ NotInOperation,
1910
+ ExistsOperation,
1911
+ NotExistsOperation
1912
+ ];
1913
+ function value(branch) {
1914
+ if (branch instanceof Attribute) return branch.cwj();
1915
+ if (branch instanceof RelationalOperationElement) return branch;
1916
+ try {
1917
+ return constant(branch);
1918
+ } catch {
1919
+ throw new TypeError(`A branch is a column, an expression or a value, not ${branch === null ? "null" : typeof branch}`);
1920
+ }
1921
+ }
1922
+ function checked(condition) {
1923
+ if (!CONDITIONS.some((c) => condition instanceof c)) {
1924
+ throw new TypeError("The condition is a comparison, a null check, a membership test, exists, or and/or of those");
1925
+ }
1926
+ return condition;
1927
+ }
1928
+ function chain(cases, fallback) {
1929
+ const [[condition, then], ...rest] = cases;
1930
+ return new CaseOperation(condition, then, rest.length > 0 ? chain(rest, fallback) : fallback);
1931
+ }
1932
+ var Then = class extends CaseOperation {
1933
+ constructor(cases) {
1934
+ const first = chain(cases);
1935
+ super(first.condition, first.then, first.fallback);
1936
+ this.cases = cases;
1937
+ }
1938
+ cases;
1939
+ /** Another case, tried when the ones before it do not hold. */
1940
+ when(condition) {
1941
+ return new When(checked(condition), this.cases);
1942
+ }
1943
+ /** The value when none of the cases hold. */
1944
+ otherwise(branch) {
1945
+ return chain(this.cases, value(branch));
1946
+ }
1947
+ };
1948
+ var When = class {
1949
+ constructor(condition, earlier = []) {
1950
+ this.condition = condition;
1951
+ this.earlier = earlier;
1952
+ }
1953
+ condition;
1954
+ earlier;
1955
+ /** The value where the condition holds. A value is a column, an expression or a plain value. */
1956
+ then(branch) {
1957
+ return new Then([...this.earlier, [this.condition, value(branch)]]);
1958
+ }
1959
+ };
1960
+ function when(condition) {
1961
+ return new When(checked(condition));
1962
+ }
1205
1963
 
1206
1964
  // src/model/milestoning.ts
1207
1965
  var MilestoningColumns = class {
@@ -1280,6 +2038,67 @@ var MilestonedTable = class extends Table {
1280
2038
  milestoningColumns;
1281
2039
  };
1282
2040
 
2041
+ // src/datafinder/dialect.ts
2042
+ var doubleQuoted = (name) => '"' + name.replaceAll('"', '""') + '"';
2043
+ var quoted = (value2) => "'" + value2.replaceAll("'", "''") + "'";
2044
+ var SECONDS_PER = { ["HOUR" /* HOUR */]: 3600, ["MINUTE" /* MINUTE */]: 60, ["SECOND" /* SECOND */]: 1 };
2045
+ var POSTGRES = {
2046
+ name: "postgres",
2047
+ quoteIdentifier: doubleQuoted,
2048
+ stringLiteral: quoted,
2049
+ orderDirection: (direction) => direction === "ASC" /* ASC */ ? " ASC" : " DESC",
2050
+ doubleType: "DOUBLE PRECISION",
2051
+ dayOfWeek: (expression) => `EXTRACT(DOW FROM ${expression})`,
2052
+ dateDiff(unit, from, to) {
2053
+ const start = `CAST(${from} AS TIMESTAMP)`;
2054
+ const end = `CAST(${to} AS TIMESTAMP)`;
2055
+ switch (unit) {
2056
+ case "DAY" /* DAY */:
2057
+ return `(CAST(${to} AS DATE) - CAST(${from} AS DATE))`;
2058
+ case "MONTH" /* MONTH */:
2059
+ return `CAST(EXTRACT(YEAR FROM AGE(${end}, ${start})) * 12 + EXTRACT(MONTH FROM AGE(${end}, ${start})) AS BIGINT)`;
2060
+ case "YEAR" /* YEAR */:
2061
+ return `CAST(EXTRACT(YEAR FROM AGE(${end}, ${start})) AS BIGINT)`;
2062
+ default: {
2063
+ const seconds = SECONDS_PER[unit];
2064
+ if (seconds === void 0) throw new Error(`Cannot take the difference in ${unit}`);
2065
+ return `CAST(FLOOR(EXTRACT(EPOCH FROM (${end} - ${start})) / ${seconds}) AS BIGINT)`;
2066
+ }
2067
+ }
2068
+ },
2069
+ stringAgg: (expression, separator, orderBy) => `STRING_AGG(${expression}, ${separator}${orderBy.length > 0 ? " ORDER BY " + orderBy.join(", ") : ""})`
2070
+ };
2071
+ var DUCKDB = {
2072
+ ...POSTGRES,
2073
+ name: "duckdb",
2074
+ // DuckDB sorts nulls last whichever way the sort goes
2075
+ orderDirection: (direction) => direction === "ASC" /* ASC */ ? " ASC" : " DESC NULLS FIRST",
2076
+ doubleType: "DOUBLE",
2077
+ dateDiff: (unit, from, to) => `DATE_DIFF('${unit.toLowerCase()}', ${from}, ${to})`
2078
+ };
2079
+ var DATABRICKS = {
2080
+ name: "databricks",
2081
+ // a double-quoted token is a string in Databricks; identifiers take backticks
2082
+ quoteIdentifier: (name) => "`" + name.replaceAll("`", "``") + "`",
2083
+ // a backslash starts an escape in a Databricks string literal, and a doubled quote is not one: Spark reads
2084
+ // 'it''s' as the two literals 'it' and 's' and joins them, losing the quote. A quote is escaped with a backslash.
2085
+ stringLiteral: (value2) => "'" + value2.replaceAll("\\", "\\\\").replaceAll("'", "\\'") + "'",
2086
+ // Databricks sorts nulls first when ascending, last when descending
2087
+ orderDirection: (direction) => direction === "ASC" /* ASC */ ? " ASC NULLS LAST" : " DESC NULLS FIRST",
2088
+ doubleType: "DOUBLE",
2089
+ // DAYOFWEEK is 1 = Sunday through 7 = Saturday
2090
+ dayOfWeek: (expression) => `(DAYOFWEEK(${expression}) - 1)`,
2091
+ dateDiff: (unit, from, to) => `DATEDIFF(${unit}, ${from}, ${to})`,
2092
+ stringAgg: (expression, separator, orderBy) => `LISTAGG(${expression}, ${separator})${orderBy.length > 0 ? " WITHIN GROUP (ORDER BY " + orderBy.join(", ") + ")" : ""}`
2093
+ };
2094
+ var DIALECTS = { postgres: POSTGRES, duckdb: DUCKDB, databricks: DATABRICKS };
2095
+ function dialectOf(dialect) {
2096
+ if (typeof dialect !== "string") return dialect;
2097
+ const found = DIALECTS[dialect];
2098
+ if (found === void 0) throw new Error(`Unknown SQL dialect '${dialect}': one of ${Object.keys(DIALECTS).join(", ")}`);
2099
+ return found;
2100
+ }
2101
+
1283
2102
  // src/datafinder/sql-generator.ts
1284
2103
  var TableAlias = class {
1285
2104
  constructor(table, alias) {
@@ -1307,14 +2126,20 @@ var Join = class {
1307
2126
  source;
1308
2127
  target;
1309
2128
  filterOp;
2129
+ /** `source = target`, written with the key column first as Legend writes a join defined as key = foreign key. */
2130
+ condition() {
2131
+ let [first, second] = [this.source, this.target];
2132
+ if (second.column.primaryKey && !first.column.primaryKey) [first, second] = [second, first];
2133
+ return first.tableAlias.alias + "." + first.column.name + " = " + second.tableAlias.alias + "." + second.column.name;
2134
+ }
1310
2135
  };
1311
- function sqlFormatDatetime(value) {
2136
+ function sqlFormatDatetime(value2) {
1312
2137
  const pad = (n, w = 2) => String(n).padStart(w, "0");
1313
- return `'${value.getUTCFullYear()}-${pad(value.getUTCMonth() + 1)}-${pad(value.getUTCDate())} ${pad(value.getUTCHours())}:${pad(value.getUTCMinutes())}:${pad(value.getUTCSeconds())}'`;
2138
+ return `'${value2.getUTCFullYear()}-${pad(value2.getUTCMonth() + 1)}-${pad(value2.getUTCDate())} ${pad(value2.getUTCHours())}:${pad(value2.getUTCMinutes())}:${pad(value2.getUTCSeconds())}'`;
1314
2139
  }
1315
- function sqlFormatDate(value) {
2140
+ function sqlFormatDate(value2) {
1316
2141
  const pad = (n) => String(n).padStart(2, "0");
1317
- return `'${value.getUTCFullYear()}-${pad(value.getUTCMonth() + 1)}-${pad(value.getUTCDate())}'`;
2142
+ return `'${value2.getUTCFullYear()}-${pad(value2.getUTCMonth() + 1)}-${pad(value2.getUTCDate())}'`;
1318
2143
  }
1319
2144
  var LOGICAL_OPERATOR_STR = {
1320
2145
  ["AND" /* AND */]: " AND ",
@@ -1333,6 +2158,13 @@ var COMPARISON_OPERATOR_STR = {
1333
2158
  var AGGREGATE_SQL_NAMES = {
1334
2159
  ["AVERAGE" /* AVERAGE */]: "AVG"
1335
2160
  };
2161
+ var GUARDED_COMPARISONS = /* @__PURE__ */ new Set([
2162
+ "LESS_THAN" /* LESS_THAN */,
2163
+ "GREATER_THAN" /* GREATER_THAN */,
2164
+ "LESS_THAN_OR_EQUAL_TO" /* LESS_THAN_OR_EQUAL_TO */,
2165
+ "GREATER_THAN_OR_EQUAL_TO" /* GREATER_THAN_OR_EQUAL_TO */,
2166
+ "LIKE" /* LIKE */
2167
+ ]);
1336
2168
  var WINDOW_SQL_NAMES = {
1337
2169
  ["ROW_NUMBER" /* ROW_NUMBER */]: "ROW_NUMBER",
1338
2170
  ["RANK" /* RANK */]: "RANK",
@@ -1364,31 +2196,63 @@ var SCALAR_SQL_NAMES = {
1364
2196
  ["RIGHT" /* RIGHT */]: "RIGHT",
1365
2197
  ["REPEAT" /* REPEAT */]: "REPEAT",
1366
2198
  ["REPLACE" /* REPLACE */]: "REPLACE",
1367
- ["SUBSTRING" /* SUBSTRING */]: "SUBSTRING"
2199
+ ["SUBSTRING" /* SUBSTRING */]: "SUBSTRING",
2200
+ ["COALESCE" /* COALESCE */]: "COALESCE"
1368
2201
  };
1369
- function constantValueString(op) {
1370
- if (op instanceof StringConstantOperation) return "'" + op.value + "'";
2202
+ function constantValueString(op, d) {
2203
+ if (op instanceof StringConstantOperation) return d.stringLiteral(op.value);
1371
2204
  if (op instanceof DateConstantOperation) return sqlFormatDate(op.value);
1372
2205
  if (op instanceof DateTimeConstantOperation) return sqlFormatDatetime(op.value);
1373
2206
  if (op instanceof IntegerConstantOperation) return String(op.value);
1374
- if (op instanceof FloatConstantOperation) return String(op.value);
2207
+ if (op instanceof FloatConstantOperation) return Number.isInteger(op.value) && Math.abs(op.value) < 1e21 ? op.value.toFixed(1) : String(op.value);
1375
2208
  if (op instanceof BooleanConstantOperation) return op.value ? "TRUE" : "FALSE";
1376
2209
  if (op instanceof DecimalConstantOperation) return String(op.value);
1377
2210
  throw new Error("Unknown constant operation");
1378
2211
  }
1379
- function windowSpecToString(window) {
2212
+ function selectedConstantString(op, d) {
2213
+ if (op instanceof FloatConstantOperation) return "CAST(" + constantValueString(op, d) + " AS " + d.doubleType + ")";
2214
+ if (op instanceof DateTimeConstantOperation) return "TIMESTAMP " + constantValueString(op, d);
2215
+ if (op instanceof DateConstantOperation) return "DATE " + constantValueString(op, d);
2216
+ return constantValueString(op, d);
2217
+ }
2218
+ function windowSpecToString(window, d) {
1380
2219
  const parts = [];
1381
2220
  if (window.partitionBy.length > 0) {
1382
- parts.push("PARTITION BY " + window.partitionBy.map((p) => sqlOperationToString(p)).join(", "));
2221
+ parts.push("PARTITION BY " + window.partitionBy.map((p) => sqlOperationToString(p, d)).join(", "));
1383
2222
  }
1384
2223
  if (window.orderBy.length > 0) {
1385
2224
  parts.push("ORDER BY " + window.orderBy.map(
1386
- (s) => sqlOperationToString(s.column) + (s.direction === "ASC" /* ASC */ ? " ASC" : " DESC")
2225
+ (s) => sqlOperationToString(s.column, d) + d.orderDirection(s.direction)
1387
2226
  ).join(", "));
1388
2227
  }
1389
2228
  return "OVER (" + parts.join(" ") + ")";
1390
2229
  }
1391
- function sqlOperationToString(operation) {
2230
+ var ARITHMETIC_PRECEDENCE = {
2231
+ ["+" /* ADD */]: 1,
2232
+ ["-" /* SUBTRACT */]: 1,
2233
+ ["*" /* MULTIPLY */]: 2,
2234
+ ["/" /* DIVIDE */]: 2
2235
+ };
2236
+ function arithmeticNeedsParentheses(parent, child, onRight) {
2237
+ if (!(child instanceof ArithmeticOperation)) return false;
2238
+ const here = ARITHMETIC_PRECEDENCE[parent.operator];
2239
+ const there = ARITHMETIC_PRECEDENCE[child.operator];
2240
+ return there < here || there === here && onRight && (parent.operator === "-" /* SUBTRACT */ || parent.operator === "/" /* DIVIDE */);
2241
+ }
2242
+ function operandString(operation, d) {
2243
+ return operation instanceof ConstantOperation ? constantValueString(operation, d) : sqlOperationToString(operation, d);
2244
+ }
2245
+ var RenderedSql = class extends RelationalOperationElement {
2246
+ constructor(sql) {
2247
+ super();
2248
+ this.sql = sql;
2249
+ }
2250
+ sql;
2251
+ };
2252
+ function isCondition(op) {
2253
+ 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;
2254
+ }
2255
+ function sqlOperationToString(operation, d) {
1392
2256
  if (operation instanceof TableAliasColumn) {
1393
2257
  return operation.tableAlias.alias + "." + operation.column.name;
1394
2258
  }
@@ -1396,46 +2260,71 @@ function sqlOperationToString(operation) {
1396
2260
  const fn = WINDOW_SQL_NAMES[operation.func];
1397
2261
  const parts = [];
1398
2262
  if (operation.element !== null && operation.element !== void 0) {
1399
- parts.push(sqlOperationToString(operation.element));
2263
+ parts.push(sqlOperationToString(operation.element, d));
1400
2264
  }
1401
2265
  if (operation.secondArg !== void 0) parts.push(String(operation.secondArg));
1402
2266
  for (const arg of operation.extraArgs) {
1403
- parts.push(typeof arg === "string" ? "'" + arg + "'" : String(arg));
2267
+ parts.push(typeof arg === "string" ? d.stringLiteral(arg) : String(arg));
1404
2268
  }
1405
2269
  const sql = fn + "(" + parts.join(", ") + ")";
1406
- return sql + (operation.window !== void 0 ? " " + windowSpecToString(operation.window) : " OVER ()");
2270
+ return sql + (operation.window !== void 0 ? " " + windowSpecToString(operation.window, d) : " OVER ()");
2271
+ }
2272
+ if (operation instanceof AggregateOperation && operation.operator === "COUNT_DISTINCT" /* COUNT_DISTINCT */) {
2273
+ return "COUNT(DISTINCT " + sqlOperationToString(operation.element, d) + ")";
2274
+ }
2275
+ if (operation instanceof AggregateOperation && operation.operator === "STRING_AGG" /* STRING_AGG */) {
2276
+ let sql = d.stringAgg(
2277
+ sqlOperationToString(operation.element, d),
2278
+ d.stringLiteral(operation.separator ?? ""),
2279
+ operation.orderBy.map((s) => sqlOperationToString(s.column, d) + d.orderDirection(s.direction))
2280
+ );
2281
+ if (operation.window !== void 0) sql += " " + windowSpecToString(operation.window, d);
2282
+ return sql;
1407
2283
  }
1408
2284
  if (operation instanceof AggregateOperation) {
1409
2285
  const fn = AGGREGATE_SQL_NAMES[operation.operator] ?? operation.operator;
1410
- let sql = fn + "(" + sqlOperationToString(operation.element) + ")";
2286
+ let sql = fn + "(" + sqlOperationToString(operation.element, d) + ")";
1411
2287
  if (operation.window !== void 0) {
1412
- sql += " " + windowSpecToString(operation.window);
2288
+ sql += " " + windowSpecToString(operation.window, d);
1413
2289
  }
1414
2290
  return sql;
1415
2291
  }
1416
2292
  if (operation instanceof ScalarFunctionOperation) {
1417
2293
  const fn = SCALAR_SQL_NAMES[operation.func];
1418
- const parts = [sqlOperationToString(operation.element)];
2294
+ const parts = [sqlOperationToString(operation.element, d)];
1419
2295
  if (operation.secondArg !== void 0) parts.push(String(operation.secondArg));
1420
2296
  for (const arg of operation.extraArgs) {
1421
- parts.push(typeof arg === "string" ? "'" + arg + "'" : String(arg));
2297
+ parts.push(typeof arg === "string" ? d.stringLiteral(arg) : String(arg));
1422
2298
  }
1423
2299
  return fn + "(" + parts.join(", ") + ")";
1424
2300
  }
1425
2301
  if (operation instanceof DateExtractOperation) {
1426
- return "EXTRACT(" + operation.part + " FROM " + sqlOperationToString(operation.element) + ")";
2302
+ const element = sqlOperationToString(operation.element, d);
2303
+ return operation.part === "DOW" /* DOW */ ? d.dayOfWeek(element) : "EXTRACT(" + operation.part + " FROM " + element + ")";
2304
+ }
2305
+ if (operation instanceof DateTruncOperation) {
2306
+ return "CAST(DATE_TRUNC('" + operation.part.toLowerCase() + "', " + sqlOperationToString(operation.element, d) + ") AS DATE)";
1427
2307
  }
1428
2308
  if (operation instanceof DateArithmeticOperation) {
1429
2309
  const op = operation.isAdd ? "+" : "-";
1430
- return sqlOperationToString(operation.element) + " " + op + " INTERVAL " + operation.n + " " + operation.unit;
2310
+ return sqlOperationToString(operation.element, d) + " " + op + " INTERVAL '" + operation.n + "' " + operation.unit;
1431
2311
  }
1432
2312
  if (operation instanceof DateDiffOperation) {
1433
- const otherSql = sqlFormatDatetime(operation.other);
1434
- return "DATE_DIFF('" + operation.unit.toLowerCase() + "', " + sqlOperationToString(operation.element) + ", " + otherSql + ")";
2313
+ return d.dateDiff(operation.unit, sqlOperationToString(operation.element, d), "TIMESTAMP " + sqlFormatDatetime(operation.other));
1435
2314
  }
1436
2315
  if (operation instanceof CountAllOperation) return "COUNT(*)";
2316
+ if (operation instanceof ConstantOperation) return selectedConstantString(operation, d);
2317
+ if (operation instanceof RenderedSql) return operation.sql;
2318
+ if (operation instanceof ConcatOperation) return operation.parts.map((part) => operandString(part, d)).join(" || ");
2319
+ if (operation instanceof ArithmeticOperation) {
2320
+ let left = operandString(operation.left, d);
2321
+ let right = operandString(operation.right, d);
2322
+ if (arithmeticNeedsParentheses(operation, operation.left, false)) left = "(" + left + ")";
2323
+ if (arithmeticNeedsParentheses(operation, operation.right, true)) right = "(" + right + ")";
2324
+ return left + " " + operation.operator + " " + right;
2325
+ }
1437
2326
  if (operation instanceof Alias) {
1438
- return sqlOperationToString(operation.element) + ' AS "' + operation.name + '"';
2327
+ return sqlOperationToString(operation.element, d) + " AS " + d.quoteIdentifier(operation.name);
1439
2328
  }
1440
2329
  throw new TypeError("Unknown operation in sqlOperationToString: " + operation.constructor.name);
1441
2330
  }
@@ -1447,81 +2336,61 @@ function findColumn(operation) {
1447
2336
  if (operation instanceof ColumnWithJoin) return operation;
1448
2337
  throw new TypeError("Cannot find ColumnWithJoin in: " + operation.constructor.name);
1449
2338
  }
1450
- function openEndClause(endAttr, value, infiniteDatetime) {
1451
- const gtOp = endAttr instanceof DateTimeAttribute ? endAttr.gt(value) : endAttr.gt(value);
2339
+ function openEndClause(endAttr, value2, infiniteDatetime) {
2340
+ const gtOp = endAttr instanceof DateTimeAttribute ? endAttr.gt(value2) : endAttr.gt(value2);
1452
2341
  if (infiniteDatetime === void 0) {
1453
2342
  const colRef = new ColumnWithJoin(endAttr.column(), endAttr.parent());
1454
2343
  return new LogicalOperation(gtOp, "OR" /* OR */, new IsNullOperation(colRef));
1455
2344
  }
1456
2345
  return gtOp;
1457
2346
  }
1458
- function buildMilestoningFilterOperation(businessDate, processingDatetime, table, joinNode) {
1459
- const mc = table.milestoningColumns;
1460
- const ops = [];
2347
+ function andAll(ops) {
2348
+ const present = ops.filter((op) => op !== null);
2349
+ if (present.length === 0) return null;
2350
+ return present.slice(1).reduce((left, right) => new LogicalOperation(left, "AND" /* AND */, right), present[0]);
2351
+ }
2352
+ function processingPredicate(mc, processingDatetime, joinNode) {
2353
+ if (!(mc instanceof ProcessingTemporalColumns || mc instanceof BusinessDateAndProcessingTemporalColumns || mc instanceof BiTemporalColumns) || processingDatetime === null) return null;
2354
+ const startAt = new DateTimeAttribute("start_at", mc.startAtColumn.name, mc.startAtColumn.type, mc.startAtColumn.table.qualifiedName, joinNode);
2355
+ const endAt = new DateTimeAttribute("end_at", mc.endAtColumn.name, mc.endAtColumn.type, mc.endAtColumn.table.qualifiedName, joinNode);
2356
+ return new LogicalOperation(startAt.lte(processingDatetime), "AND" /* AND */, openEndClause(endAt, processingDatetime, mc.infiniteDatetime));
2357
+ }
2358
+ function businessPredicate(mc, businessDate, joinNode) {
2359
+ if (businessDate === null) return null;
1461
2360
  if (mc instanceof BiTemporalColumns) {
1462
- if (businessDate !== null) {
1463
- const dateFrom = new DateAttribute("business_date_from", mc.businessDateFromColumn.name, mc.businessDateFromColumn.type, mc.businessDateFromColumn.table.qualifiedName, joinNode);
1464
- const dateTo = new DateAttribute("business_date_to", mc.businessDateToColumn.name, mc.businessDateToColumn.type, mc.businessDateToColumn.table.qualifiedName, joinNode);
1465
- ops.push(new LogicalOperation(dateFrom.lte(businessDate), "AND" /* AND */, openEndClause(dateTo, businessDate, mc.infiniteDatetime)));
1466
- }
1467
- if (processingDatetime !== null) {
1468
- const startAt = new DateTimeAttribute("start_at", mc.startAtColumn.name, mc.startAtColumn.type, mc.startAtColumn.table.qualifiedName, joinNode);
1469
- const endAt = new DateTimeAttribute("end_at", mc.endAtColumn.name, mc.endAtColumn.type, mc.endAtColumn.table.qualifiedName, joinNode);
1470
- ops.push(new LogicalOperation(startAt.lte(processingDatetime), "AND" /* AND */, openEndClause(endAt, processingDatetime, mc.infiniteDatetime)));
1471
- }
1472
- } else if (mc instanceof BusinessDateAndProcessingTemporalColumns) {
1473
- if (businessDate !== null) {
1474
- const businessAtt = new DateAttribute("business_date", mc.businessDateColumn.name, mc.businessDateColumn.type, mc.businessDateColumn.table.qualifiedName, joinNode);
1475
- ops.push(businessAtt.eq(businessDate));
1476
- }
1477
- if (processingDatetime !== null) {
1478
- const startAt = new DateTimeAttribute("start_at", mc.startAtColumn.name, mc.startAtColumn.type, mc.startAtColumn.table.qualifiedName, joinNode);
1479
- const endAt = new DateTimeAttribute("end_at", mc.endAtColumn.name, mc.endAtColumn.type, mc.endAtColumn.table.qualifiedName, joinNode);
1480
- ops.push(new LogicalOperation(startAt.lte(processingDatetime), "AND" /* AND */, openEndClause(endAt, processingDatetime, mc.infiniteDatetime)));
1481
- }
1482
- } else if (mc instanceof ProcessingTemporalColumns && processingDatetime !== null) {
1483
- const startAt = new DateTimeAttribute("start_at", mc.startAtColumn.name, mc.startAtColumn.type, mc.startAtColumn.table.qualifiedName, joinNode);
1484
- const endAt = new DateTimeAttribute("end_at", mc.endAtColumn.name, mc.endAtColumn.type, mc.endAtColumn.table.qualifiedName, joinNode);
1485
- ops.push(new LogicalOperation(startAt.lte(processingDatetime), "AND" /* AND */, openEndClause(endAt, processingDatetime, mc.infiniteDatetime)));
1486
- } else if (mc instanceof SingleBusinessDateColumn && businessDate !== null) {
2361
+ const dateFrom = new DateAttribute("business_date_from", mc.businessDateFromColumn.name, mc.businessDateFromColumn.type, mc.businessDateFromColumn.table.qualifiedName, joinNode);
2362
+ const dateTo = new DateAttribute("business_date_to", mc.businessDateToColumn.name, mc.businessDateToColumn.type, mc.businessDateToColumn.table.qualifiedName, joinNode);
2363
+ return new LogicalOperation(dateFrom.lte(businessDate), "AND" /* AND */, openEndClause(dateTo, businessDate, mc.infiniteDatetime));
2364
+ }
2365
+ if (mc instanceof BusinessDateAndProcessingTemporalColumns || mc instanceof SingleBusinessDateColumn) {
1487
2366
  const businessAtt = new DateAttribute("business_date", mc.businessDateColumn.name, mc.businessDateColumn.type, mc.businessDateColumn.table.qualifiedName, joinNode);
1488
- ops.push(businessAtt.eq(businessDate));
2367
+ return businessAtt.eq(businessDate);
1489
2368
  }
1490
- if (ops.length === 0) return null;
1491
- if (ops.length === 1) return ops[0];
1492
- return new LogicalOperation(ops[0], "AND" /* AND */, ops[1]);
2369
+ return null;
1493
2370
  }
1494
- function buildMilestoningFilterOperationForDateRange(businessDateFrom, businessDateTo, processingDatetime, table, joinNode) {
1495
- const mc = table.milestoningColumns;
1496
- const ops = [];
1497
- const hasRange = businessDateFrom !== null && businessDateTo !== null;
1498
- const processingOp = (m) => {
1499
- const startAt = new DateTimeAttribute("start_at", m.startAtColumn.name, m.startAtColumn.type, m.startAtColumn.table.qualifiedName, joinNode);
1500
- const endAt = new DateTimeAttribute("end_at", m.endAtColumn.name, m.endAtColumn.type, m.endAtColumn.table.qualifiedName, joinNode);
1501
- return new LogicalOperation(startAt.lte(processingDatetime), "AND" /* AND */, openEndClause(endAt, processingDatetime, m.infiniteDatetime));
1502
- };
2371
+ function businessRangePredicate(mc, businessDateFrom, businessDateTo, joinNode) {
2372
+ if (businessDateFrom === null || businessDateTo === null) return null;
1503
2373
  if (mc instanceof BiTemporalColumns) {
1504
- if (hasRange) {
1505
- const dateFrom = new DateAttribute("business_date_from", mc.businessDateFromColumn.name, mc.businessDateFromColumn.type, mc.businessDateFromColumn.table.qualifiedName, joinNode);
1506
- const dateTo = new DateAttribute("business_date_to", mc.businessDateToColumn.name, mc.businessDateToColumn.type, mc.businessDateToColumn.table.qualifiedName, joinNode);
1507
- ops.push(new LogicalOperation(dateFrom.lte(businessDateTo), "AND" /* AND */, openEndClause(dateTo, businessDateFrom, mc.infiniteDatetime)));
1508
- }
1509
- if (processingDatetime !== null) ops.push(processingOp(mc));
1510
- } else if (mc instanceof BusinessDateAndProcessingTemporalColumns) {
1511
- if (hasRange) {
1512
- const businessAtt = new DateAttribute("business_date", mc.businessDateColumn.name, mc.businessDateColumn.type, mc.businessDateColumn.table.qualifiedName, joinNode);
1513
- ops.push(new LogicalOperation(businessAtt.gte(businessDateFrom), "AND" /* AND */, businessAtt.lte(businessDateTo)));
1514
- }
1515
- if (processingDatetime !== null) ops.push(processingOp(mc));
1516
- } else if (mc instanceof ProcessingTemporalColumns) {
1517
- if (processingDatetime !== null) ops.push(processingOp(mc));
1518
- } else if (mc instanceof SingleBusinessDateColumn && hasRange) {
2374
+ const dateFrom = new DateAttribute("business_date_from", mc.businessDateFromColumn.name, mc.businessDateFromColumn.type, mc.businessDateFromColumn.table.qualifiedName, joinNode);
2375
+ const dateTo = new DateAttribute("business_date_to", mc.businessDateToColumn.name, mc.businessDateToColumn.type, mc.businessDateToColumn.table.qualifiedName, joinNode);
2376
+ return new LogicalOperation(dateFrom.lte(businessDateTo), "AND" /* AND */, openEndClause(dateTo, businessDateFrom, mc.infiniteDatetime));
2377
+ }
2378
+ if (mc instanceof BusinessDateAndProcessingTemporalColumns || mc instanceof SingleBusinessDateColumn) {
1519
2379
  const businessAtt = new DateAttribute("business_date", mc.businessDateColumn.name, mc.businessDateColumn.type, mc.businessDateColumn.table.qualifiedName, joinNode);
1520
- ops.push(new LogicalOperation(businessAtt.gte(businessDateFrom), "AND" /* AND */, businessAtt.lte(businessDateTo)));
2380
+ return new LogicalOperation(businessAtt.gte(businessDateFrom), "AND" /* AND */, businessAtt.lte(businessDateTo));
1521
2381
  }
1522
- if (ops.length === 0) return null;
1523
- if (ops.length === 1) return ops[0];
1524
- return new LogicalOperation(ops[0], "AND" /* AND */, ops[1]);
2382
+ return null;
2383
+ }
2384
+ function buildMilestoningFilterOperation(businessDate, processingDatetime, table, joinNode) {
2385
+ const mc = table.milestoningColumns;
2386
+ return andAll([processingPredicate(mc, processingDatetime, joinNode), businessPredicate(mc, businessDate, joinNode)]);
2387
+ }
2388
+ function buildMilestoningFilterOperationForDateRange(businessDateFrom, businessDateTo, processingDatetime, table, joinNode) {
2389
+ const mc = table.milestoningColumns;
2390
+ return andAll([
2391
+ processingPredicate(mc, processingDatetime, joinNode),
2392
+ businessRangePredicate(mc, businessDateFrom, businessDateTo, joinNode)
2393
+ ]);
1525
2394
  }
1526
2395
  function walkRefs(op, visit, visitExists) {
1527
2396
  if (op === null || op === void 0) return;
@@ -1532,11 +2401,23 @@ function walkRefs(op, visit, visitExists) {
1532
2401
  } else if (op instanceof AggregateOperation) {
1533
2402
  walkRefs(op.element, visit, visitExists);
1534
2403
  if (op.window) walkWindowSpec(op.window, visit, visitExists);
2404
+ for (const sort of op.orderBy) walkRefs(sort, visit, visitExists);
1535
2405
  } else if (op instanceof WindowFunctionOperation) {
1536
2406
  if (op.element) walkRefs(op.element, visit, visitExists);
1537
2407
  if (op.window) walkWindowSpec(op.window, visit, visitExists);
1538
- } else if (op instanceof ScalarFunctionOperation || op instanceof DateExtractOperation || op instanceof DateArithmeticOperation || op instanceof DateDiffOperation || op instanceof IsNullOperation || op instanceof IsNotNullOperation) {
2408
+ } 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) {
1539
2409
  walkRefs(op.element, visit, visitExists);
2410
+ } else if (op instanceof Alias) {
2411
+ walkRefs(op.element, visit, visitExists);
2412
+ } else if (op instanceof ConcatOperation) {
2413
+ for (const part of op.parts) walkRefs(part, visit, visitExists);
2414
+ } else if (op instanceof ArithmeticOperation) {
2415
+ walkRefs(op.left, visit, visitExists);
2416
+ walkRefs(op.right, visit, visitExists);
2417
+ } else if (op instanceof CaseOperation) {
2418
+ walkRefs(op.condition, visit, visitExists);
2419
+ walkRefs(op.then, visit, visitExists);
2420
+ walkRefs(op.fallback, visit, visitExists);
1540
2421
  } else if (op instanceof SortOperation) {
1541
2422
  walkRefs(op.column, visit, visitExists);
1542
2423
  } else if (op instanceof LogicalOperation || op instanceof ComparisonOperation) {
@@ -1550,19 +2431,19 @@ function walkWindowSpec(window, visit, visitExists) {
1550
2431
  }
1551
2432
  function buildJoinFilterFromProperties(node, filter, columnMap) {
1552
2433
  const ops = [];
1553
- for (const [key, value] of Object.entries(filter)) {
2434
+ for (const [key, value2] of Object.entries(filter)) {
1554
2435
  const entry = columnMap[key];
1555
2436
  if (entry === void 0) {
1556
2437
  throw new Error(`Unknown property '${key}' \u2014 valid properties are: ${Object.keys(columnMap).sort().join(", ")}`);
1557
2438
  }
1558
2439
  const [name, type, table] = entry;
1559
2440
  const col = new ColumnWithJoin(new Column(name, type, table), node);
1560
- let constant;
1561
- if (typeof value === "boolean") constant = new BooleanConstantOperation(value);
1562
- else if (typeof value === "number") constant = Number.isInteger(value) ? new IntegerConstantOperation(value) : new FloatConstantOperation(value);
1563
- else if (value instanceof Date) constant = type.toUpperCase() === "DATE" ? new DateConstantOperation(value) : new DateTimeConstantOperation(value);
1564
- else constant = new StringConstantOperation(String(value));
1565
- ops.push(new ComparisonOperation(col, "EQUAL" /* EQUAL */, constant));
2441
+ let constant2;
2442
+ if (typeof value2 === "boolean") constant2 = new BooleanConstantOperation(value2);
2443
+ else if (typeof value2 === "number") constant2 = Number.isInteger(value2) ? new IntegerConstantOperation(value2) : new FloatConstantOperation(value2);
2444
+ else if (value2 instanceof Date) constant2 = type.toUpperCase() === "DATE" ? new DateConstantOperation(value2) : new DateTimeConstantOperation(value2);
2445
+ else constant2 = new StringConstantOperation(String(value2));
2446
+ ops.push(new ComparisonOperation(col, "EQUAL" /* EQUAL */, constant2));
1566
2447
  }
1567
2448
  return ops.reduce((acc, op) => new LogicalOperation(acc, "AND" /* AND */, op));
1568
2449
  }
@@ -1576,7 +2457,7 @@ function withAncestors(nodes) {
1576
2457
  for (const node of nodes) add(node);
1577
2458
  return [...ordered];
1578
2459
  }
1579
- function buildQueryOperation(businessDate, processingDatetime, columns, table, op, orderBy = [], groupBy = [], limit, businessDateTo = null) {
2460
+ function buildQueryOperation(businessDate, processingDatetime, columns, table, op, orderBy = [], groupBy = [], limit, businessDateTo = null, distinct = false, offset, having) {
1580
2461
  let filter = op;
1581
2462
  const milestoningFor = (t, node) => businessDateTo !== null ? buildMilestoningFilterOperationForDateRange(businessDate, businessDateTo, processingDatetime, t, node) : buildMilestoningFilterOperation(businessDate, processingDatetime, t, node);
1582
2463
  if (table instanceof MilestonedTable) {
@@ -1609,22 +2490,45 @@ function buildQueryOperation(businessDate, processingDatetime, columns, table, o
1609
2490
  }
1610
2491
  if (combined !== void 0) joinFilters.set(node, combined);
1611
2492
  }
1612
- return new SelectOperation(columns, filter, orderBy, groupBy, limit, table, joinFilters);
2493
+ return new SelectOperation(columns, filter, orderBy, groupBy, limit, table, joinFilters, distinct, offset, having);
2494
+ }
2495
+ function needsParentheses(parent, child) {
2496
+ return child instanceof LogicalOperation && child.operator !== parent.operator;
2497
+ }
2498
+ function reachesToMany(op) {
2499
+ if (op instanceof ColumnWithJoin) {
2500
+ for (let node = op.parent; node !== void 0; node = node.parent) if (node.many) return true;
2501
+ return false;
2502
+ }
2503
+ if (op instanceof UnaryOperation || op instanceof Alias) return reachesToMany(op.element);
2504
+ if (op instanceof BinaryOperation) return reachesToMany(op.left) || reachesToMany(op.right);
2505
+ return false;
2506
+ }
2507
+ function unaliased(op) {
2508
+ return op instanceof Alias ? unaliased(op.element) : op;
1613
2509
  }
1614
2510
  var SQLQueryGenerator = class {
2511
+ constructor(_dialect) {
2512
+ this._dialect = _dialect;
2513
+ }
2514
+ _dialect;
1615
2515
  _select = [];
1616
2516
  _from = /* @__PURE__ */ new Set();
1617
2517
  _join = [];
1618
2518
  _groupByParts = [];
2519
+ _having = "";
1619
2520
  _orderByParts = [];
1620
2521
  _where = "";
1621
2522
  _limit;
2523
+ _distinct = false;
2524
+ _offset;
1622
2525
  _tableAliasIncr = 0;
1623
2526
  _tableAliasesByTable = /* @__PURE__ */ new Map();
1624
2527
  _addedJoinIds = /* @__PURE__ */ new Set();
1625
2528
  _rootTable;
1626
2529
  _elidableNodes = /* @__PURE__ */ new Set();
1627
2530
  _joinFilters = /* @__PURE__ */ new Map();
2531
+ _guardOptional = true;
1628
2532
  generate(select) {
1629
2533
  this._rootTable = select.table;
1630
2534
  this._elidableNodes = this._computeElidableNodes(select);
@@ -1641,11 +2545,52 @@ var SQLQueryGenerator = class {
1641
2545
  for (const node of groupByJoins.values()) {
1642
2546
  this._addJoin(node);
1643
2547
  }
1644
- this._groupByParts = select.groupBy.map((a) => this._attrToColString(a));
2548
+ this._groupByParts = this._groupByPartsFor(select);
2549
+ this._having = "";
2550
+ if (select.having !== void 0) {
2551
+ const havingJoins = /* @__PURE__ */ new Map();
2552
+ this._collectRequiredJoins(select.having, havingJoins);
2553
+ for (const node of havingJoins.values()) this._addJoin(node);
2554
+ this._guardOptional = false;
2555
+ try {
2556
+ this._having = this.buildFilter(select.having);
2557
+ } finally {
2558
+ this._guardOptional = true;
2559
+ }
2560
+ }
1645
2561
  this._orderByParts = select.orderBy.map(
1646
- (s) => this.buildFilter(s.column) + (s.direction === "ASC" /* ASC */ ? " ASC" : " DESC")
2562
+ (s) => this._sortExpression(s.column) + this._dialect.orderDirection(s.direction)
1647
2563
  );
1648
2564
  this._limit = select.limit;
2565
+ this._distinct = select.distinct;
2566
+ this._offset = select.offset;
2567
+ }
2568
+ /**
2569
+ * The GROUP BY of a query: the grouping it was given, else the grouping its columns imply.
2570
+ *
2571
+ * Columns that are not aggregated are what the aggregates are computed for, so a query that selects both is
2572
+ * grouped by those columns (as a DataFrame's `groupby(columns).agg(...)` does). An aggregate read through a
2573
+ * to-many association is computed for each row of the root table, as Legend does, so the root's primary key
2574
+ * is grouped by too. A query that selects only aggregates over the root's own columns is not grouped: the
2575
+ * aggregate covers every row. A constant needs no grouping: a bare
2576
+ * `GROUP BY 7` would be a column position.
2577
+ */
2578
+ _groupByPartsFor(select) {
2579
+ if (select.groupBy.length > 0) return select.groupBy.map((a) => this._attrToColString(a));
2580
+ const aggregates = select.display.filter(containsAggregate);
2581
+ if (aggregates.length === 0) return [];
2582
+ const perRoot = select.table !== void 0 && aggregates.some(reachesToMany);
2583
+ const keys = perRoot ? select.table.columns.filter((c) => c.primaryKey).map((c) => this._columnToString(c)) : [];
2584
+ 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));
2585
+ return [.../* @__PURE__ */ new Set([...keys, ...grouped])];
2586
+ }
2587
+ /** What a sort orders by: a column, or an expression such as an aggregate. */
2588
+ _sortExpression(expression) {
2589
+ if (expression instanceof ColumnWithJoin || expression instanceof Attribute) return this.buildFilter(expression);
2590
+ return sqlOperationToString(this._rewriteOperation(expression), this._dialect);
2591
+ }
2592
+ _columnToString(column) {
2593
+ return this._tableAliasForTable(column.owner, column.owner).alias + "." + column.name;
1649
2594
  }
1650
2595
  _attrToColString(attr) {
1651
2596
  const { column, parent } = this._resolve(attr);
@@ -1692,6 +2637,13 @@ var SQLQueryGenerator = class {
1692
2637
  }
1693
2638
  return { column, parent };
1694
2639
  }
2640
+ /** Whether the value `op` reads can be missing, in the join or embedded form that is used for it. */
2641
+ _resolveOptional(op) {
2642
+ if (op.parent !== void 0 && this._elidableNodes.has(op.parent) && op.embedded !== void 0) {
2643
+ return this._resolveOptional(op.embedded);
2644
+ }
2645
+ return op.optional;
2646
+ }
1695
2647
  _rewriteWindowSpec(window) {
1696
2648
  const partitionBy = window.partitionBy.map((p) => this._rewriteOperation(p));
1697
2649
  const orderBy = window.orderBy.map((s) => new SortOperation(this._rewriteOperation(s.column), s.direction));
@@ -1711,9 +2663,17 @@ var SQLQueryGenerator = class {
1711
2663
  this._rewriteOperation(op.element),
1712
2664
  op.operator,
1713
2665
  op.displayName,
1714
- op.window ? this._rewriteWindowSpec(op.window) : void 0
2666
+ op.window ? this._rewriteWindowSpec(op.window) : void 0,
2667
+ op.separator,
2668
+ op.orderBy.map((s) => new SortOperation(this._rewriteOperation(s.column), s.direction))
1715
2669
  );
1716
2670
  }
2671
+ if (op instanceof CaseOperation) return new RenderedSql(this._caseSql(op));
2672
+ if (isCondition(op)) return new RenderedSql(this.buildFilter(op));
2673
+ if (op instanceof ConcatOperation) return new ConcatOperation(op.parts.map((part) => this._rewriteOperation(part)), op.displayName);
2674
+ if (op instanceof ArithmeticOperation) {
2675
+ return new ArithmeticOperation(this._rewriteOperation(op.left), op.operator, this._rewriteOperation(op.right), op.displayName);
2676
+ }
1717
2677
  if (op instanceof WindowFunctionOperation) {
1718
2678
  const el = op.element ? this._rewriteOperation(op.element) : null;
1719
2679
  return new WindowFunctionOperation(
@@ -1731,6 +2691,9 @@ var SQLQueryGenerator = class {
1731
2691
  if (op instanceof DateExtractOperation) {
1732
2692
  return new DateExtractOperation(this._rewriteOperation(op.element), op.part, op.displayName);
1733
2693
  }
2694
+ if (op instanceof DateTruncOperation) {
2695
+ return new DateTruncOperation(this._rewriteOperation(op.element), op.part, op.displayName);
2696
+ }
1734
2697
  if (op instanceof DateArithmeticOperation) {
1735
2698
  return new DateArithmeticOperation(this._rewriteOperation(op.element), op.n, op.unit, op.isAdd, op.displayName);
1736
2699
  }
@@ -1739,6 +2702,13 @@ var SQLQueryGenerator = class {
1739
2702
  }
1740
2703
  return op;
1741
2704
  }
2705
+ /** The CASE written out now: its condition can only be rendered while the query is being built. */
2706
+ _caseSql(op) {
2707
+ const branch = (value2) => value2 instanceof ConstantOperation ? constantValueString(value2, this._dialect) : sqlOperationToString(this._rewriteOperation(value2), this._dialect);
2708
+ let sql = "CASE WHEN " + this.buildFilter(op.condition) + " THEN " + branch(op.then);
2709
+ if (op.fallback !== void 0) sql += " ELSE " + branch(op.fallback);
2710
+ return sql + " END";
2711
+ }
1742
2712
  processSelect(cols) {
1743
2713
  const requiredJoins = /* @__PURE__ */ new Map();
1744
2714
  for (const col of cols) {
@@ -1747,88 +2717,96 @@ var SQLQueryGenerator = class {
1747
2717
  for (const node of requiredJoins.values()) {
1748
2718
  this._addJoin(node);
1749
2719
  }
1750
- for (const col of cols) {
1751
- if (col instanceof Attribute) {
1752
- const { column, parent: node } = this._resolve(col);
1753
- let ta;
1754
- if (node !== void 0) {
1755
- ta = this._tableAliasForTable(column.owner, node);
1756
- } else {
1757
- ta = this._tableAliasForTable(column.owner, column.owner);
1758
- this._from.add(ta);
1759
- }
1760
- this._select.push(new Alias(new TableAliasColumn(column, ta), col.displayName()));
1761
- } else if (col instanceof WindowFunctionOperation) {
1762
- const rewritten = this._rewriteOperation(col);
1763
- let alias;
1764
- if (col.displayName) {
1765
- alias = col.displayName;
1766
- } else if (["ROW_NUMBER" /* ROW_NUMBER */, "RANK" /* RANK */, "DENSE_RANK" /* DENSE_RANK */].includes(col.func)) {
1767
- alias = col.func.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
1768
- } else if (col.element) {
1769
- alias = col.func + " " + findColumn(col).column.name;
1770
- } else {
1771
- alias = col.func;
1772
- }
1773
- this._select.push(new Alias(rewritten, alias));
1774
- } else if (col instanceof AggregateOperation) {
1775
- const colNested = this._resolve(findColumn(col));
1776
- const node = colNested.parent;
1777
- let ta;
1778
- if (node !== void 0) {
1779
- ta = this._tableAliasForTable(colNested.column.owner, node);
1780
- } else {
1781
- ta = this._tableAliasForTable(colNested.column.owner, colNested.column.owner);
1782
- this._from.add(ta);
1783
- }
1784
- const alias = col.displayName ?? col.operator + " " + findColumn(col).column.name;
1785
- const rewrittenAgg = new AggregateOperation(
1786
- new TableAliasColumn(colNested.column, ta),
1787
- col.operator,
1788
- void 0,
1789
- col.window ? this._rewriteWindowSpec(col.window) : void 0
1790
- );
1791
- this._select.push(new Alias(rewrittenAgg, alias));
1792
- } else if (col instanceof ScalarFunctionOperation) {
1793
- const colNested = this._resolve(findColumn(col));
1794
- const node = colNested.parent;
1795
- let ta;
1796
- if (node !== void 0) {
1797
- ta = this._tableAliasForTable(colNested.column.owner, node);
1798
- } else {
1799
- ta = this._tableAliasForTable(colNested.column.owner, colNested.column.owner);
1800
- this._from.add(ta);
1801
- }
1802
- const alias = col.displayName ?? col.func + " " + findColumn(col).column.name;
1803
- this._select.push(new Alias(
1804
- new ScalarFunctionOperation(new TableAliasColumn(colNested.column, ta), col.func, void 0, col.secondArg, col.extraArgs),
1805
- alias
1806
- ));
1807
- } else if (col instanceof DateExtractOperation || col instanceof DateArithmeticOperation || col instanceof DateDiffOperation) {
1808
- const colNested = this._resolve(findColumn(col));
1809
- const node = colNested.parent;
1810
- let ta;
1811
- if (node !== void 0) {
1812
- ta = this._tableAliasForTable(colNested.column.owner, node);
1813
- } else {
1814
- ta = this._tableAliasForTable(colNested.column.owner, colNested.column.owner);
1815
- this._from.add(ta);
1816
- }
1817
- const alias = col.displayName ?? findColumn(col).column.name;
1818
- let aliasedOp;
1819
- if (col instanceof DateExtractOperation) {
1820
- aliasedOp = new DateExtractOperation(new TableAliasColumn(colNested.column, ta), col.part);
1821
- } else if (col instanceof DateArithmeticOperation) {
1822
- aliasedOp = new DateArithmeticOperation(new TableAliasColumn(colNested.column, ta), col.n, col.unit, col.isAdd);
1823
- } else {
1824
- aliasedOp = new DateDiffOperation(new TableAliasColumn(colNested.column, ta), col.other, col.unit);
1825
- }
1826
- this._select.push(new Alias(aliasedOp, alias));
1827
- } else if (col instanceof CountAllOperation) {
1828
- const ta = this._tableAliasForTable(col.table, col.table);
2720
+ for (const col of cols) this._selectColumn(col);
2721
+ }
2722
+ /** Add one column to the select list. An alias reads the column it wraps, then names the entry. */
2723
+ _selectColumn(col) {
2724
+ if (col instanceof Alias) {
2725
+ this._selectColumn(col.element);
2726
+ const read = this._select.pop();
2727
+ this._select.push(new Alias(read.element, col.name));
2728
+ } else if (col instanceof Attribute) {
2729
+ const { column, parent: node } = this._resolve(col);
2730
+ let ta;
2731
+ if (node !== void 0) {
2732
+ ta = this._tableAliasForTable(column.owner, node);
2733
+ } else {
2734
+ ta = this._tableAliasForTable(column.owner, column.owner);
2735
+ this._from.add(ta);
2736
+ }
2737
+ this._select.push(new Alias(new TableAliasColumn(column, ta), col.displayName()));
2738
+ } else if (col instanceof WindowFunctionOperation) {
2739
+ const rewritten = this._rewriteOperation(col);
2740
+ let alias;
2741
+ if (col.displayName) {
2742
+ alias = col.displayName;
2743
+ } else if (["ROW_NUMBER" /* ROW_NUMBER */, "RANK" /* RANK */, "DENSE_RANK" /* DENSE_RANK */].includes(col.func)) {
2744
+ alias = col.func.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
2745
+ } else if (col.element) {
2746
+ alias = col.func + " " + findColumn(col).column.name;
2747
+ } else {
2748
+ alias = col.func;
2749
+ }
2750
+ this._select.push(new Alias(rewritten, alias));
2751
+ } else if (col instanceof AggregateOperation && !(col.element instanceof ColumnWithJoin)) {
2752
+ this._select.push(new Alias(this._rewriteOperation(col), col.displayName ?? "Expression"));
2753
+ } else if (col instanceof AggregateOperation) {
2754
+ const colNested = this._resolve(findColumn(col));
2755
+ const node = colNested.parent;
2756
+ let ta;
2757
+ if (node !== void 0) {
2758
+ ta = this._tableAliasForTable(colNested.column.owner, node);
2759
+ } else {
2760
+ ta = this._tableAliasForTable(colNested.column.owner, colNested.column.owner);
2761
+ this._from.add(ta);
2762
+ }
2763
+ const alias = col.displayName ?? col.operator + " " + findColumn(col).column.name;
2764
+ const rewrittenAgg = new AggregateOperation(
2765
+ new TableAliasColumn(colNested.column, ta),
2766
+ col.operator,
2767
+ void 0,
2768
+ col.window ? this._rewriteWindowSpec(col.window) : void 0,
2769
+ col.separator,
2770
+ col.orderBy.map((s) => new SortOperation(this._rewriteOperation(s.column), s.direction))
2771
+ );
2772
+ this._select.push(new Alias(rewrittenAgg, alias));
2773
+ } else if (col instanceof ScalarFunctionOperation) {
2774
+ this._select.push(new Alias(this._rewriteOperation(col), col.displayName ?? col.func + " " + findColumn(col).column.name));
2775
+ } else if (col instanceof DateExtractOperation || col instanceof DateArithmeticOperation || col instanceof DateDiffOperation) {
2776
+ const colNested = this._resolve(findColumn(col));
2777
+ const node = colNested.parent;
2778
+ let ta;
2779
+ if (node !== void 0) {
2780
+ ta = this._tableAliasForTable(colNested.column.owner, node);
2781
+ } else {
2782
+ ta = this._tableAliasForTable(colNested.column.owner, colNested.column.owner);
1829
2783
  this._from.add(ta);
1830
- this._select.push(new Alias(col, "Count"));
1831
2784
  }
2785
+ const alias = col.displayName ?? findColumn(col).column.name;
2786
+ let aliasedOp;
2787
+ if (col instanceof DateExtractOperation) {
2788
+ aliasedOp = new DateExtractOperation(new TableAliasColumn(colNested.column, ta), col.part);
2789
+ } else if (col instanceof DateArithmeticOperation) {
2790
+ aliasedOp = new DateArithmeticOperation(new TableAliasColumn(colNested.column, ta), col.n, col.unit, col.isAdd);
2791
+ } else {
2792
+ aliasedOp = new DateDiffOperation(new TableAliasColumn(colNested.column, ta), col.other, col.unit);
2793
+ }
2794
+ this._select.push(new Alias(aliasedOp, alias));
2795
+ } else if (col instanceof CaseOperation) {
2796
+ this._select.push(new Alias(this._rewriteOperation(col), col.displayName ?? "Expression"));
2797
+ } else if (col instanceof ConcatOperation) {
2798
+ this._select.push(new Alias(this._rewriteOperation(col), col.displayName ?? "Expression"));
2799
+ } else if (col instanceof ArithmeticOperation) {
2800
+ this._select.push(new Alias(this._rewriteOperation(col), col.displayName ?? "Expression"));
2801
+ } else if (col instanceof DateTruncOperation) {
2802
+ this._select.push(new Alias(this._rewriteOperation(col), col.displayName ?? findColumn(col).column.name));
2803
+ } else if (isCondition(col)) {
2804
+ this._select.push(new Alias(new RenderedSql(this.buildFilter(col)), "Expression"));
2805
+ } else if (col instanceof ConstantOperation) {
2806
+ this._select.push(new Alias(col, "Constant"));
2807
+ } else if (col instanceof CountAllOperation) {
2808
+ if (col.table !== "") this._from.add(this._tableAliasForTable(col.table, col.table));
2809
+ this._select.push(new Alias(col, "Count"));
1832
2810
  }
1833
2811
  }
1834
2812
  _addJoin(node) {
@@ -1856,19 +2834,43 @@ var SQLQueryGenerator = class {
1856
2834
  const col = op.node.join.right;
1857
2835
  return this.buildFilter(new ColumnWithJoin(col, op.node)) + " IS NULL";
1858
2836
  }
2837
+ if (op instanceof InOperation) {
2838
+ return this.buildFilter(op.element) + " IN (" + op.values.map((value2) => constantValueString(value2, this._dialect)).join(", ") + ")";
2839
+ }
2840
+ if (op instanceof NotInOperation) {
2841
+ const column = this.buildFilter(op.element);
2842
+ const sql = column + " NOT IN (" + op.values.map((value2) => constantValueString(value2, this._dialect)).join(", ") + ")";
2843
+ if (op.element instanceof ColumnWithJoin && this._resolve(op.element).column.nullable) {
2844
+ return "(" + sql + " OR " + column + " IS NULL)";
2845
+ }
2846
+ return sql;
2847
+ }
1859
2848
  if (op instanceof IsNotNullOperation) return this.buildFilter(op.element) + " IS NOT NULL";
1860
2849
  if (op instanceof IsNullOperation) return this.buildFilter(op.element) + " IS NULL";
1861
2850
  if (op instanceof LogicalOperation) {
1862
2851
  let left = this.buildFilter(op.left);
1863
2852
  let right = this.buildFilter(op.right);
1864
- if (op.left instanceof LogicalOperation) left = "(" + left + ")";
1865
- if (op.right instanceof LogicalOperation) right = "(" + right + ")";
2853
+ if (needsParentheses(op, op.left)) left = "(" + left + ")";
2854
+ if (needsParentheses(op, op.right)) right = "(" + right + ")";
1866
2855
  return left + LOGICAL_OPERATOR_STR[op.operator] + right;
1867
2856
  }
1868
2857
  if (op instanceof ComparisonOperation) {
1869
- return this.buildFilter(op.left) + COMPARISON_OPERATOR_STR[op.operator] + this.buildFilter(op.right);
2858
+ let sql = this.buildFilter(op.left) + COMPARISON_OPERATOR_STR[op.operator] + this.buildFilter(op.right);
2859
+ 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("\\"))) {
2860
+ sql += " ESCAPE '" + LIKE_ESCAPE + "'";
2861
+ }
2862
+ if (this._guardOptional && GUARDED_COMPARISONS.has(op.operator) && op.left instanceof ColumnWithJoin && this._resolveOptional(op.left)) {
2863
+ sql = "(" + this.buildFilter(op.left) + " IS NOT NULL AND " + sql + ")";
2864
+ }
2865
+ return sql;
2866
+ }
2867
+ if (op instanceof ConstantOperation) return constantValueString(op, this._dialect);
2868
+ if (op instanceof ScalarFunctionOperation || op instanceof ArithmeticOperation || op instanceof ConcatOperation || op instanceof DateTruncOperation || op instanceof AggregateOperation || op instanceof CountAllOperation) {
2869
+ const required = /* @__PURE__ */ new Map();
2870
+ this._collectRequiredJoins(op, required);
2871
+ for (const node of required.values()) this._addJoin(node);
2872
+ return sqlOperationToString(this._rewriteOperation(op), this._dialect);
1870
2873
  }
1871
- if (op instanceof ConstantOperation) return constantValueString(op);
1872
2874
  if (op instanceof ColumnWithJoin) {
1873
2875
  const { column, parent: node } = this._resolve(op);
1874
2876
  let ta;
@@ -1896,9 +2898,9 @@ var SQLQueryGenerator = class {
1896
2898
  }
1897
2899
  buildQueryString() {
1898
2900
  const joins = this._join.map(
1899
- (j) => " LEFT OUTER JOIN " + j.target.tableAlias.table + " AS " + j.target.tableAlias.alias + " ON " + j.source.tableAlias.alias + "." + j.source.column.name + " = " + j.target.tableAlias.alias + "." + j.target.column.name + (j.filterOp ? " AND " + this.buildFilter(j.filterOp) : "")
2901
+ (j) => " LEFT OUTER JOIN " + j.target.tableAlias.table + " AS " + j.target.tableAlias.alias + " ON (" + j.condition() + (j.filterOp ? " AND " + this.buildFilter(j.filterOp) : "") + ")"
1900
2902
  );
1901
- 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();
2903
+ 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();
1902
2904
  }
1903
2905
  _buildWhere() {
1904
2906
  return this._where.length > 0 ? " WHERE " + this._where : "";
@@ -1906,26 +2908,32 @@ var SQLQueryGenerator = class {
1906
2908
  _buildGroupBy() {
1907
2909
  return this._groupByParts.length > 0 ? " GROUP BY " + this._groupByParts.join(", ") : "";
1908
2910
  }
2911
+ _buildHaving() {
2912
+ return this._having.length > 0 ? " HAVING " + this._having : "";
2913
+ }
1909
2914
  _buildOrderBy() {
1910
2915
  return this._orderByParts.length > 0 ? " ORDER BY " + this._orderByParts.join(", ") : "";
1911
2916
  }
2917
+ _buildOffset() {
2918
+ return this._offset !== void 0 ? " OFFSET " + this._offset : "";
2919
+ }
1912
2920
  _buildLimit() {
1913
2921
  return this._limit !== void 0 ? " LIMIT " + this._limit : "";
1914
2922
  }
1915
2923
  };
1916
- function selectSqlToString(selectOperation) {
1917
- const qg = new SQLQueryGenerator();
2924
+ function selectSqlToString(selectOperation, dialect = "postgres") {
2925
+ const qg = new SQLQueryGenerator(dialectOf(dialect));
1918
2926
  qg.generate(selectOperation);
1919
2927
  return qg.buildQueryString();
1920
2928
  }
1921
- function toSql(businessDate, processingDatetime, columns, table, op, orderBy = [], groupBy = [], limit, businessDateTo = null) {
1922
- const selectOp = buildQueryOperation(businessDate, processingDatetime, columns, table, op, orderBy, groupBy, limit, businessDateTo);
1923
- return selectSqlToString(selectOp);
2929
+ function toSql(businessDate, processingDatetime, columns, table, op, orderBy = [], groupBy = [], limit, businessDateTo = null, distinct = false, offset, having, dialect = "postgres") {
2930
+ const selectOp = buildQueryOperation(businessDate, processingDatetime, columns, table, op, orderBy, groupBy, limit, businessDateTo, distinct, offset, having);
2931
+ return selectSqlToString(selectOp, dialect);
1924
2932
  }
1925
2933
 
1926
2934
  // src/datafinder/naming.ts
1927
- function titleCase(value) {
1928
- return value.replace(/[A-Za-z]+/g, (w) => w[0].toUpperCase() + w.slice(1).toLowerCase());
2935
+ function titleCase(value2) {
2936
+ return value2.replace(/[A-Za-z]+/g, (w) => w[0].toUpperCase() + w.slice(1).toLowerCase());
1929
2937
  }
1930
2938
 
1931
2939
  // src/datafinder/embedded.ts
@@ -1973,6 +2981,18 @@ function getRunner() {
1973
2981
  if (!_runner) throw new Error("No query runner registered. Call registerRunner() first.");
1974
2982
  return _runner;
1975
2983
  }
2984
+ var expressionIds = /* @__PURE__ */ new WeakMap();
2985
+ var nextExpressionId = 1;
2986
+ function sortTarget(sort) {
2987
+ const column = sort.column;
2988
+ if (!(column instanceof ColumnWithJoin)) {
2989
+ if (!expressionIds.has(column)) expressionIds.set(column, nextExpressionId++);
2990
+ return JSON.stringify(["expression", expressionIds.get(column)]);
2991
+ }
2992
+ const joins = [];
2993
+ for (let node = column.parent; node !== void 0; node = node.parent) joins.push(node.join.name);
2994
+ return JSON.stringify([column.column.owner, column.column.name, joins]);
2995
+ }
1976
2996
  var FinderResult = class {
1977
2997
  constructor(_businessDate, _processingDatetime, _columns, _table, _op, _businessDateTo = null) {
1978
2998
  this._businessDate = _businessDate;
@@ -1991,12 +3011,20 @@ var FinderResult = class {
1991
3011
  _orderBy = [];
1992
3012
  _groupBy = [];
1993
3013
  _limit;
3014
+ _distinct = false;
3015
+ _offset;
3016
+ _having;
1994
3017
  _timeoutMs = DEFAULT_TIMEOUT_MS;
1995
- orderByOp(...sorts) {
1996
- this._orderBy = sorts;
3018
+ /**
3019
+ * Order the rows. Calls accumulate: the sorts of the latest call take priority and earlier ones order the
3020
+ * rows it leaves tied, as in a chain of `sortBy` calls. Sorting a column again replaces its earlier direction.
3021
+ */
3022
+ orderBy(...sorts) {
3023
+ const resorted = new Set(sorts.map(sortTarget));
3024
+ this._orderBy = [...sorts, ...this._orderBy.filter((s) => !resorted.has(sortTarget(s)))];
1997
3025
  return this;
1998
3026
  }
1999
- groupByOp(...attrs) {
3027
+ groupBy(...attrs) {
2000
3028
  this._groupBy = attrs;
2001
3029
  return this;
2002
3030
  }
@@ -2004,12 +3032,40 @@ var FinderResult = class {
2004
3032
  this._limit = n;
2005
3033
  return this;
2006
3034
  }
3035
+ /** Skip the first `n` rows. Sort the rows first: without an order, which rows are first is not defined. */
3036
+ offset(n) {
3037
+ if (!Number.isInteger(n) || n < 0) throw new Error("offset cannot be negative");
3038
+ this._offset = n;
3039
+ return this;
3040
+ }
3041
+ /** Rows `start` up to but not including `stop`, counting from 0: `offset(start).limit(stop - start)`. */
3042
+ slice(start, stop) {
3043
+ if (!Number.isInteger(start) || !Number.isInteger(stop) || start < 0 || stop < start) {
3044
+ throw new Error("slice needs 0 <= start <= stop");
3045
+ }
3046
+ return this.offset(start).limit(stop - start);
3047
+ }
3048
+ /**
3049
+ * Keep the groups for which every condition holds: `HAVING`. A condition tests an aggregate or a grouping column:
3050
+ * `f.findAll(null, null, [f.category(), countAll()]).groupBy(f.category()).having(countAll().gt(1))`.
3051
+ * Calls accumulate, as `and` does.
3052
+ */
3053
+ having(...conditions) {
3054
+ for (const condition of conditions) this._having = this._having === void 0 ? condition : this._having.and(condition);
3055
+ return this;
3056
+ }
3057
+ /** Return each distinct row once: `SELECT DISTINCT`. A sort on a distinct query has to use a selected column. */
3058
+ distinct() {
3059
+ this._distinct = true;
3060
+ return this;
3061
+ }
2007
3062
  /** Abort the query and throw QueryTimeoutError if it runs longer than `milliseconds` (default 60000). */
2008
3063
  timeout(milliseconds) {
2009
3064
  this._timeoutMs = milliseconds;
2010
3065
  return this;
2011
3066
  }
2012
- toSql() {
3067
+ /** The query as SQL, in Postgres unless a dialect is given: `toSql('databricks')`. Nothing is run. */
3068
+ toSql(dialect = "postgres") {
2013
3069
  return toSql(
2014
3070
  this._businessDate,
2015
3071
  this._processingDatetime,
@@ -2019,7 +3075,11 @@ var FinderResult = class {
2019
3075
  this._orderBy,
2020
3076
  this._groupBy,
2021
3077
  this._limit,
2022
- this._businessDateTo
3078
+ this._businessDateTo,
3079
+ this._distinct,
3080
+ this._offset,
3081
+ this._having,
3082
+ dialect
2023
3083
  );
2024
3084
  }
2025
3085
  async toRows() {
@@ -2033,24 +3093,31 @@ var FinderResult = class {
2033
3093
  this._groupBy,
2034
3094
  this._limit,
2035
3095
  this._timeoutMs,
2036
- this._businessDateTo
3096
+ this._businessDateTo,
3097
+ this._distinct,
3098
+ this._offset,
3099
+ this._having
2037
3100
  );
2038
3101
  }
2039
3102
  };
2040
- function convertDate(value) {
2041
- if (value === null) return null;
2042
- if (value instanceof Date) return value;
2043
- let normalized = value;
2044
- if (/^\d{4}-\d{2}-\d{2}$/.test(value)) normalized = value + "T00:00:00Z";
2045
- else if (/^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}(:\d{2}(\.\d+)?)?$/.test(value)) normalized = value.replace(" ", "T") + "Z";
3103
+ function convertProcessingDate(value2) {
3104
+ if (typeof value2 === "string" && DATE_ONLY_PATTERN.test(value2)) return new DateOnly(value2 + "T00:00:00Z");
3105
+ return convertDate(value2);
3106
+ }
3107
+ function convertDate(value2) {
3108
+ if (value2 === null) return null;
3109
+ if (value2 instanceof Date) return value2;
3110
+ let normalized = value2;
3111
+ if (DATE_ONLY_PATTERN.test(value2)) normalized = value2 + "T00:00:00Z";
3112
+ else if (/^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}(:\d{2}(\.\d+)?)?$/.test(value2)) normalized = value2.replace(" ", "T") + "Z";
2046
3113
  const d = new Date(normalized);
2047
- if (isNaN(d.getTime())) throw new Error(`Cannot parse date: ${value}`);
3114
+ if (isNaN(d.getTime())) throw new Error(`Cannot parse date: ${value2}`);
2048
3115
  return d;
2049
3116
  }
2050
3117
  function convertInputsAndSelect(businessDate, processingDatetime, columns, table, op = new NoOperation()) {
2051
3118
  return new FinderResult(
2052
3119
  convertDate(businessDate),
2053
- convertDate(processingDatetime),
3120
+ convertProcessingDate(processingDatetime),
2054
3121
  columns,
2055
3122
  table,
2056
3123
  op
@@ -2062,42 +3129,223 @@ function convertInputsAndSelectForDateRange(businessDateFrom, businessDateTo, pr
2062
3129
  if (processingDatetime == null) throw new Error("processingValidAt is required for findForDateRange");
2063
3130
  return new FinderResult(
2064
3131
  convertDate(businessDateFrom),
2065
- convertDate(processingDatetime),
3132
+ convertProcessingDate(processingDatetime),
2066
3133
  columns,
2067
3134
  table,
2068
3135
  op,
2069
3136
  convertDate(businessDateTo)
2070
3137
  );
2071
3138
  }
3139
+
3140
+ // src/datafinder/databricks-runner.ts
3141
+ var DatabricksQueryError = class extends Error {
3142
+ constructor(message, code, statementId) {
3143
+ super(message);
3144
+ this.code = code;
3145
+ this.statementId = statementId;
3146
+ this.name = "DatabricksQueryError";
3147
+ }
3148
+ code;
3149
+ statementId;
3150
+ };
3151
+ var API = "/api/2.0/sql/statements";
3152
+ var MAX_SAFE = BigInt(Number.MAX_SAFE_INTEGER);
3153
+ function convertValue(text, typeName) {
3154
+ if (text === null || text === void 0) return null;
3155
+ switch ((typeName ?? "").toUpperCase()) {
3156
+ case "BYTE":
3157
+ case "SHORT":
3158
+ case "INT":
3159
+ return Number(text);
3160
+ case "LONG": {
3161
+ const value2 = BigInt(text);
3162
+ return value2 >= -MAX_SAFE && value2 <= MAX_SAFE ? Number(value2) : value2;
3163
+ }
3164
+ case "FLOAT":
3165
+ case "DOUBLE":
3166
+ case "DECIMAL":
3167
+ return Number(text);
3168
+ case "BOOLEAN":
3169
+ return text.toLowerCase() === "true";
3170
+ case "DATE":
3171
+ return new DateOnly(text + "T00:00:00Z");
3172
+ case "TIMESTAMP":
3173
+ case "TIMESTAMP_NTZ": {
3174
+ const zoned = /(Z|[+-]\d{2}:?\d{2})$/.test(text);
3175
+ return new Date(zoned ? text : text.replace(" ", "T") + "Z");
3176
+ }
3177
+ default:
3178
+ return text;
3179
+ }
3180
+ }
3181
+ var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
3182
+ var DatabricksConnect = class {
3183
+ constructor(config) {
3184
+ this.config = config;
3185
+ if (!config.host) throw new Error("DatabricksConnect needs the host of a workspace, or of a server in front of it");
3186
+ if (!config.warehouseId) throw new Error("DatabricksConnect needs the id of a SQL warehouse");
3187
+ }
3188
+ config;
3189
+ dialect = "databricks";
3190
+ /** Names of the columns of the last query that returned. */
3191
+ lastColumns = [];
3192
+ async select(businessDate, processingDatetime, columns, table, op, orderBy, groupBy, limit, timeoutMs = DEFAULT_TIMEOUT_MS, businessDateTo = null, distinct = false, offset, having) {
3193
+ const statement = toSql(
3194
+ businessDate,
3195
+ processingDatetime,
3196
+ columns,
3197
+ table,
3198
+ op,
3199
+ orderBy,
3200
+ groupBy,
3201
+ limit,
3202
+ businessDateTo,
3203
+ distinct,
3204
+ offset,
3205
+ having,
3206
+ this.dialect
3207
+ );
3208
+ const deadline = Date.now() + timeoutMs;
3209
+ const controller = new AbortController();
3210
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
3211
+ let statementId;
3212
+ try {
3213
+ let response = await this.call("POST", `${API}/`, controller.signal, {
3214
+ warehouse_id: this.config.warehouseId,
3215
+ statement,
3216
+ // the API holds the request for up to 50 s and answers at once if the statement is quicker; a shorter
3217
+ // wait than 5 s is not allowed except 0, so poll
3218
+ wait_timeout: timeoutMs >= 5e3 ? `${Math.min(50, Math.floor(timeoutMs / 1e3))}s` : "0s",
3219
+ on_wait_timeout: "CONTINUE",
3220
+ disposition: "INLINE",
3221
+ format: "JSON_ARRAY",
3222
+ ...this.config.catalog ? { catalog: this.config.catalog } : {},
3223
+ ...this.config.schema ? { schema: this.config.schema } : {}
3224
+ });
3225
+ statementId = response.statement_id;
3226
+ let delay = this.config.pollIntervalMs ?? 250;
3227
+ while (response.status.state === "PENDING" || response.status.state === "RUNNING") {
3228
+ if (Date.now() >= deadline) throw new QueryTimeoutError(timeoutMs);
3229
+ await sleep(Math.min(delay, Math.max(0, deadline - Date.now())));
3230
+ delay = Math.min(delay * 2, 2e3);
3231
+ response = await this.call("GET", `${API}/${statementId}`, controller.signal);
3232
+ }
3233
+ if (response.status.state !== "SUCCEEDED") {
3234
+ const error = response.status.error;
3235
+ throw new DatabricksQueryError(
3236
+ error?.message ?? `The statement ${response.status.state.toLowerCase()}`,
3237
+ error?.error_code,
3238
+ statementId
3239
+ );
3240
+ }
3241
+ return await this.rows(response, controller.signal);
3242
+ } catch (e) {
3243
+ const timedOut = controller.signal.aborted || e instanceof QueryTimeoutError;
3244
+ if (timedOut && statementId !== void 0) await this.cancel(statementId);
3245
+ if (controller.signal.aborted) throw new QueryTimeoutError(timeoutMs);
3246
+ throw e;
3247
+ } finally {
3248
+ clearTimeout(timer);
3249
+ }
3250
+ }
3251
+ /** The rows of a finished statement, following its chunks. */
3252
+ async rows(first, signal) {
3253
+ const info = first.manifest?.schema?.columns ?? [];
3254
+ this.lastColumns = info.map((c) => c.name);
3255
+ const rows = [];
3256
+ const take = (data) => {
3257
+ for (const row of data ?? []) rows.push(row.map((text, i) => convertValue(text, info[i]?.type_name)));
3258
+ };
3259
+ take(first.result?.data_array);
3260
+ let next = first.result?.next_chunk_index;
3261
+ while (next !== void 0 && next !== null) {
3262
+ const chunk = await this.call("GET", `${API}/${first.statement_id}/result/chunks/${next}`, signal);
3263
+ take(chunk.data_array);
3264
+ next = chunk.next_chunk_index;
3265
+ }
3266
+ return rows;
3267
+ }
3268
+ /** Ask Databricks to stop a statement. Best effort: the query is already given up on. */
3269
+ async cancel(statementId) {
3270
+ try {
3271
+ await this.call("POST", `${API}/${statementId}/cancel`, void 0, {});
3272
+ } catch {
3273
+ }
3274
+ }
3275
+ async call(method, path, signal, body) {
3276
+ const { host, token, headers, fetch: custom } = this.config;
3277
+ const bearer = typeof token === "function" ? await token() : token;
3278
+ const response = await (custom ?? fetch)(host.replace(/\/+$/, "") + path, {
3279
+ method,
3280
+ headers: {
3281
+ "Content-Type": "application/json",
3282
+ ...bearer ? { Authorization: `Bearer ${bearer}` } : {},
3283
+ ...headers
3284
+ },
3285
+ body: body === void 0 ? void 0 : JSON.stringify(body),
3286
+ signal
3287
+ });
3288
+ const text = await response.text();
3289
+ let parsed;
3290
+ try {
3291
+ parsed = text ? JSON.parse(text) : {};
3292
+ } catch {
3293
+ parsed = void 0;
3294
+ }
3295
+ if (!response.ok) {
3296
+ const detail = parsed;
3297
+ throw new DatabricksQueryError(
3298
+ detail?.message ?? `Databricks request failed: ${response.status} ${response.statusText}`,
3299
+ detail?.error_code
3300
+ );
3301
+ }
3302
+ return parsed;
3303
+ }
3304
+ };
2072
3305
  // Annotate the CommonJS export names for ESM import in node:
2073
3306
  0 && (module.exports = {
2074
3307
  AggregateOperation,
2075
3308
  AggregateOperator,
3309
+ Aggregates,
2076
3310
  Alias,
3311
+ Arithmetic,
3312
+ ArithmeticOperation,
3313
+ ArithmeticOperator,
2077
3314
  Attribute,
2078
3315
  BiTemporalColumns,
2079
3316
  BinaryOperation,
3317
+ BooleanAggregates,
2080
3318
  BooleanAttribute,
2081
3319
  BooleanConstantOperation,
2082
3320
  BusinessDateAndProcessingTemporalColumns,
3321
+ CaseOperation,
2083
3322
  Column,
2084
3323
  ColumnWithJoin,
3324
+ Comparable,
2085
3325
  ComparisonOperation,
2086
3326
  ComparisonOperator,
3327
+ ConcatOperation,
2087
3328
  ConstantOperation,
2088
3329
  CountAllOperation,
3330
+ DATABRICKS,
3331
+ DATE_ONLY_PATTERN,
2089
3332
  DEFAULT_TIMEOUT_MS,
3333
+ DUCKDB,
2090
3334
  DataCatalog,
2091
3335
  DataStore,
2092
3336
  Database,
3337
+ DatabricksConnect,
3338
+ DatabricksQueryError,
2093
3339
  DateArithmeticOperation,
2094
3340
  DateAttribute,
2095
3341
  DateConstantOperation,
2096
3342
  DateDiffOperation,
2097
3343
  DateExtractOperation,
3344
+ DateOnly,
2098
3345
  DatePart,
2099
3346
  DateTimeAttribute,
2100
3347
  DateTimeConstantOperation,
3348
+ DateTruncOperation,
2101
3349
  DecimalAttribute,
2102
3350
  DecimalConstantOperation,
2103
3351
  DoubleAttribute,
@@ -2106,20 +3354,27 @@ function convertInputsAndSelectForDateRange(businessDateFrom, businessDateTo, pr
2106
3354
  FloatAttribute,
2107
3355
  FloatConstantOperation,
2108
3356
  ForeignKey,
3357
+ InOperation,
2109
3358
  IntegerAttribute,
2110
3359
  IntegerConstantOperation,
2111
3360
  IsNotNullOperation,
2112
3361
  IsNullOperation,
2113
3362
  JoinOperation,
2114
3363
  JoinTreeNodeOperation,
3364
+ LIKE_ESCAPE,
2115
3365
  LogicalOperation,
2116
3366
  LogicalOperator,
2117
3367
  MilestonedTable,
2118
3368
  MilestoningColumns,
3369
+ NUMERIC_FUNCTIONS,
2119
3370
  NoOperation,
2120
3371
  NotExistsOperation,
3372
+ NotInOperation,
2121
3373
  NumericAttribute,
3374
+ NumericConstantOperation,
3375
+ NumericFunctionOperation,
2122
3376
  Operation,
3377
+ POSTGRES,
2123
3378
  ProcessingTemporalColumns,
2124
3379
  QueryTimeoutError,
2125
3380
  RelatedFinder,
@@ -2133,21 +3388,35 @@ function convertInputsAndSelectForDateRange(businessDateFrom, businessDateTo, pr
2133
3388
  SortOperation,
2134
3389
  StringAttribute,
2135
3390
  StringConstantOperation,
3391
+ StringFunctionOperation,
3392
+ StringPredicates,
2136
3393
  Table,
2137
3394
  UnaryOperation,
2138
3395
  WindowFunction,
2139
3396
  WindowFunctionOperation,
2140
3397
  WindowSpecification,
3398
+ applyMixins,
2141
3399
  clearRunner,
3400
+ concat,
3401
+ constant,
3402
+ containsAggregate,
3403
+ containsAggregateOrWindow,
2142
3404
  convertInputsAndSelect,
2143
3405
  convertInputsAndSelectForDateRange,
3406
+ countAll,
3407
+ dialectOf,
2144
3408
  embeddedUnder,
3409
+ escapeLike,
2145
3410
  getRelatedFinderClass,
2146
3411
  getRunner,
3412
+ operandOf,
2147
3413
  registerRelatedFinderClass,
2148
3414
  registerRunner,
3415
+ sample,
2149
3416
  selectSqlToString,
2150
3417
  titleCase,
2151
- toSql
3418
+ toSql,
3419
+ valueOperand,
3420
+ when
2152
3421
  });
2153
3422
  //# sourceMappingURL=index.cjs.map