data-finder-ts 0.1.3 → 0.1.4

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 (52) hide show
  1. package/README.md +17 -55
  2. package/dist/{chunk-V647VNMY.js → chunk-4JVW4TAB.js} +59 -14
  3. package/dist/chunk-4JVW4TAB.js.map +1 -0
  4. package/dist/{chunk-5K2Z3YDY.js → chunk-4LNZV6EN.js} +138 -31
  5. package/dist/chunk-4LNZV6EN.js.map +1 -0
  6. package/dist/{chunk-6QTCGJWX.js → chunk-FJYA2ASS.js} +46 -8
  7. package/dist/chunk-FJYA2ASS.js.map +1 -0
  8. package/dist/{chunk-DFYZVBII.js → chunk-MH4XMYVB.js} +186 -142
  9. package/dist/chunk-MH4XMYVB.js.map +1 -0
  10. package/dist/{chunk-EYXBYV2X.js → chunk-PMPLCEWQ.js} +2 -2
  11. package/dist/{chunk-3SSWFES4.js → chunk-UYMOE6YU.js} +64 -3
  12. package/dist/chunk-UYMOE6YU.js.map +1 -0
  13. package/dist/datafinder/attribute.cjs +64 -13
  14. package/dist/datafinder/attribute.cjs.map +1 -1
  15. package/dist/datafinder/attribute.d.cts +48 -7
  16. package/dist/datafinder/attribute.d.ts +48 -7
  17. package/dist/datafinder/attribute.js +2 -2
  18. package/dist/datafinder/runner.cjs +389 -140
  19. package/dist/datafinder/runner.cjs.map +1 -1
  20. package/dist/datafinder/runner.d.cts +14 -3
  21. package/dist/datafinder/runner.d.ts +14 -3
  22. package/dist/datafinder/runner.js +12 -6
  23. package/dist/datafinder/sql-generator.cjs +344 -138
  24. package/dist/datafinder/sql-generator.cjs.map +1 -1
  25. package/dist/datafinder/sql-generator.d.cts +4 -13
  26. package/dist/datafinder/sql-generator.d.ts +4 -13
  27. package/dist/datafinder/sql-generator.js +5 -7
  28. package/dist/datafinder/typed-attributes.cjs +199 -41
  29. package/dist/datafinder/typed-attributes.cjs.map +1 -1
  30. package/dist/datafinder/typed-attributes.d.cts +120 -13
  31. package/dist/datafinder/typed-attributes.d.ts +120 -13
  32. package/dist/datafinder/typed-attributes.js +3 -3
  33. package/dist/index.cjs +507 -176
  34. package/dist/index.cjs.map +1 -1
  35. package/dist/index.d.cts +16 -15
  36. package/dist/index.d.ts +16 -15
  37. package/dist/index.js +49 -9
  38. package/dist/index.js.map +1 -1
  39. package/dist/model/milestoning.cjs.map +1 -1
  40. package/dist/model/milestoning.js +2 -2
  41. package/dist/model/relational.cjs +66 -1
  42. package/dist/model/relational.cjs.map +1 -1
  43. package/dist/model/relational.d.cts +47 -2
  44. package/dist/model/relational.d.ts +47 -2
  45. package/dist/model/relational.js +9 -1
  46. package/package.json +4 -2
  47. package/dist/chunk-3SSWFES4.js.map +0 -1
  48. package/dist/chunk-5K2Z3YDY.js.map +0 -1
  49. package/dist/chunk-6QTCGJWX.js.map +0 -1
  50. package/dist/chunk-DFYZVBII.js.map +0 -1
  51. package/dist/chunk-V647VNMY.js.map +0 -1
  52. /package/dist/{chunk-EYXBYV2X.js.map → chunk-PMPLCEWQ.js.map} +0 -0
@@ -20,9 +20,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/datafinder/runner.ts
21
21
  var runner_exports = {};
22
22
  __export(runner_exports, {
23
+ DEFAULT_TIMEOUT_MS: () => DEFAULT_TIMEOUT_MS,
23
24
  FinderResult: () => FinderResult,
25
+ QueryTimeoutError: () => QueryTimeoutError,
24
26
  clearRunner: () => clearRunner,
25
27
  convertInputsAndSelect: () => convertInputsAndSelect,
28
+ convertInputsAndSelectForDateRange: () => convertInputsAndSelectForDateRange,
26
29
  getRunner: () => getRunner,
27
30
  registerRunner: () => registerRunner
28
31
  });
@@ -265,13 +268,19 @@ var Table = class {
265
268
  }
266
269
  };
267
270
  var ColumnWithJoin = class extends RelationalOperationElement {
268
- constructor(column, parent) {
271
+ /**
272
+ * `embedded` is an alternate reference to a flat (denormalized) column on the owning table that
273
+ * holds the same value without the join; the SQL generator uses it when the join can be elided.
274
+ */
275
+ constructor(column, parent, embedded) {
269
276
  super();
270
277
  this.column = column;
271
278
  this.parent = parent;
279
+ this.embedded = embedded;
272
280
  }
273
281
  column;
274
282
  parent;
283
+ embedded;
275
284
  };
276
285
  var SortOperation = class {
277
286
  constructor(column, direction) {
@@ -288,18 +297,67 @@ var CountAllOperation = class extends RelationalOperationElement {
288
297
  }
289
298
  table;
290
299
  };
300
+ var Alias = class extends RelationalOperationElement {
301
+ constructor(element, name) {
302
+ super();
303
+ this.element = element;
304
+ this.name = name;
305
+ }
306
+ element;
307
+ name;
308
+ };
309
+ var ExistsOperation = class extends RelationalOperationElement {
310
+ constructor(node) {
311
+ super();
312
+ this.node = node;
313
+ }
314
+ node;
315
+ andOp(other) {
316
+ return new LogicalOperation(this, "AND" /* AND */, other);
317
+ }
318
+ };
319
+ var NotExistsOperation = class extends RelationalOperationElement {
320
+ constructor(node) {
321
+ super();
322
+ this.node = node;
323
+ }
324
+ node;
325
+ andOp(other) {
326
+ return new LogicalOperation(this, "AND" /* AND */, other);
327
+ }
328
+ };
329
+ var SelectOperation = class {
330
+ constructor(display, filter, orderBy = [], groupBy = [], limit, table, joinFilters = /* @__PURE__ */ new Map()) {
331
+ this.display = display;
332
+ this.filter = filter;
333
+ this.orderBy = orderBy;
334
+ this.groupBy = groupBy;
335
+ this.limit = limit;
336
+ this.table = table;
337
+ this.joinFilters = joinFilters;
338
+ }
339
+ display;
340
+ filter;
341
+ orderBy;
342
+ groupBy;
343
+ limit;
344
+ table;
345
+ joinFilters;
346
+ };
291
347
 
292
348
  // src/datafinder/attribute.ts
293
- var Attribute = class {
349
+ var Attribute = class _Attribute {
294
350
  _displayName;
295
351
  _column;
296
352
  _owner;
297
353
  _parent;
298
- constructor(displayName, columnName, columnDbType, owner, parent) {
354
+ _embedded;
355
+ constructor(displayName, columnName, columnDbType, owner, parent, embedded) {
299
356
  this._displayName = displayName;
300
357
  this._column = new Column(columnName, columnDbType, owner);
301
358
  this._owner = owner;
302
359
  this._parent = parent;
360
+ this._embedded = embedded;
303
361
  }
304
362
  column() {
305
363
  return this._column;
@@ -313,33 +371,58 @@ var Attribute = class {
313
371
  displayName() {
314
372
  return this._displayName;
315
373
  }
374
+ /** Alternate attribute on a flat column of the owning table, used in place of this one when its join is elided. */
375
+ embedded() {
376
+ return this._embedded;
377
+ }
316
378
  cwj() {
317
- return new ColumnWithJoin(this._column, this._parent);
379
+ return new ColumnWithJoin(this._column, this._parent, this._embedded?.cwj());
318
380
  }
381
+ /** Count the number of non-null values. Use in a projection with `groupByOp` to aggregate per group. */
319
382
  count() {
320
383
  return new AggregateOperation(
321
- new ColumnWithJoin(this._column, this._parent),
384
+ this.cwj(),
322
385
  "COUNT" /* COUNT */,
323
386
  this._displayName + " Count"
324
387
  );
325
388
  }
389
+ /** Sort this attribute in ascending order. Pass to `orderByOp` or a window function's `orderBy`. */
326
390
  ascending() {
327
- return new SortOperation(new ColumnWithJoin(this._column, this._parent), "ASC" /* ASC */);
391
+ return new SortOperation(this.cwj(), "ASC" /* ASC */);
328
392
  }
393
+ /** Sort this attribute in descending order. Pass to `orderByOp` or a window function's `orderBy`. */
329
394
  descending() {
330
- return new SortOperation(new ColumnWithJoin(this._column, this._parent), "DESC" /* DESC */);
395
+ return new SortOperation(this.cwj(), "DESC" /* DESC */);
331
396
  }
397
+ /** Filter to rows where this attribute has no value. */
332
398
  isNull() {
333
- return new IsNullOperation(new ColumnWithJoin(this._column, this._parent));
399
+ return new IsNullOperation(this.cwj());
334
400
  }
401
+ /** Filter to rows where this attribute has a value. */
335
402
  isNotNull() {
336
- return new IsNotNullOperation(new ColumnWithJoin(this._column, this._parent));
403
+ return new IsNotNullOperation(this.cwj());
337
404
  }
338
405
  _windowSpec(partitionBy, orderBy) {
339
- const pb = partitionBy === void 0 ? [] : Array.isArray(partitionBy) ? partitionBy : [partitionBy];
406
+ const pbArr = partitionBy === void 0 ? [] : Array.isArray(partitionBy) ? partitionBy : [partitionBy];
407
+ const pb = pbArr.map((x) => x instanceof _Attribute ? x.cwj() : x);
340
408
  const ob = orderBy === void 0 ? [] : Array.isArray(orderBy) ? orderBy : [orderBy];
341
409
  return new WindowSpecification(pb, ob);
342
410
  }
411
+ /**
412
+ * Assign a rank to each row within the ordered window, following pandas `Series.rank` conventions.
413
+ *
414
+ * `method` controls tie-breaking (default `'min'`):
415
+ * - `'min'` — tied rows share the lowest rank; the next rank skips.
416
+ * - `'dense'` — like `'min'` but ranks are contiguous (no gaps).
417
+ * - `'first'` — each row gets a unique sequential integer (no ties).
418
+ * - `'max'` — only meaningful with `pct: true` (see below).
419
+ *
420
+ * When `pct: true` the result is a relative rank between 0 and 1:
421
+ * - `method: 'min'` (default) → fraction of values strictly below this row (PERCENT_RANK).
422
+ * - `method: 'max'` → fraction of values at or below this row (cumulative distribution).
423
+ *
424
+ * `partitionBy` restarts the ranking within each group of distinct values.
425
+ */
343
426
  rank(opts = {}) {
344
427
  const { method = "min", pct = false, partitionBy, orderBy } = opts;
345
428
  let func;
@@ -364,6 +447,11 @@ var Attribute = class {
364
447
  }
365
448
  return new WindowFunctionOperation(null, func, name, void 0, [], this._windowSpec(partitionBy, orderBy));
366
449
  }
450
+ /**
451
+ * Split rows into `buckets` equal-sized quantile bins ordered by `orderBy`.
452
+ * Each row receives a bucket number from 1 (lowest) to `buckets` (highest).
453
+ * Named after `pandas.qcut`.
454
+ */
367
455
  qcut(buckets, opts = {}) {
368
456
  return new WindowFunctionOperation(
369
457
  null,
@@ -374,12 +462,17 @@ var Attribute = class {
374
462
  this._windowSpec(opts.partitionBy, opts.orderBy)
375
463
  );
376
464
  }
465
+ /**
466
+ * Return the value of this attribute from `periods` rows earlier (positive) or later (negative)
467
+ * within the ordered window, following `pandas.Series.shift`.
468
+ * Rows with no neighbour at the given offset return `null` (or `fillValue` if provided).
469
+ */
377
470
  shift(periods = 1, opts = {}) {
378
471
  const extraArgs = opts.fillValue !== void 0 ? [opts.fillValue] : [];
379
472
  const func = periods >= 0 ? "LAG" /* LAG */ : "LEAD" /* LEAD */;
380
473
  const label = periods >= 0 ? "Lag" : "Lead";
381
474
  return new WindowFunctionOperation(
382
- new ColumnWithJoin(this._column, this._parent),
475
+ this.cwj(),
383
476
  func,
384
477
  label + " " + this._displayName,
385
478
  Math.abs(periods),
@@ -387,9 +480,13 @@ var Attribute = class {
387
480
  this._windowSpec(opts.partitionBy, opts.orderBy)
388
481
  );
389
482
  }
483
+ /**
484
+ * Return the first value of this attribute in the window frame.
485
+ * Use `partitionBy` to restart the frame for each group.
486
+ */
390
487
  first(opts = {}) {
391
488
  return new WindowFunctionOperation(
392
- new ColumnWithJoin(this._column, this._parent),
489
+ this.cwj(),
393
490
  "FIRST_VALUE" /* FIRST_VALUE */,
394
491
  "First " + this._displayName,
395
492
  void 0,
@@ -397,9 +494,13 @@ var Attribute = class {
397
494
  this._windowSpec(opts.partitionBy, opts.orderBy)
398
495
  );
399
496
  }
497
+ /**
498
+ * Return the last value of this attribute in the window frame.
499
+ * Use `partitionBy` to restart the frame for each group.
500
+ */
400
501
  last(opts = {}) {
401
502
  return new WindowFunctionOperation(
402
- new ColumnWithJoin(this._column, this._parent),
503
+ this.cwj(),
403
504
  "LAST_VALUE" /* LAST_VALUE */,
404
505
  "Last " + this._displayName,
405
506
  void 0,
@@ -494,209 +595,233 @@ function parseDate(value) {
494
595
  return d;
495
596
  }
496
597
  var DateAttribute = class extends Attribute {
497
- constructor(displayName, columnName, columnDbType, owner, parent) {
498
- super(displayName, columnName, columnDbType, owner, parent);
598
+ constructor(displayName, columnName, columnDbType, owner, parent, embedded) {
599
+ super(displayName, columnName, columnDbType, owner, parent, embedded);
499
600
  }
601
+ /** Filter to rows where this date equals `value`. */
500
602
  eq(value) {
501
603
  return new ComparisonOperation(this.cwj(), "EQUAL" /* EQUAL */, new DateConstantOperation(parseDate(value)));
502
604
  }
605
+ /** Filter to rows where this date does not equal `value`. */
503
606
  ne(value) {
504
607
  return new ComparisonOperation(this.cwj(), "NOT_EQUAL" /* NOT_EQUAL */, new DateConstantOperation(parseDate(value)));
505
608
  }
609
+ /** Filter to rows where this date is after `value`. */
506
610
  gt(value) {
507
611
  return new ComparisonOperation(this.cwj(), "GREATER_THAN" /* GREATER_THAN */, new DateConstantOperation(parseDate(value)));
508
612
  }
613
+ /** Filter to rows where this date is before `value`. */
509
614
  lt(value) {
510
615
  return new ComparisonOperation(this.cwj(), "LESS_THAN" /* LESS_THAN */, new DateConstantOperation(parseDate(value)));
511
616
  }
617
+ /** Filter to rows where this date is on or after `value`. */
512
618
  gte(value) {
513
619
  return new ComparisonOperation(this.cwj(), "GREATER_THAN_OR_EQUAL_TO" /* GREATER_THAN_OR_EQUAL_TO */, new DateConstantOperation(parseDate(value)));
514
620
  }
621
+ /** Filter to rows where this date is on or before `value`. */
515
622
  lte(value) {
516
623
  return new ComparisonOperation(this.cwj(), "LESS_THAN_OR_EQUAL_TO" /* LESS_THAN_OR_EQUAL_TO */, new DateConstantOperation(parseDate(value)));
517
624
  }
625
+ /** Extract the four-digit calendar year. */
518
626
  year() {
519
627
  return new DateExtractOperation(this.cwj(), "YEAR" /* YEAR */, "Year " + this.displayName());
520
628
  }
629
+ /** Extract the month number (1–12). */
521
630
  month() {
522
631
  return new DateExtractOperation(this.cwj(), "MONTH" /* MONTH */, "Month " + this.displayName());
523
632
  }
633
+ /** Extract the day of the month (1–31). */
524
634
  day() {
525
635
  return new DateExtractOperation(this.cwj(), "DAY" /* DAY */, "Day " + this.displayName());
526
636
  }
637
+ /** Extract the quarter (1–4). */
527
638
  quarter() {
528
639
  return new DateExtractOperation(this.cwj(), "QUARTER" /* QUARTER */, "Quarter " + this.displayName());
529
640
  }
641
+ /** Extract the ISO week number (1–53). */
530
642
  week() {
531
643
  return new DateExtractOperation(this.cwj(), "WEEK" /* WEEK */, "Week " + this.displayName());
532
644
  }
645
+ /** Extract the day of the week (0 = Sunday through 6 = Saturday). */
533
646
  dayOfWeek() {
534
647
  return new DateExtractOperation(this.cwj(), "DOW" /* DOW */, "Day Of Week " + this.displayName());
535
648
  }
649
+ /** Add `n` days to this date. */
536
650
  addDays(n) {
537
651
  return new DateArithmeticOperation(this.cwj(), n, "DAY" /* DAY */, true, "Add Days " + this.displayName());
538
652
  }
653
+ /** Add `n` months to this date. */
539
654
  addMonths(n) {
540
655
  return new DateArithmeticOperation(this.cwj(), n, "MONTH" /* MONTH */, true, "Add Months " + this.displayName());
541
656
  }
657
+ /** Add `n` years to this date. */
542
658
  addYears(n) {
543
659
  return new DateArithmeticOperation(this.cwj(), n, "YEAR" /* YEAR */, true, "Add Years " + this.displayName());
544
660
  }
661
+ /** Subtract `n` days from this date. */
545
662
  subtractDays(n) {
546
663
  return new DateArithmeticOperation(this.cwj(), n, "DAY" /* DAY */, false, "Subtract Days " + this.displayName());
547
664
  }
665
+ /** Subtract `n` months from this date. */
548
666
  subtractMonths(n) {
549
667
  return new DateArithmeticOperation(this.cwj(), n, "MONTH" /* MONTH */, false, "Subtract Months " + this.displayName());
550
668
  }
669
+ /** Subtract `n` years from this date. */
551
670
  subtractYears(n) {
552
671
  return new DateArithmeticOperation(this.cwj(), n, "YEAR" /* YEAR */, false, "Subtract Years " + this.displayName());
553
672
  }
673
+ /** Number of whole days between this date and `other`. */
554
674
  diffDays(other) {
555
675
  return new DateDiffOperation(this.cwj(), other, "DAY" /* DAY */, "Diff Days " + this.displayName());
556
676
  }
677
+ /** Number of whole months between this date and `other`. */
557
678
  diffMonths(other) {
558
679
  return new DateDiffOperation(this.cwj(), other, "MONTH" /* MONTH */, "Diff Months " + this.displayName());
559
680
  }
681
+ /** Number of whole years between this date and `other`. */
560
682
  diffYears(other) {
561
683
  return new DateDiffOperation(this.cwj(), other, "YEAR" /* YEAR */, "Diff Years " + this.displayName());
562
684
  }
563
685
  };
564
686
  var DateTimeAttribute = class extends Attribute {
565
- constructor(displayName, columnName, columnDbType, owner, parent) {
566
- super(displayName, columnName, columnDbType, owner, parent);
687
+ constructor(displayName, columnName, columnDbType, owner, parent, embedded) {
688
+ super(displayName, columnName, columnDbType, owner, parent, embedded);
567
689
  }
690
+ /** Filter to rows where this timestamp equals `value`. */
568
691
  eq(value) {
569
692
  return new ComparisonOperation(this.cwj(), "EQUAL" /* EQUAL */, new DateTimeConstantOperation(parseDate(value)));
570
693
  }
694
+ /** Filter to rows where this timestamp does not equal `value`. */
571
695
  ne(value) {
572
696
  return new ComparisonOperation(this.cwj(), "NOT_EQUAL" /* NOT_EQUAL */, new DateTimeConstantOperation(parseDate(value)));
573
697
  }
698
+ /** Filter to rows where this timestamp is after `value`. */
574
699
  gt(value) {
575
700
  return new ComparisonOperation(this.cwj(), "GREATER_THAN" /* GREATER_THAN */, new DateTimeConstantOperation(parseDate(value)));
576
701
  }
702
+ /** Filter to rows where this timestamp is before `value`. */
577
703
  lt(value) {
578
704
  return new ComparisonOperation(this.cwj(), "LESS_THAN" /* LESS_THAN */, new DateTimeConstantOperation(parseDate(value)));
579
705
  }
706
+ /** Filter to rows where this timestamp is on or after `value`. */
580
707
  gte(value) {
581
708
  return new ComparisonOperation(this.cwj(), "GREATER_THAN_OR_EQUAL_TO" /* GREATER_THAN_OR_EQUAL_TO */, new DateTimeConstantOperation(parseDate(value)));
582
709
  }
710
+ /** Filter to rows where this timestamp is on or before `value`. */
583
711
  lte(value) {
584
712
  return new ComparisonOperation(this.cwj(), "LESS_THAN_OR_EQUAL_TO" /* LESS_THAN_OR_EQUAL_TO */, new DateTimeConstantOperation(parseDate(value)));
585
713
  }
714
+ /** Extract the four-digit calendar year. */
586
715
  year() {
587
716
  return new DateExtractOperation(this.cwj(), "YEAR" /* YEAR */, "Year " + this.displayName());
588
717
  }
718
+ /** Extract the month number (1–12). */
589
719
  month() {
590
720
  return new DateExtractOperation(this.cwj(), "MONTH" /* MONTH */, "Month " + this.displayName());
591
721
  }
722
+ /** Extract the day of the month (1–31). */
592
723
  day() {
593
724
  return new DateExtractOperation(this.cwj(), "DAY" /* DAY */, "Day " + this.displayName());
594
725
  }
726
+ /** Extract the hour (0–23). */
595
727
  hour() {
596
728
  return new DateExtractOperation(this.cwj(), "HOUR" /* HOUR */, "Hour " + this.displayName());
597
729
  }
730
+ /** Extract the minute (0–59). */
598
731
  minute() {
599
732
  return new DateExtractOperation(this.cwj(), "MINUTE" /* MINUTE */, "Minute " + this.displayName());
600
733
  }
734
+ /** Extract the second (0–59). */
601
735
  second() {
602
736
  return new DateExtractOperation(this.cwj(), "SECOND" /* SECOND */, "Second " + this.displayName());
603
737
  }
738
+ /** Extract the quarter (1–4). */
604
739
  quarter() {
605
740
  return new DateExtractOperation(this.cwj(), "QUARTER" /* QUARTER */, "Quarter " + this.displayName());
606
741
  }
742
+ /** Extract the ISO week number (1–53). */
607
743
  week() {
608
744
  return new DateExtractOperation(this.cwj(), "WEEK" /* WEEK */, "Week " + this.displayName());
609
745
  }
746
+ /** Extract the day of the week (0 = Sunday through 6 = Saturday). */
610
747
  dayOfWeek() {
611
748
  return new DateExtractOperation(this.cwj(), "DOW" /* DOW */, "Day Of Week " + this.displayName());
612
749
  }
750
+ /** Add `n` days to this timestamp. */
613
751
  addDays(n) {
614
752
  return new DateArithmeticOperation(this.cwj(), n, "DAY" /* DAY */, true, "Add Days " + this.displayName());
615
753
  }
754
+ /** Add `n` months to this timestamp. */
616
755
  addMonths(n) {
617
756
  return new DateArithmeticOperation(this.cwj(), n, "MONTH" /* MONTH */, true, "Add Months " + this.displayName());
618
757
  }
758
+ /** Add `n` years to this timestamp. */
619
759
  addYears(n) {
620
760
  return new DateArithmeticOperation(this.cwj(), n, "YEAR" /* YEAR */, true, "Add Years " + this.displayName());
621
761
  }
762
+ /** Add `n` hours to this timestamp. */
622
763
  addHours(n) {
623
764
  return new DateArithmeticOperation(this.cwj(), n, "HOUR" /* HOUR */, true, "Add Hours " + this.displayName());
624
765
  }
766
+ /** Add `n` minutes to this timestamp. */
625
767
  addMinutes(n) {
626
768
  return new DateArithmeticOperation(this.cwj(), n, "MINUTE" /* MINUTE */, true, "Add Minutes " + this.displayName());
627
769
  }
770
+ /** Add `n` seconds to this timestamp. */
628
771
  addSeconds(n) {
629
772
  return new DateArithmeticOperation(this.cwj(), n, "SECOND" /* SECOND */, true, "Add Seconds " + this.displayName());
630
773
  }
774
+ /** Subtract `n` days from this timestamp. */
631
775
  subtractDays(n) {
632
776
  return new DateArithmeticOperation(this.cwj(), n, "DAY" /* DAY */, false, "Subtract Days " + this.displayName());
633
777
  }
778
+ /** Subtract `n` months from this timestamp. */
634
779
  subtractMonths(n) {
635
780
  return new DateArithmeticOperation(this.cwj(), n, "MONTH" /* MONTH */, false, "Subtract Months " + this.displayName());
636
781
  }
782
+ /** Subtract `n` years from this timestamp. */
637
783
  subtractYears(n) {
638
784
  return new DateArithmeticOperation(this.cwj(), n, "YEAR" /* YEAR */, false, "Subtract Years " + this.displayName());
639
785
  }
786
+ /** Subtract `n` hours from this timestamp. */
640
787
  subtractHours(n) {
641
788
  return new DateArithmeticOperation(this.cwj(), n, "HOUR" /* HOUR */, false, "Subtract Hours " + this.displayName());
642
789
  }
790
+ /** Subtract `n` minutes from this timestamp. */
643
791
  subtractMinutes(n) {
644
792
  return new DateArithmeticOperation(this.cwj(), n, "MINUTE" /* MINUTE */, false, "Subtract Minutes " + this.displayName());
645
793
  }
794
+ /** Subtract `n` seconds from this timestamp. */
646
795
  subtractSeconds(n) {
647
796
  return new DateArithmeticOperation(this.cwj(), n, "SECOND" /* SECOND */, false, "Subtract Seconds " + this.displayName());
648
797
  }
798
+ /** Number of whole days between this timestamp and `other`. */
649
799
  diffDays(other) {
650
800
  return new DateDiffOperation(this.cwj(), other, "DAY" /* DAY */, "Diff Days " + this.displayName());
651
801
  }
802
+ /** Number of whole months between this timestamp and `other`. */
652
803
  diffMonths(other) {
653
804
  return new DateDiffOperation(this.cwj(), other, "MONTH" /* MONTH */, "Diff Months " + this.displayName());
654
805
  }
806
+ /** Number of whole years between this timestamp and `other`. */
655
807
  diffYears(other) {
656
808
  return new DateDiffOperation(this.cwj(), other, "YEAR" /* YEAR */, "Diff Years " + this.displayName());
657
809
  }
810
+ /** Number of whole hours between this timestamp and `other`. */
658
811
  diffHours(other) {
659
812
  return new DateDiffOperation(this.cwj(), other, "HOUR" /* HOUR */, "Diff Hours " + this.displayName());
660
813
  }
814
+ /** Number of whole minutes between this timestamp and `other`. */
661
815
  diffMinutes(other) {
662
816
  return new DateDiffOperation(this.cwj(), other, "MINUTE" /* MINUTE */, "Diff Minutes " + this.displayName());
663
817
  }
818
+ /** Number of whole seconds between this timestamp and `other`. */
664
819
  diffSeconds(other) {
665
820
  return new DateDiffOperation(this.cwj(), other, "SECOND" /* SECOND */, "Diff Seconds " + this.displayName());
666
821
  }
667
822
  };
668
823
 
669
- // src/datafinder/finder.ts
670
- var ExistsOperation = class extends RelationalOperationElement {
671
- constructor(node) {
672
- super();
673
- this.node = node;
674
- }
675
- node;
676
- andOp(other) {
677
- return new LogicalOperation(this, "AND" /* AND */, other);
678
- }
679
- };
680
- var NotExistsOperation = class extends RelationalOperationElement {
681
- constructor(node) {
682
- super();
683
- this.node = node;
684
- }
685
- node;
686
- andOp(other) {
687
- return new LogicalOperation(this, "AND" /* AND */, other);
688
- }
689
- };
690
-
691
824
  // src/datafinder/sql-generator.ts
692
- var Alias = class {
693
- constructor(element, name) {
694
- this.element = element;
695
- this.name = name;
696
- }
697
- element;
698
- name;
699
- };
700
825
  var TableAlias = class {
701
826
  constructor(table, alias) {
702
827
  this.table = table;
@@ -724,22 +849,6 @@ var Join = class {
724
849
  target;
725
850
  filterOp;
726
851
  };
727
- var SelectOperation = class {
728
- constructor(display, filter, orderBy = [], groupBy = [], limit, table) {
729
- this.display = display;
730
- this.filter = filter;
731
- this.orderBy = orderBy;
732
- this.groupBy = groupBy;
733
- this.limit = limit;
734
- this.table = table;
735
- }
736
- display;
737
- filter;
738
- orderBy;
739
- groupBy;
740
- limit;
741
- table;
742
- };
743
852
  function sqlFormatDatetime(value) {
744
853
  const pad = (n, w = 2) => String(n).padStart(w, "0");
745
854
  return `'${value.getUTCFullYear()}-${pad(value.getUTCMonth() + 1)}-${pad(value.getUTCDate())} ${pad(value.getUTCHours())}:${pad(value.getUTCMinutes())}:${pad(value.getUTCSeconds())}'`;
@@ -871,6 +980,9 @@ function sqlOperationToString(operation) {
871
980
  }
872
981
  throw new TypeError("Unknown operation in sqlOperationToString: " + operation.constructor.name);
873
982
  }
983
+ function embeddedOf(ref) {
984
+ return ref instanceof Attribute ? ref.embedded() : ref.embedded;
985
+ }
874
986
  function findColumn(operation) {
875
987
  if (operation instanceof UnaryOperation) return findColumn(operation.element);
876
988
  if (operation instanceof ColumnWithJoin) return operation;
@@ -920,38 +1032,125 @@ function buildMilestoningFilterOperation(businessDate, processingDatetime, table
920
1032
  if (ops.length === 1) return ops[0];
921
1033
  return new LogicalOperation(ops[0], "AND" /* AND */, ops[1]);
922
1034
  }
923
- function buildQueryOperation(businessDate, processingDatetime, columns, table, op, orderBy = [], groupBy = [], limit) {
1035
+ function buildMilestoningFilterOperationForDateRange(businessDateFrom, businessDateTo, processingDatetime, table, joinNode) {
1036
+ const mc = table.milestoningColumns;
1037
+ const ops = [];
1038
+ const hasRange = businessDateFrom !== null && businessDateTo !== null;
1039
+ const processingOp = (m) => {
1040
+ const startAt = new DateTimeAttribute("start_at", m.startAtColumn.name, m.startAtColumn.type, m.startAtColumn.table.qualifiedName, joinNode);
1041
+ const endAt = new DateTimeAttribute("end_at", m.endAtColumn.name, m.endAtColumn.type, m.endAtColumn.table.qualifiedName, joinNode);
1042
+ return new LogicalOperation(startAt.lte(processingDatetime), "AND" /* AND */, openEndClause(endAt, processingDatetime, m.infiniteDatetime));
1043
+ };
1044
+ if (mc instanceof BiTemporalColumns) {
1045
+ if (hasRange) {
1046
+ const dateFrom = new DateAttribute("business_date_from", mc.businessDateFromColumn.name, mc.businessDateFromColumn.type, mc.businessDateFromColumn.table.qualifiedName, joinNode);
1047
+ const dateTo = new DateAttribute("business_date_to", mc.businessDateToColumn.name, mc.businessDateToColumn.type, mc.businessDateToColumn.table.qualifiedName, joinNode);
1048
+ ops.push(new LogicalOperation(dateFrom.lte(businessDateTo), "AND" /* AND */, openEndClause(dateTo, businessDateFrom, mc.infiniteDatetime)));
1049
+ }
1050
+ if (processingDatetime !== null) ops.push(processingOp(mc));
1051
+ } else if (mc instanceof BusinessDateAndProcessingTemporalColumns) {
1052
+ if (hasRange) {
1053
+ const businessAtt = new DateAttribute("business_date", mc.businessDateColumn.name, mc.businessDateColumn.type, mc.businessDateColumn.table.qualifiedName, joinNode);
1054
+ ops.push(new LogicalOperation(businessAtt.gte(businessDateFrom), "AND" /* AND */, businessAtt.lte(businessDateTo)));
1055
+ }
1056
+ if (processingDatetime !== null) ops.push(processingOp(mc));
1057
+ } else if (mc instanceof ProcessingTemporalColumns) {
1058
+ if (processingDatetime !== null) ops.push(processingOp(mc));
1059
+ } else if (mc instanceof SingleBusinessDateColumn && hasRange) {
1060
+ const businessAtt = new DateAttribute("business_date", mc.businessDateColumn.name, mc.businessDateColumn.type, mc.businessDateColumn.table.qualifiedName, joinNode);
1061
+ ops.push(new LogicalOperation(businessAtt.gte(businessDateFrom), "AND" /* AND */, businessAtt.lte(businessDateTo)));
1062
+ }
1063
+ if (ops.length === 0) return null;
1064
+ if (ops.length === 1) return ops[0];
1065
+ return new LogicalOperation(ops[0], "AND" /* AND */, ops[1]);
1066
+ }
1067
+ function walkRefs(op, visit, visitExists) {
1068
+ if (op === null || op === void 0) return;
1069
+ if (op instanceof Attribute || op instanceof ColumnWithJoin) {
1070
+ visit(op);
1071
+ } else if (op instanceof ExistsOperation || op instanceof NotExistsOperation) {
1072
+ visitExists?.(op.node);
1073
+ } else if (op instanceof AggregateOperation) {
1074
+ walkRefs(op.element, visit, visitExists);
1075
+ if (op.window) walkWindowSpec(op.window, visit, visitExists);
1076
+ } else if (op instanceof WindowFunctionOperation) {
1077
+ if (op.element) walkRefs(op.element, visit, visitExists);
1078
+ if (op.window) walkWindowSpec(op.window, visit, visitExists);
1079
+ } else if (op instanceof ScalarFunctionOperation || op instanceof DateExtractOperation || op instanceof DateArithmeticOperation || op instanceof DateDiffOperation || op instanceof IsNullOperation || op instanceof IsNotNullOperation) {
1080
+ walkRefs(op.element, visit, visitExists);
1081
+ } else if (op instanceof SortOperation) {
1082
+ walkRefs(op.column, visit, visitExists);
1083
+ } else if (op instanceof LogicalOperation || op instanceof ComparisonOperation) {
1084
+ walkRefs(op.left, visit, visitExists);
1085
+ walkRefs(op.right, visit, visitExists);
1086
+ }
1087
+ }
1088
+ function walkWindowSpec(window, visit, visitExists) {
1089
+ for (const p of window.partitionBy) walkRefs(p, visit, visitExists);
1090
+ for (const s of window.orderBy) walkRefs(s.column, visit, visitExists);
1091
+ }
1092
+ function buildJoinFilterFromProperties(node, filter, columnMap) {
1093
+ const ops = [];
1094
+ for (const [key, value] of Object.entries(filter)) {
1095
+ const entry = columnMap[key];
1096
+ if (entry === void 0) {
1097
+ throw new Error(`Unknown property '${key}' \u2014 valid properties are: ${Object.keys(columnMap).sort().join(", ")}`);
1098
+ }
1099
+ const [name, type, table] = entry;
1100
+ const col = new ColumnWithJoin(new Column(name, type, table), node);
1101
+ let constant;
1102
+ if (typeof value === "boolean") constant = new BooleanConstantOperation(value);
1103
+ else if (typeof value === "number") constant = Number.isInteger(value) ? new IntegerConstantOperation(value) : new FloatConstantOperation(value);
1104
+ else if (value instanceof Date) constant = type.toUpperCase() === "DATE" ? new DateConstantOperation(value) : new DateTimeConstantOperation(value);
1105
+ else constant = new StringConstantOperation(String(value));
1106
+ ops.push(new ComparisonOperation(col, "EQUAL" /* EQUAL */, constant));
1107
+ }
1108
+ return ops.reduce((acc, op) => new LogicalOperation(acc, "AND" /* AND */, op));
1109
+ }
1110
+ function withAncestors(nodes) {
1111
+ const ordered = /* @__PURE__ */ new Set();
1112
+ const add = (node) => {
1113
+ if (ordered.has(node)) return;
1114
+ if (node.parent !== void 0) add(node.parent);
1115
+ ordered.add(node);
1116
+ };
1117
+ for (const node of nodes) add(node);
1118
+ return [...ordered];
1119
+ }
1120
+ function buildQueryOperation(businessDate, processingDatetime, columns, table, op, orderBy = [], groupBy = [], limit, businessDateTo = null) {
924
1121
  let filter = op;
1122
+ const milestoningFor = (t, node) => businessDateTo !== null ? buildMilestoningFilterOperationForDateRange(businessDate, businessDateTo, processingDatetime, t, node) : buildMilestoningFilterOperation(businessDate, processingDatetime, t, node);
925
1123
  if (table instanceof MilestonedTable) {
926
- const milestonedOp = buildMilestoningFilterOperation(businessDate, processingDatetime, table);
1124
+ const milestonedOp = milestoningFor(table);
927
1125
  if (milestonedOp !== null) {
928
1126
  filter = filter instanceof NoOperation ? milestonedOp : new LogicalOperation(filter, "AND" /* AND */, milestonedOp);
929
1127
  }
930
1128
  }
931
- const requiredJoins = [];
932
- const requiredJoinIds = /* @__PURE__ */ new Set();
933
- for (const col of columns) {
934
- if (col instanceof CountAllOperation) continue;
935
- let node;
936
- if (col instanceof Attribute) {
937
- node = col.parent();
938
- } else {
939
- node = findColumn(col).parent;
1129
+ const requiredJoins = /* @__PURE__ */ new Set();
1130
+ const collect = (ref) => {
1131
+ const parent = ref instanceof Attribute ? ref.parent() : ref.parent;
1132
+ if (parent !== void 0) requiredJoins.add(parent);
1133
+ };
1134
+ const collectNode = (node) => requiredJoins.add(node);
1135
+ for (const col of columns) walkRefs(col, collect, collectNode);
1136
+ for (const expr of groupBy) walkRefs(expr, collect, collectNode);
1137
+ for (const sort of orderBy) walkRefs(sort, collect, collectNode);
1138
+ walkRefs(op, collect, collectNode);
1139
+ const joinFilters = /* @__PURE__ */ new Map();
1140
+ for (const node of withAncestors(requiredJoins)) {
1141
+ let combined;
1142
+ if (Object.keys(node.join.filterKwargs).length > 0) {
1143
+ combined = buildJoinFilterFromProperties(node, node.join.filterKwargs, node.join.filterColumnMap);
940
1144
  }
941
- if (node !== void 0 && !requiredJoinIds.has(node)) {
942
- requiredJoinIds.add(node);
943
- requiredJoins.push(node);
944
- }
945
- }
946
- for (const node of requiredJoins) {
947
1145
  if (node.join.target instanceof MilestonedTable) {
948
- const milestonedOp = buildMilestoningFilterOperation(businessDate, processingDatetime, node.join.target, node);
1146
+ const milestonedOp = milestoningFor(node.join.target, node);
949
1147
  if (milestonedOp !== null) {
950
- node.join.filter = milestonedOp;
1148
+ combined = combined === void 0 ? milestonedOp : new LogicalOperation(combined, "AND" /* AND */, milestonedOp);
951
1149
  }
952
1150
  }
1151
+ if (combined !== void 0) joinFilters.set(node, combined);
953
1152
  }
954
- return new SelectOperation(columns, filter, orderBy, groupBy, limit, table);
1153
+ return new SelectOperation(columns, filter, orderBy, groupBy, limit, table, joinFilters);
955
1154
  }
956
1155
  var SQLQueryGenerator = class {
957
1156
  _select = [];
@@ -965,8 +1164,12 @@ var SQLQueryGenerator = class {
965
1164
  _tableAliasesByTable = /* @__PURE__ */ new Map();
966
1165
  _addedJoinIds = /* @__PURE__ */ new Set();
967
1166
  _rootTable;
1167
+ _elidableNodes = /* @__PURE__ */ new Set();
1168
+ _joinFilters = /* @__PURE__ */ new Map();
968
1169
  generate(select) {
969
1170
  this._rootTable = select.table;
1171
+ this._elidableNodes = this._computeElidableNodes(select);
1172
+ this._joinFilters = select.joinFilters;
970
1173
  if (this._rootTable !== void 0) {
971
1174
  this._from.add(this._tableAliasForTable(this._rootTable.qualifiedName, this._rootTable.qualifiedName));
972
1175
  }
@@ -986,39 +1189,49 @@ var SQLQueryGenerator = class {
986
1189
  this._limit = select.limit;
987
1190
  }
988
1191
  _attrToColString(attr) {
989
- const node = attr.parent();
990
- const ta = this._tableAliasForTable(attr.owner(), node ?? attr.owner());
991
- return ta.alias + "." + attr.column().name;
1192
+ const { column, parent } = this._resolve(attr);
1193
+ const ta = this._tableAliasForTable(column.owner, parent ?? column.owner);
1194
+ return ta.alias + "." + column.name;
992
1195
  }
993
1196
  _collectRequiredJoins(op, out) {
994
- if (op === null || op === void 0) return;
995
- if (op instanceof Attribute) {
996
- const p = op.parent();
997
- if (p !== void 0) out.set(p, p);
998
- } else if (op instanceof ColumnWithJoin) {
999
- if (op.parent !== void 0) out.set(op.parent, op.parent);
1000
- } else if (op instanceof AggregateOperation) {
1001
- this._collectRequiredJoins(op.element, out);
1002
- if (op.window) this._collectRequiredJoins(op.window, out);
1003
- } else if (op instanceof WindowFunctionOperation) {
1004
- if (op.element) this._collectRequiredJoins(op.element, out);
1005
- if (op.window) this._collectRequiredJoinsFromWindowSpec(op.window, out);
1006
- } else if (op instanceof ScalarFunctionOperation || op instanceof DateExtractOperation || op instanceof DateArithmeticOperation || op instanceof DateDiffOperation) {
1007
- this._collectRequiredJoins(op.element, out);
1008
- } else if (op instanceof SortOperation) {
1009
- this._collectRequiredJoins(op.column, out);
1010
- } else if (op instanceof LogicalOperation || op instanceof ComparisonOperation) {
1011
- this._collectRequiredJoins(op.left, out);
1012
- this._collectRequiredJoins(op.right, out);
1013
- }
1014
- }
1015
- _collectRequiredJoinsFromWindowSpec(window, out) {
1016
- for (const p of window.partitionBy) {
1017
- this._collectRequiredJoins(p, out);
1197
+ walkRefs(op, (ref) => {
1198
+ const { parent } = this._resolve(ref);
1199
+ if (parent !== void 0) out.set(parent, parent);
1200
+ });
1201
+ }
1202
+ /**
1203
+ * Determine upfront which join nodes can be satisfied entirely by embedded (join-less) alternates:
1204
+ * a node is elidable when every reference to it has an embedded alternate. A reference without one
1205
+ * (e.g. a milestoning column) keeps the join for every reference to that node.
1206
+ */
1207
+ _computeElidableNodes(select) {
1208
+ const refsByNode = /* @__PURE__ */ new Map();
1209
+ const record = (ref) => {
1210
+ const parent = ref instanceof Attribute ? ref.parent() : ref.parent;
1211
+ if (parent === void 0) return;
1212
+ const refs = refsByNode.get(parent);
1213
+ if (refs) refs.push(ref);
1214
+ else refsByNode.set(parent, [ref]);
1215
+ };
1216
+ for (const col of select.display) walkRefs(col, record);
1217
+ for (const expr of select.groupBy) walkRefs(expr, record);
1218
+ for (const sort of select.orderBy) walkRefs(sort, record);
1219
+ walkRefs(select.filter, record);
1220
+ const elidable = /* @__PURE__ */ new Set();
1221
+ for (const [node, refs] of refsByNode) {
1222
+ if (refs.every((ref) => embeddedOf(ref) !== void 0)) elidable.add(node);
1018
1223
  }
1019
- for (const s of window.orderBy) {
1020
- this._collectRequiredJoins(s.column, out);
1224
+ return elidable;
1225
+ }
1226
+ /** The (column, parent) a reference should resolve to, substituting its embedded alternate when its join is elided. */
1227
+ _resolve(ref) {
1228
+ const column = ref instanceof Attribute ? ref.column() : ref.column;
1229
+ const parent = ref instanceof Attribute ? ref.parent() : ref.parent;
1230
+ if (parent !== void 0 && this._elidableNodes.has(parent)) {
1231
+ const embedded = embeddedOf(ref);
1232
+ if (embedded !== void 0) return this._resolve(embedded);
1021
1233
  }
1234
+ return { column, parent };
1022
1235
  }
1023
1236
  _rewriteWindowSpec(window) {
1024
1237
  const partitionBy = window.partitionBy.map((p) => this._rewriteOperation(p));
@@ -1026,13 +1239,9 @@ var SQLQueryGenerator = class {
1026
1239
  return new WindowSpecification(partitionBy, orderBy);
1027
1240
  }
1028
1241
  _rewriteOperation(op) {
1029
- if (op instanceof Attribute) {
1030
- const ta = this._tableAliasForTable(op.owner(), op.parent() ?? op.owner());
1031
- return new TableAliasColumn(op.column(), ta);
1032
- }
1033
- if (op instanceof ColumnWithJoin) {
1034
- const ta = op.parent !== void 0 ? this._tableAliasForTable(op.column.owner, op.parent) : this._tableAliasForTable(op.column.owner, op.column.owner);
1035
- return new TableAliasColumn(op.column, ta);
1242
+ if (op instanceof Attribute || op instanceof ColumnWithJoin) {
1243
+ const { column, parent } = this._resolve(op);
1244
+ return new TableAliasColumn(column, this._tableAliasForTable(column.owner, parent ?? column.owner));
1036
1245
  }
1037
1246
  if (op instanceof Column) {
1038
1247
  const ta = this._tableAliasForTable(op.owner, op.owner);
@@ -1081,15 +1290,15 @@ var SQLQueryGenerator = class {
1081
1290
  }
1082
1291
  for (const col of cols) {
1083
1292
  if (col instanceof Attribute) {
1084
- const node = col.parent();
1293
+ const { column, parent: node } = this._resolve(col);
1085
1294
  let ta;
1086
1295
  if (node !== void 0) {
1087
- ta = this._tableAliasForTable(col.owner(), node);
1296
+ ta = this._tableAliasForTable(column.owner, node);
1088
1297
  } else {
1089
- ta = this._tableAliasForTable(col.owner(), col.owner());
1298
+ ta = this._tableAliasForTable(column.owner, column.owner);
1090
1299
  this._from.add(ta);
1091
1300
  }
1092
- this._select.push(new Alias(new TableAliasColumn(col.column(), ta), col.displayName()));
1301
+ this._select.push(new Alias(new TableAliasColumn(column, ta), col.displayName()));
1093
1302
  } else if (col instanceof WindowFunctionOperation) {
1094
1303
  const rewritten = this._rewriteOperation(col);
1095
1304
  let alias;
@@ -1104,7 +1313,7 @@ var SQLQueryGenerator = class {
1104
1313
  }
1105
1314
  this._select.push(new Alias(rewritten, alias));
1106
1315
  } else if (col instanceof AggregateOperation) {
1107
- const colNested = findColumn(col);
1316
+ const colNested = this._resolve(findColumn(col));
1108
1317
  const node = colNested.parent;
1109
1318
  let ta;
1110
1319
  if (node !== void 0) {
@@ -1113,7 +1322,7 @@ var SQLQueryGenerator = class {
1113
1322
  ta = this._tableAliasForTable(colNested.column.owner, colNested.column.owner);
1114
1323
  this._from.add(ta);
1115
1324
  }
1116
- const alias = col.displayName ?? col.operator + " " + colNested.column.name;
1325
+ const alias = col.displayName ?? col.operator + " " + findColumn(col).column.name;
1117
1326
  const rewrittenAgg = new AggregateOperation(
1118
1327
  new TableAliasColumn(colNested.column, ta),
1119
1328
  col.operator,
@@ -1122,7 +1331,7 @@ var SQLQueryGenerator = class {
1122
1331
  );
1123
1332
  this._select.push(new Alias(rewrittenAgg, alias));
1124
1333
  } else if (col instanceof ScalarFunctionOperation) {
1125
- const colNested = findColumn(col);
1334
+ const colNested = this._resolve(findColumn(col));
1126
1335
  const node = colNested.parent;
1127
1336
  let ta;
1128
1337
  if (node !== void 0) {
@@ -1131,13 +1340,13 @@ var SQLQueryGenerator = class {
1131
1340
  ta = this._tableAliasForTable(colNested.column.owner, colNested.column.owner);
1132
1341
  this._from.add(ta);
1133
1342
  }
1134
- const alias = col.displayName ?? col.func + " " + colNested.column.name;
1343
+ const alias = col.displayName ?? col.func + " " + findColumn(col).column.name;
1135
1344
  this._select.push(new Alias(
1136
1345
  new ScalarFunctionOperation(new TableAliasColumn(colNested.column, ta), col.func, void 0, col.secondArg, col.extraArgs),
1137
1346
  alias
1138
1347
  ));
1139
1348
  } else if (col instanceof DateExtractOperation || col instanceof DateArithmeticOperation || col instanceof DateDiffOperation) {
1140
- const colNested = findColumn(col);
1349
+ const colNested = this._resolve(findColumn(col));
1141
1350
  const node = colNested.parent;
1142
1351
  let ta;
1143
1352
  if (node !== void 0) {
@@ -1146,7 +1355,7 @@ var SQLQueryGenerator = class {
1146
1355
  ta = this._tableAliasForTable(colNested.column.owner, colNested.column.owner);
1147
1356
  this._from.add(ta);
1148
1357
  }
1149
- const alias = col.displayName ?? colNested.column.name;
1358
+ const alias = col.displayName ?? findColumn(col).column.name;
1150
1359
  let aliasedOp;
1151
1360
  if (col instanceof DateExtractOperation) {
1152
1361
  aliasedOp = new DateExtractOperation(new TableAliasColumn(colNested.column, ta), col.part);
@@ -1174,7 +1383,9 @@ var SQLQueryGenerator = class {
1174
1383
  const sc = new TableAliasColumn(left, srcTa);
1175
1384
  const right = join.right;
1176
1385
  const tc = new TableAliasColumn(right, this._tableAliasForTable(right.owner, node));
1177
- this._join.push(new Join(sc, tc, join.filter));
1386
+ const queryFilter = this._joinFilters.get(node);
1387
+ const filterOp = join.filter !== void 0 && queryFilter !== void 0 ? new LogicalOperation(join.filter, "AND" /* AND */, queryFilter) : join.filter ?? queryFilter;
1388
+ this._join.push(new Join(sc, tc, filterOp));
1178
1389
  }
1179
1390
  buildFilter(op) {
1180
1391
  if (op instanceof NoOperation) return "";
@@ -1200,15 +1411,15 @@ var SQLQueryGenerator = class {
1200
1411
  }
1201
1412
  if (op instanceof ConstantOperation) return constantValueString(op);
1202
1413
  if (op instanceof ColumnWithJoin) {
1203
- const node = op.parent;
1414
+ const { column, parent: node } = this._resolve(op);
1204
1415
  let ta;
1205
1416
  if (node !== void 0) {
1206
- ta = this._tableAliasForTable(op.column.owner, node);
1417
+ ta = this._tableAliasForTable(column.owner, node);
1207
1418
  this._addJoin(node);
1208
1419
  } else {
1209
- ta = this._tableAliasForTable(op.column.owner, op.column.owner);
1420
+ ta = this._tableAliasForTable(column.owner, column.owner);
1210
1421
  }
1211
- return ta.alias + "." + op.column.name;
1422
+ return ta.alias + "." + column.name;
1212
1423
  }
1213
1424
  if (op instanceof Column) {
1214
1425
  const ta = this._tableAliasForTable(op.owner, op.owner);
@@ -1248,12 +1459,21 @@ function selectSqlToString(selectOperation) {
1248
1459
  qg.generate(selectOperation);
1249
1460
  return qg.buildQueryString();
1250
1461
  }
1251
- function toSql(businessDate, processingDatetime, columns, table, op, orderBy = [], groupBy = [], limit) {
1252
- const selectOp = buildQueryOperation(businessDate, processingDatetime, columns, table, op, orderBy, groupBy, limit);
1462
+ function toSql(businessDate, processingDatetime, columns, table, op, orderBy = [], groupBy = [], limit, businessDateTo = null) {
1463
+ const selectOp = buildQueryOperation(businessDate, processingDatetime, columns, table, op, orderBy, groupBy, limit, businessDateTo);
1253
1464
  return selectSqlToString(selectOp);
1254
1465
  }
1255
1466
 
1256
1467
  // src/datafinder/runner.ts
1468
+ var DEFAULT_TIMEOUT_MS = 6e4;
1469
+ var QueryTimeoutError = class extends Error {
1470
+ constructor(timeoutMs) {
1471
+ super(`Query exceeded ${timeoutMs}ms timeout`);
1472
+ this.timeoutMs = timeoutMs;
1473
+ this.name = "QueryTimeoutError";
1474
+ }
1475
+ timeoutMs;
1476
+ };
1257
1477
  var _runner = null;
1258
1478
  function registerRunner(runner) {
1259
1479
  _runner = runner;
@@ -1266,21 +1486,24 @@ function getRunner() {
1266
1486
  return _runner;
1267
1487
  }
1268
1488
  var FinderResult = class {
1269
- constructor(_businessDate, _processingDatetime, _columns, _table, _op) {
1489
+ constructor(_businessDate, _processingDatetime, _columns, _table, _op, _businessDateTo = null) {
1270
1490
  this._businessDate = _businessDate;
1271
1491
  this._processingDatetime = _processingDatetime;
1272
1492
  this._columns = _columns;
1273
1493
  this._table = _table;
1274
1494
  this._op = _op;
1495
+ this._businessDateTo = _businessDateTo;
1275
1496
  }
1276
1497
  _businessDate;
1277
1498
  _processingDatetime;
1278
1499
  _columns;
1279
1500
  _table;
1280
1501
  _op;
1502
+ _businessDateTo;
1281
1503
  _orderBy = [];
1282
1504
  _groupBy = [];
1283
1505
  _limit;
1506
+ _timeoutMs = DEFAULT_TIMEOUT_MS;
1284
1507
  orderByOp(...sorts) {
1285
1508
  this._orderBy = sorts;
1286
1509
  return this;
@@ -1293,6 +1516,11 @@ var FinderResult = class {
1293
1516
  this._limit = n;
1294
1517
  return this;
1295
1518
  }
1519
+ /** Abort the query and throw QueryTimeoutError if it runs longer than `milliseconds` (default 60000). */
1520
+ timeout(milliseconds) {
1521
+ this._timeoutMs = milliseconds;
1522
+ return this;
1523
+ }
1296
1524
  toSql() {
1297
1525
  return toSql(
1298
1526
  this._businessDate,
@@ -1302,7 +1530,8 @@ var FinderResult = class {
1302
1530
  this._op,
1303
1531
  this._orderBy,
1304
1532
  this._groupBy,
1305
- this._limit
1533
+ this._limit,
1534
+ this._businessDateTo
1306
1535
  );
1307
1536
  }
1308
1537
  async toRows() {
@@ -1314,14 +1543,18 @@ var FinderResult = class {
1314
1543
  this._op,
1315
1544
  this._orderBy,
1316
1545
  this._groupBy,
1317
- this._limit
1546
+ this._limit,
1547
+ this._timeoutMs,
1548
+ this._businessDateTo
1318
1549
  );
1319
1550
  }
1320
1551
  };
1321
1552
  function convertDate(value) {
1322
1553
  if (value === null) return null;
1323
1554
  if (value instanceof Date) return value;
1324
- const normalized = /^\d{4}-\d{2}-\d{2}$/.test(value) ? value + "T00:00:00Z" : value;
1555
+ let normalized = value;
1556
+ if (/^\d{4}-\d{2}-\d{2}$/.test(value)) normalized = value + "T00:00:00Z";
1557
+ else if (/^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}(:\d{2}(\.\d+)?)?$/.test(value)) normalized = value.replace(" ", "T") + "Z";
1325
1558
  const d = new Date(normalized);
1326
1559
  if (isNaN(d.getTime())) throw new Error(`Cannot parse date: ${value}`);
1327
1560
  return d;
@@ -1335,11 +1568,27 @@ function convertInputsAndSelect(businessDate, processingDatetime, columns, table
1335
1568
  op
1336
1569
  );
1337
1570
  }
1571
+ function convertInputsAndSelectForDateRange(businessDateFrom, businessDateTo, processingDatetime, columns, table, op = new NoOperation()) {
1572
+ if (businessDateFrom == null) throw new Error("businessDateFrom is required for findForDateRange");
1573
+ if (businessDateTo == null) throw new Error("businessDateTo is required for findForDateRange");
1574
+ if (processingDatetime == null) throw new Error("processingValidAt is required for findForDateRange");
1575
+ return new FinderResult(
1576
+ convertDate(businessDateFrom),
1577
+ convertDate(processingDatetime),
1578
+ columns,
1579
+ table,
1580
+ op,
1581
+ convertDate(businessDateTo)
1582
+ );
1583
+ }
1338
1584
  // Annotate the CommonJS export names for ESM import in node:
1339
1585
  0 && (module.exports = {
1586
+ DEFAULT_TIMEOUT_MS,
1340
1587
  FinderResult,
1588
+ QueryTimeoutError,
1341
1589
  clearRunner,
1342
1590
  convertInputsAndSelect,
1591
+ convertInputsAndSelectForDateRange,
1343
1592
  getRunner,
1344
1593
  registerRunner
1345
1594
  });