data-finder-ts 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +17 -55
  2. package/dist/chunk-BGEX377Q.js +230 -0
  3. package/dist/chunk-BGEX377Q.js.map +1 -0
  4. package/dist/chunk-BKPWV3OF.js +962 -0
  5. package/dist/chunk-BKPWV3OF.js.map +1 -0
  6. package/dist/{chunk-EYXBYV2X.js → chunk-GPHWC533.js} +2 -2
  7. package/dist/chunk-KAK75RVS.js +198 -0
  8. package/dist/chunk-KAK75RVS.js.map +1 -0
  9. package/dist/chunk-MGEL5RWM.js +628 -0
  10. package/dist/chunk-MGEL5RWM.js.map +1 -0
  11. package/dist/chunk-PF6EJZHB.js +1015 -0
  12. package/dist/chunk-PF6EJZHB.js.map +1 -0
  13. package/dist/datafinder/attribute.cjs +595 -18
  14. package/dist/datafinder/attribute.cjs.map +1 -1
  15. package/dist/datafinder/attribute.d.cts +73 -10
  16. package/dist/datafinder/attribute.d.ts +73 -10
  17. package/dist/datafinder/attribute.js +2 -2
  18. package/dist/datafinder/runner.cjs +1589 -288
  19. package/dist/datafinder/runner.cjs.map +1 -1
  20. package/dist/datafinder/runner.d.cts +41 -7
  21. package/dist/datafinder/runner.d.ts +41 -7
  22. package/dist/datafinder/runner.js +12 -6
  23. package/dist/datafinder/sql-generator.cjs +1484 -281
  24. package/dist/datafinder/sql-generator.cjs.map +1 -1
  25. package/dist/datafinder/sql-generator.d.cts +19 -14
  26. package/dist/datafinder/sql-generator.d.ts +19 -14
  27. package/dist/datafinder/sql-generator.js +9 -7
  28. package/dist/datafinder/typed-attributes.cjs +856 -93
  29. package/dist/datafinder/typed-attributes.cjs.map +1 -1
  30. package/dist/datafinder/typed-attributes.d.cts +3 -135
  31. package/dist/datafinder/typed-attributes.d.ts +3 -135
  32. package/dist/datafinder/typed-attributes.js +3 -3
  33. package/dist/dialect-CogGPm_y.d.cts +38 -0
  34. package/dist/dialect-aaG1bDi5.d.ts +38 -0
  35. package/dist/index.cjs +2080 -480
  36. package/dist/index.cjs.map +1 -1
  37. package/dist/index.d.cts +119 -14
  38. package/dist/index.d.ts +119 -14
  39. package/dist/index.js +362 -12
  40. package/dist/index.js.map +1 -1
  41. package/dist/model/milestoning.cjs +529 -0
  42. package/dist/model/milestoning.cjs.map +1 -1
  43. package/dist/model/milestoning.js +2 -2
  44. package/dist/model/relational.cjs +608 -12
  45. package/dist/model/relational.cjs.map +1 -1
  46. package/dist/model/relational.d.cts +456 -47
  47. package/dist/model/relational.d.ts +456 -47
  48. package/dist/model/relational.js +61 -3
  49. package/dist/typed-attributes-CUTf_6Ru.d.ts +328 -0
  50. package/dist/typed-attributes-CdWXq_78.d.cts +328 -0
  51. package/package.json +5 -2
  52. package/dist/chunk-3SSWFES4.js +0 -448
  53. package/dist/chunk-3SSWFES4.js.map +0 -1
  54. package/dist/chunk-5K2Z3YDY.js +0 -393
  55. package/dist/chunk-5K2Z3YDY.js.map +0 -1
  56. package/dist/chunk-6QTCGJWX.js +0 -98
  57. package/dist/chunk-6QTCGJWX.js.map +0 -1
  58. package/dist/chunk-DFYZVBII.js +0 -652
  59. package/dist/chunk-DFYZVBII.js.map +0 -1
  60. package/dist/chunk-V647VNMY.js +0 -135
  61. package/dist/chunk-V647VNMY.js.map +0 -1
  62. /package/dist/{chunk-EYXBYV2X.js.map → chunk-GPHWC533.js.map} +0 -0
@@ -25,12 +25,87 @@ __export(attribute_exports, {
25
25
  module.exports = __toCommonJS(attribute_exports);
26
26
 
27
27
  // src/model/relational.ts
28
+ var LIKE_ESCAPE = "!";
29
+ function escapeLike(value) {
30
+ return value.replaceAll(LIKE_ESCAPE, LIKE_ESCAPE + LIKE_ESCAPE).replaceAll("%", LIKE_ESCAPE + "%").replaceAll("_", LIKE_ESCAPE + "_");
31
+ }
28
32
  var RelationalOperationElement = class {
29
33
  };
30
34
  var Operation = class extends RelationalOperationElement {
31
- andOp(other) {
35
+ /** Name this column in the result: `f.price().sum().alias('Total')`, `f.age().gt(30).alias('Adult')`. */
36
+ alias(name) {
37
+ return new Alias(this, name);
38
+ }
39
+ and(other) {
32
40
  return new LogicalOperation(this, "AND" /* AND */, other);
33
41
  }
42
+ /** Combine with `other` using OR. A chain reads left to right: `a.or(b).and(c)` is `(a OR b) AND c`. */
43
+ or(other) {
44
+ return new LogicalOperation(this, "OR" /* OR */, other);
45
+ }
46
+ };
47
+ var ConstantOperation = class extends RelationalOperationElement {
48
+ /** Name this column in the result. */
49
+ alias(name) {
50
+ return new Alias(this, name);
51
+ }
52
+ /** Sort by this expression, smallest first. */
53
+ ascending() {
54
+ return new SortOperation(this, "ASC" /* ASC */);
55
+ }
56
+ /** Sort by this expression, largest first. */
57
+ descending() {
58
+ return new SortOperation(this, "DESC" /* DESC */);
59
+ }
60
+ };
61
+ var NumericConstantOperation = class extends ConstantOperation {
62
+ arithmeticOperand() {
63
+ return this;
64
+ }
65
+ };
66
+ var IntegerConstantOperation = class extends NumericConstantOperation {
67
+ constructor(value) {
68
+ super();
69
+ this.value = value;
70
+ }
71
+ value;
72
+ };
73
+ var FloatConstantOperation = class extends NumericConstantOperation {
74
+ constructor(value) {
75
+ super();
76
+ this.value = value;
77
+ }
78
+ value;
79
+ };
80
+ var StringConstantOperation = class extends ConstantOperation {
81
+ constructor(value) {
82
+ super();
83
+ this.value = value;
84
+ }
85
+ value;
86
+ };
87
+ var DateOnly = class extends Date {
88
+ };
89
+ var DateConstantOperation = class extends ConstantOperation {
90
+ constructor(value) {
91
+ super();
92
+ this.value = value;
93
+ }
94
+ value;
95
+ };
96
+ var DateTimeConstantOperation = class extends ConstantOperation {
97
+ constructor(value) {
98
+ super();
99
+ this.value = value;
100
+ }
101
+ value;
102
+ };
103
+ var BooleanConstantOperation = class extends ConstantOperation {
104
+ constructor(value) {
105
+ super();
106
+ this.value = value;
107
+ }
108
+ value;
34
109
  };
35
110
  var UnaryOperation = class extends Operation {
36
111
  constructor(element) {
@@ -52,6 +127,27 @@ var IsNullOperation = class extends UnaryOperation {
52
127
  };
53
128
  var IsNotNullOperation = class extends UnaryOperation {
54
129
  };
130
+ var InOperation = class extends UnaryOperation {
131
+ constructor(element, values) {
132
+ super(element);
133
+ this.values = values;
134
+ }
135
+ values;
136
+ };
137
+ var NotInOperation = class extends UnaryOperation {
138
+ constructor(element, values) {
139
+ super(element);
140
+ this.values = values;
141
+ }
142
+ values;
143
+ };
144
+ var ComparisonOperation = class extends BinaryOperation {
145
+ constructor(left, operator, right) {
146
+ super(left, right);
147
+ this.operator = operator;
148
+ }
149
+ operator;
150
+ };
55
151
  var LogicalOperation = class extends BinaryOperation {
56
152
  constructor(left, operator, right) {
57
153
  super(left, right);
@@ -68,21 +164,41 @@ var WindowSpecification = class {
68
164
  orderBy;
69
165
  };
70
166
  var AggregateOperation = class _AggregateOperation extends UnaryOperation {
71
- constructor(element, operator, displayName, window) {
167
+ constructor(element, operator, displayName, window, separator, orderBy = []) {
72
168
  super(element);
73
169
  this.operator = operator;
74
170
  this.displayName = displayName;
75
171
  this.window = window;
172
+ this.separator = separator;
173
+ this.orderBy = orderBy;
76
174
  }
77
175
  operator;
78
176
  displayName;
79
177
  window;
178
+ separator;
179
+ orderBy;
180
+ /** Sort by this expression, smallest first. */
181
+ ascending() {
182
+ return new SortOperation(this, "ASC" /* ASC */);
183
+ }
184
+ /** Sort by this expression, largest first. */
185
+ descending() {
186
+ return new SortOperation(this, "DESC" /* DESC */);
187
+ }
188
+ arithmeticOperand() {
189
+ return this;
190
+ }
191
+ comparisonOperand() {
192
+ return this;
193
+ }
80
194
  over(partitionBy, orderBy) {
81
195
  return new _AggregateOperation(
82
196
  this.element,
83
197
  this.operator,
84
198
  this.displayName,
85
- new WindowSpecification(partitionBy ?? [], orderBy ?? [])
199
+ new WindowSpecification(partitionBy ?? [], orderBy ?? []),
200
+ this.separator,
201
+ this.orderBy
86
202
  );
87
203
  }
88
204
  };
@@ -100,6 +216,14 @@ var WindowFunctionOperation = class _WindowFunctionOperation extends UnaryOperat
100
216
  secondArg;
101
217
  extraArgs;
102
218
  window;
219
+ /** Sort by this expression, smallest first. */
220
+ ascending() {
221
+ return new SortOperation(this, "ASC" /* ASC */);
222
+ }
223
+ /** Sort by this expression, largest first. */
224
+ descending() {
225
+ return new SortOperation(this, "DESC" /* DESC */);
226
+ }
103
227
  over(partitionBy, orderBy) {
104
228
  return new _WindowFunctionOperation(
105
229
  this.element,
@@ -111,28 +235,110 @@ var WindowFunctionOperation = class _WindowFunctionOperation extends UnaryOperat
111
235
  );
112
236
  }
113
237
  };
238
+ var ScalarFunctionOperation = class extends UnaryOperation {
239
+ constructor(element, func, displayName, secondArg, extraArgs = []) {
240
+ super(element);
241
+ this.func = func;
242
+ this.displayName = displayName;
243
+ this.secondArg = secondArg;
244
+ this.extraArgs = extraArgs;
245
+ }
246
+ func;
247
+ displayName;
248
+ secondArg;
249
+ extraArgs;
250
+ /** Sort by this expression, smallest first. */
251
+ ascending() {
252
+ return new SortOperation(this, "ASC" /* ASC */);
253
+ }
254
+ /** Sort by this expression, largest first. */
255
+ descending() {
256
+ return new SortOperation(this, "DESC" /* DESC */);
257
+ }
258
+ /** This expression as an operand of a comparison. */
259
+ comparisonOperand() {
260
+ return this;
261
+ }
262
+ arithmeticOperand() {
263
+ return this;
264
+ }
265
+ /** Only a function that gives a number can be used in arithmetic. */
266
+ assertNumeric() {
267
+ if (!NUMERIC_FUNCTIONS.has(this.func)) {
268
+ throw new TypeError(`${this.func} does not give a number, so it cannot be used in arithmetic`);
269
+ }
270
+ }
271
+ };
272
+ var NUMERIC_FUNCTIONS = /* @__PURE__ */ new Set([
273
+ "ABS" /* ABS */,
274
+ "CEILING" /* CEILING */,
275
+ "FLOOR" /* FLOOR */,
276
+ "MOD" /* MOD */,
277
+ "POWER" /* POWER */,
278
+ "SQRT" /* SQRT */,
279
+ "ROUND" /* ROUND */,
280
+ "LENGTH" /* LENGTH */
281
+ ]);
282
+ var DateTruncOperation = class extends UnaryOperation {
283
+ constructor(element, part, displayName) {
284
+ super(element);
285
+ this.part = part;
286
+ this.displayName = displayName;
287
+ }
288
+ part;
289
+ displayName;
290
+ /** Sort by this expression, earliest first. */
291
+ ascending() {
292
+ return new SortOperation(this, "ASC" /* ASC */);
293
+ }
294
+ /** Sort by this expression, latest first. */
295
+ descending() {
296
+ return new SortOperation(this, "DESC" /* DESC */);
297
+ }
298
+ comparisonOperand() {
299
+ return this;
300
+ }
301
+ };
114
302
  var Column = class extends RelationalOperationElement {
115
- constructor(name, type, owner, primaryKey = false) {
303
+ constructor(name, type, owner, primaryKey = false, nullable = true) {
116
304
  super();
117
305
  this.name = name;
118
306
  this.type = type;
119
307
  this.owner = owner;
120
308
  this.primaryKey = primaryKey;
309
+ this.nullable = nullable && !primaryKey;
121
310
  }
122
311
  name;
123
312
  type;
124
313
  owner;
125
314
  primaryKey;
126
315
  table;
316
+ /** Whether the column may hold NULL. As in Legend, a primary key is never null. */
317
+ nullable;
127
318
  };
128
319
  var ColumnWithJoin = class extends RelationalOperationElement {
129
- constructor(column, parent) {
320
+ /**
321
+ * `embedded` is an alternate reference to a flat (denormalized) column on the owning table that
322
+ * holds the same value without the join; the SQL generator uses it when the join can be elided.
323
+ */
324
+ constructor(column, parent, embedded, _optional = false) {
130
325
  super();
131
326
  this.column = column;
132
327
  this.parent = parent;
328
+ this.embedded = embedded;
329
+ this._optional = _optional;
133
330
  }
134
331
  column;
135
332
  parent;
333
+ embedded;
334
+ _optional;
335
+ /** Whether the value can be missing: its property is optional, or a navigation on the way to it is. */
336
+ get optional() {
337
+ for (let node = this.parent; node !== void 0; node = node.parent) {
338
+ if (node.optional) return true;
339
+ }
340
+ return this._optional;
341
+ }
136
342
  };
137
343
  var SortOperation = class {
138
344
  constructor(column, direction) {
@@ -142,18 +348,302 @@ var SortOperation = class {
142
348
  column;
143
349
  direction;
144
350
  };
351
+ var CountAllOperation = class extends RelationalOperationElement {
352
+ constructor(table) {
353
+ super();
354
+ this.table = table;
355
+ }
356
+ table;
357
+ /** Name this column in the result. */
358
+ alias(name) {
359
+ return new Alias(this, name);
360
+ }
361
+ /** Sort by this expression, smallest first. */
362
+ ascending() {
363
+ return new SortOperation(this, "ASC" /* ASC */);
364
+ }
365
+ /** Sort by this expression, largest first. */
366
+ descending() {
367
+ return new SortOperation(this, "DESC" /* DESC */);
368
+ }
369
+ comparisonOperand() {
370
+ return this;
371
+ }
372
+ };
373
+ var Alias = class _Alias extends RelationalOperationElement {
374
+ constructor(element, name) {
375
+ super();
376
+ this.element = element;
377
+ this.name = name;
378
+ }
379
+ element;
380
+ name;
381
+ alias(name) {
382
+ return new _Alias(this.element, name);
383
+ }
384
+ /** Sorts by the column the alias names. */
385
+ ascending() {
386
+ return new SortOperation(this.element, "ASC" /* ASC */);
387
+ }
388
+ /** Sorts by the column the alias names. */
389
+ descending() {
390
+ return new SortOperation(this.element, "DESC" /* DESC */);
391
+ }
392
+ };
393
+ var CaseOperation = class extends Operation {
394
+ constructor(condition, then, fallback, displayName) {
395
+ super();
396
+ this.condition = condition;
397
+ this.then = then;
398
+ this.fallback = fallback;
399
+ this.displayName = displayName;
400
+ }
401
+ condition;
402
+ then;
403
+ fallback;
404
+ displayName;
405
+ };
406
+ function valueOperand(value) {
407
+ if (typeof value === "boolean") return new BooleanConstantOperation(value);
408
+ if (typeof value === "number" && Number.isFinite(value)) {
409
+ return Number.isInteger(value) ? new IntegerConstantOperation(value) : new FloatConstantOperation(value);
410
+ }
411
+ if (typeof value === "string") return new StringConstantOperation(value);
412
+ if (value instanceof DateOnly) return new DateConstantOperation(value);
413
+ if (value instanceof Date) return new DateTimeConstantOperation(value);
414
+ throw new TypeError(`A value to compare with is a boolean, a finite number, a string or a date, not ${value === null ? "null" : typeof value}`);
415
+ }
416
+ function operandOf(other) {
417
+ if (other instanceof RelationalOperationElement) return other;
418
+ if (typeof other?.cwj === "function") return other.cwj();
419
+ return valueOperand(other);
420
+ }
421
+ var Comparable = class {
422
+ _compared(operator, other) {
423
+ return new ComparisonOperation(this.comparisonOperand(), operator, operandOf(other));
424
+ }
425
+ /** Filter to rows where this expression equals `other`. */
426
+ eq(other) {
427
+ return this._compared("EQUAL" /* EQUAL */, other);
428
+ }
429
+ /** Filter to rows where this expression does not equal `other`. */
430
+ ne(other) {
431
+ return this._compared("NOT_EQUAL" /* NOT_EQUAL */, other);
432
+ }
433
+ /** Filter to rows where this expression is less than `other`. */
434
+ lt(other) {
435
+ return this._compared("LESS_THAN" /* LESS_THAN */, other);
436
+ }
437
+ /** Filter to rows where this expression is at most `other`. */
438
+ lte(other) {
439
+ return this._compared("LESS_THAN_OR_EQUAL_TO" /* LESS_THAN_OR_EQUAL_TO */, other);
440
+ }
441
+ /** Filter to rows where this expression is greater than `other`. */
442
+ gt(other) {
443
+ return this._compared("GREATER_THAN" /* GREATER_THAN */, other);
444
+ }
445
+ /** Filter to rows where this expression is at least `other`. */
446
+ gte(other) {
447
+ return this._compared("GREATER_THAN_OR_EQUAL_TO" /* GREATER_THAN_OR_EQUAL_TO */, other);
448
+ }
449
+ };
450
+ function sample(ddof) {
451
+ if (ddof !== 0 && ddof !== 1) throw new RangeError(`ddof is 0 (population) or 1 (sample), not ${ddof}`);
452
+ return ddof === 1;
453
+ }
454
+ var StringPredicates = class {
455
+ _like(pattern) {
456
+ return new ComparisonOperation(this.comparisonOperand(), "LIKE" /* LIKE */, new StringConstantOperation(pattern));
457
+ }
458
+ /** Filter to rows where this text contains `value`. */
459
+ contains(value) {
460
+ return this._like(`%${escapeLike(value)}%`);
461
+ }
462
+ /** Filter to rows where this text starts with `prefix`. */
463
+ startsWith(prefix) {
464
+ return this._like(`${escapeLike(prefix)}%`);
465
+ }
466
+ /** Filter to rows where this text ends with `suffix`. */
467
+ endsWith(suffix) {
468
+ return this._like(`%${escapeLike(suffix)}`);
469
+ }
470
+ };
471
+ var Aggregates = class {
472
+ _aggregate(operator, label) {
473
+ return new AggregateOperation(this, operator, label + " Expression");
474
+ }
475
+ /** Sum of the values in the group. */
476
+ sum() {
477
+ return this._aggregate("SUM" /* SUM */, "Sum");
478
+ }
479
+ /** Smallest value in the group. */
480
+ min() {
481
+ return this._aggregate("MIN" /* MIN */, "Min");
482
+ }
483
+ /** Largest value in the group. */
484
+ max() {
485
+ return this._aggregate("MAX" /* MAX */, "Max");
486
+ }
487
+ /** Arithmetic mean of the values in the group. */
488
+ average() {
489
+ return this._aggregate("AVERAGE" /* AVERAGE */, "Average");
490
+ }
491
+ /** Number of non-null values in the group. */
492
+ count() {
493
+ return this._aggregate("COUNT" /* COUNT */, "Count");
494
+ }
495
+ /** Standard deviation of the values in the group: the sample one by default, `ddof = 0` for the population one. */
496
+ std(ddof = 1) {
497
+ return this._aggregate(sample(ddof) ? "STDDEV_SAMP" /* STDDEV_SAMP */ : "STDDEV_POP" /* STDDEV_POP */, "Std");
498
+ }
499
+ /** Variance of the values in the group: the sample one by default, `ddof = 0` for the population one. */
500
+ var(ddof = 1) {
501
+ return this._aggregate(sample(ddof) ? "VAR_SAMP" /* VAR_SAMP */ : "VAR_POP" /* VAR_POP */, "Var");
502
+ }
503
+ };
504
+ var BooleanAggregates = class {
505
+ /** True for a group where every row satisfies the condition. */
506
+ all() {
507
+ return new AggregateOperation(this, "BOOL_AND" /* BOOL_AND */, "All Expression");
508
+ }
509
+ /** True for a group where at least one row satisfies the condition. */
510
+ any() {
511
+ return new AggregateOperation(this, "BOOL_OR" /* BOOL_OR */, "Any Expression");
512
+ }
513
+ };
514
+ function applyMixins(derived, bases) {
515
+ for (const base of bases) {
516
+ for (const name of Object.getOwnPropertyNames(base.prototype)) {
517
+ if (name === "constructor" || Object.prototype.hasOwnProperty.call(derived.prototype, name)) continue;
518
+ Object.defineProperty(derived.prototype, name, Object.getOwnPropertyDescriptor(base.prototype, name));
519
+ }
520
+ }
521
+ }
522
+ var Arithmetic = class {
523
+ /** Raises if this expression is not a number. */
524
+ assertNumeric() {
525
+ }
526
+ _arithmetic(operator, other) {
527
+ this.assertNumeric();
528
+ let operand;
529
+ if (typeof other === "number") {
530
+ if (!Number.isFinite(other)) throw new TypeError("Arithmetic is between numbers and numeric columns, not a non-finite number");
531
+ operand = valueOperand(other);
532
+ } else if (other !== null && typeof other === "object" && typeof other.arithmeticOperand === "function") {
533
+ other.assertNumeric?.();
534
+ operand = other.arithmeticOperand();
535
+ } else {
536
+ throw new TypeError(`Arithmetic is between numbers and numeric columns, not ${other === null ? "null" : typeof other}`);
537
+ }
538
+ return new ArithmeticOperation(this.arithmeticOperand(), operator, operand);
539
+ }
540
+ /** `this + other`. */
541
+ plus(other) {
542
+ return this._arithmetic("+" /* ADD */, other);
543
+ }
544
+ /** `this - other`. */
545
+ minus(other) {
546
+ return this._arithmetic("-" /* SUBTRACT */, other);
547
+ }
548
+ /** `this * other`. */
549
+ times(other) {
550
+ return this._arithmetic("*" /* MULTIPLY */, other);
551
+ }
552
+ /** `this / other`. */
553
+ dividedBy(other) {
554
+ return this._arithmetic("/" /* DIVIDE */, other);
555
+ }
556
+ };
557
+ var ArithmeticOperation = class extends BinaryOperation {
558
+ constructor(left, operator, right, displayName) {
559
+ super(left, right);
560
+ this.operator = operator;
561
+ this.displayName = displayName;
562
+ }
563
+ operator;
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
+ }
573
+ arithmeticOperand() {
574
+ return this;
575
+ }
576
+ comparisonOperand() {
577
+ return this;
578
+ }
579
+ };
580
+ var ConcatOperation = class extends Operation {
581
+ constructor(parts, displayName) {
582
+ super();
583
+ this.parts = parts;
584
+ this.displayName = displayName;
585
+ }
586
+ parts;
587
+ displayName;
588
+ /** Join more text on the end: `f.first().concat(' ', f.last())`. A concatenation joins into one. */
589
+ concat(...more) {
590
+ return concat(this, ...more);
591
+ }
592
+ /** Sort by this expression, smallest first. */
593
+ ascending() {
594
+ return new SortOperation(this, "ASC" /* ASC */);
595
+ }
596
+ /** Sort by this expression, largest first. */
597
+ descending() {
598
+ return new SortOperation(this, "DESC" /* DESC */);
599
+ }
600
+ comparisonOperand() {
601
+ return this;
602
+ }
603
+ };
604
+ function concat(...parts) {
605
+ const partsOf = (part) => {
606
+ if (part instanceof ConcatOperation) return part.parts;
607
+ if (typeof part === "string") return [new StringConstantOperation(part)];
608
+ if (part instanceof RelationalOperationElement) return [part];
609
+ if (part !== null && typeof part === "object" && typeof part.functionInput === "function") return [part.functionInput()];
610
+ throw new TypeError(`Text is joined with text, not ${part === null ? "null" : typeof part}`);
611
+ };
612
+ return new ConcatOperation(parts.flatMap(partsOf));
613
+ }
614
+ applyMixins(ConcatOperation, [Comparable, StringPredicates]);
615
+ applyMixins(DateTruncOperation, [Comparable]);
616
+ applyMixins(ArithmeticOperation, [Arithmetic, Comparable]);
617
+ applyMixins(ScalarFunctionOperation, [Comparable, Arithmetic, StringPredicates]);
618
+ applyMixins(AggregateOperation, [Arithmetic, Comparable, StringPredicates]);
619
+ applyMixins(CountAllOperation, [Comparable]);
620
+ applyMixins(NumericConstantOperation, [Arithmetic]);
621
+ applyMixins(ConstantOperation, [Aggregates]);
622
+ applyMixins(ArithmeticOperation, [Aggregates]);
623
+ applyMixins(ScalarFunctionOperation, [Aggregates]);
624
+ applyMixins(CaseOperation, [Aggregates]);
625
+ applyMixins(IsNullOperation, [BooleanAggregates]);
626
+ applyMixins(IsNotNullOperation, [BooleanAggregates]);
627
+ applyMixins(InOperation, [BooleanAggregates]);
628
+ applyMixins(NotInOperation, [BooleanAggregates]);
629
+ applyMixins(ComparisonOperation, [BooleanAggregates]);
630
+ applyMixins(LogicalOperation, [BooleanAggregates]);
145
631
 
146
632
  // src/datafinder/attribute.ts
147
- var Attribute = class {
633
+ var Attribute = class _Attribute {
148
634
  _displayName;
149
635
  _column;
150
636
  _owner;
151
637
  _parent;
152
- constructor(displayName, columnName, columnDbType, owner, parent) {
638
+ _embedded;
639
+ _optional;
640
+ constructor(displayName, columnName, columnDbType, owner, parent, embedded, nullable = true, optional = false) {
641
+ this._optional = optional;
153
642
  this._displayName = displayName;
154
- this._column = new Column(columnName, columnDbType, owner);
643
+ this._column = new Column(columnName, columnDbType, owner, false, nullable);
155
644
  this._owner = owner;
156
645
  this._parent = parent;
646
+ this._embedded = embedded;
157
647
  }
158
648
  column() {
159
649
  return this._column;
@@ -167,33 +657,102 @@ var Attribute = class {
167
657
  displayName() {
168
658
  return this._displayName;
169
659
  }
660
+ /** Alternate attribute on a flat column of the owning table, used in place of this one when its join is elided. */
661
+ embedded() {
662
+ return this._embedded;
663
+ }
664
+ /** @internal The expression a function of this attribute applies to: its column. */
665
+ functionInput() {
666
+ return this.cwj();
667
+ }
668
+ /** @internal What a function of this attribute is labelled after: its display name. */
669
+ functionLabel() {
670
+ return this._displayName;
671
+ }
672
+ /** @internal This attribute as an operand of arithmetic: its column. */
673
+ arithmeticOperand() {
674
+ return this.cwj();
675
+ }
170
676
  cwj() {
171
- return new ColumnWithJoin(this._column, this._parent);
677
+ return new ColumnWithJoin(this._column, this._parent, this._embedded?.cwj(), this._optional);
172
678
  }
679
+ /** Count the number of non-null values. Use in a projection with `groupBy` to aggregate per group. */
173
680
  count() {
174
681
  return new AggregateOperation(
175
- new ColumnWithJoin(this._column, this._parent),
682
+ this.cwj(),
176
683
  "COUNT" /* COUNT */,
177
684
  this._displayName + " Count"
178
685
  );
179
686
  }
687
+ /** Name this column in the result: `f.price().sum().alias('Total')`. */
688
+ alias(name) {
689
+ return new Alias(this, name);
690
+ }
691
+ /** The number of different non-NULL values in the group: `COUNT(DISTINCT column)`. Use with `groupBy` to count per group. */
692
+ countDistinct() {
693
+ return new AggregateOperation(this.cwj(), "COUNT_DISTINCT" /* COUNT_DISTINCT */, this._displayName + " Count Distinct");
694
+ }
695
+ /** The value, or `defaultValue` when it is NULL: `name().orElse('N/A')`. Like `COALESCE` in SQL. */
696
+ orElse(defaultValue) {
697
+ if (!["string", "number", "boolean"].includes(typeof defaultValue)) {
698
+ throw new TypeError(`An orElse default is a string, number or boolean, not ${defaultValue === null ? "null" : typeof defaultValue}`);
699
+ }
700
+ return new ScalarFunctionOperation(this.cwj(), "COALESCE" /* COALESCE */, "Or Else " + this._displayName, void 0, [defaultValue]);
701
+ }
702
+ /** Sort this attribute in ascending order. Pass to `orderBy` or a window function's `orderBy`. */
180
703
  ascending() {
181
- return new SortOperation(new ColumnWithJoin(this._column, this._parent), "ASC" /* ASC */);
704
+ return new SortOperation(this.cwj(), "ASC" /* ASC */);
182
705
  }
706
+ /** Sort this attribute in descending order. Pass to `orderBy` or a window function's `orderBy`. */
183
707
  descending() {
184
- return new SortOperation(new ColumnWithJoin(this._column, this._parent), "DESC" /* DESC */);
708
+ return new SortOperation(this.cwj(), "DESC" /* DESC */);
185
709
  }
710
+ /** Filter to rows where this attribute has no value. */
186
711
  isNull() {
187
- return new IsNullOperation(new ColumnWithJoin(this._column, this._parent));
712
+ return new IsNullOperation(this.cwj());
188
713
  }
714
+ /** Filter to rows where this attribute has a value. */
189
715
  isNotNull() {
190
- return new IsNotNullOperation(new ColumnWithJoin(this._column, this._parent));
716
+ return new IsNotNullOperation(this.cwj());
717
+ }
718
+ /** Wrap a value as a constant of this attribute's type. Overridden by the typed attributes. */
719
+ toConstant(_value) {
720
+ throw new TypeError(`${this.constructor.name} does not support isIn / isNotIn`);
721
+ }
722
+ _constants(values) {
723
+ const constants = values.map((v) => this.toConstant(v));
724
+ if (constants.length === 0) throw new Error("isIn / isNotIn need at least one value");
725
+ return constants;
726
+ }
727
+ /** Filter to rows where this attribute equals any of `values`. */
728
+ isIn(values) {
729
+ return new InOperation(this.cwj(), this._constants(values));
730
+ }
731
+ /** Filter to rows where this attribute equals none of `values`. Rows with no value are excluded, as in SQL. */
732
+ isNotIn(values) {
733
+ return new NotInOperation(this.cwj(), this._constants(values));
191
734
  }
192
735
  _windowSpec(partitionBy, orderBy) {
193
- const pb = partitionBy === void 0 ? [] : Array.isArray(partitionBy) ? partitionBy : [partitionBy];
736
+ const pbArr = partitionBy === void 0 ? [] : Array.isArray(partitionBy) ? partitionBy : [partitionBy];
737
+ const pb = pbArr.map((x) => x instanceof _Attribute ? x.cwj() : x);
194
738
  const ob = orderBy === void 0 ? [] : Array.isArray(orderBy) ? orderBy : [orderBy];
195
739
  return new WindowSpecification(pb, ob);
196
740
  }
741
+ /**
742
+ * Assign a rank to each row within the ordered window, following pandas `Series.rank` conventions.
743
+ *
744
+ * `method` controls tie-breaking (default `'min'`):
745
+ * - `'min'` — tied rows share the lowest rank; the next rank skips.
746
+ * - `'dense'` — like `'min'` but ranks are contiguous (no gaps).
747
+ * - `'first'` — each row gets a unique sequential integer (no ties).
748
+ * - `'max'` — only meaningful with `pct: true` (see below).
749
+ *
750
+ * When `pct: true` the result is a relative rank between 0 and 1:
751
+ * - `method: 'min'` (default) → fraction of values strictly below this row (PERCENT_RANK).
752
+ * - `method: 'max'` → fraction of values at or below this row (cumulative distribution).
753
+ *
754
+ * `partitionBy` restarts the ranking within each group of distinct values.
755
+ */
197
756
  rank(opts = {}) {
198
757
  const { method = "min", pct = false, partitionBy, orderBy } = opts;
199
758
  let func;
@@ -218,6 +777,11 @@ var Attribute = class {
218
777
  }
219
778
  return new WindowFunctionOperation(null, func, name, void 0, [], this._windowSpec(partitionBy, orderBy));
220
779
  }
780
+ /**
781
+ * Split rows into `buckets` equal-sized quantile bins ordered by `orderBy`.
782
+ * Each row receives a bucket number from 1 (lowest) to `buckets` (highest).
783
+ * Named after `pandas.qcut`.
784
+ */
221
785
  qcut(buckets, opts = {}) {
222
786
  return new WindowFunctionOperation(
223
787
  null,
@@ -228,12 +792,17 @@ var Attribute = class {
228
792
  this._windowSpec(opts.partitionBy, opts.orderBy)
229
793
  );
230
794
  }
795
+ /**
796
+ * Return the value of this attribute from `periods` rows earlier (positive) or later (negative)
797
+ * within the ordered window, following `pandas.Series.shift`.
798
+ * Rows with no neighbour at the given offset return `null` (or `fillValue` if provided).
799
+ */
231
800
  shift(periods = 1, opts = {}) {
232
801
  const extraArgs = opts.fillValue !== void 0 ? [opts.fillValue] : [];
233
802
  const func = periods >= 0 ? "LAG" /* LAG */ : "LEAD" /* LEAD */;
234
803
  const label = periods >= 0 ? "Lag" : "Lead";
235
804
  return new WindowFunctionOperation(
236
- new ColumnWithJoin(this._column, this._parent),
805
+ this.cwj(),
237
806
  func,
238
807
  label + " " + this._displayName,
239
808
  Math.abs(periods),
@@ -241,9 +810,13 @@ var Attribute = class {
241
810
  this._windowSpec(opts.partitionBy, opts.orderBy)
242
811
  );
243
812
  }
813
+ /**
814
+ * Return the first value of this attribute in the window frame.
815
+ * Use `partitionBy` to restart the frame for each group.
816
+ */
244
817
  first(opts = {}) {
245
818
  return new WindowFunctionOperation(
246
- new ColumnWithJoin(this._column, this._parent),
819
+ this.cwj(),
247
820
  "FIRST_VALUE" /* FIRST_VALUE */,
248
821
  "First " + this._displayName,
249
822
  void 0,
@@ -251,9 +824,13 @@ var Attribute = class {
251
824
  this._windowSpec(opts.partitionBy, opts.orderBy)
252
825
  );
253
826
  }
827
+ /**
828
+ * Return the last value of this attribute in the window frame.
829
+ * Use `partitionBy` to restart the frame for each group.
830
+ */
254
831
  last(opts = {}) {
255
832
  return new WindowFunctionOperation(
256
- new ColumnWithJoin(this._column, this._parent),
833
+ this.cwj(),
257
834
  "LAST_VALUE" /* LAST_VALUE */,
258
835
  "Last " + this._displayName,
259
836
  void 0,