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,7 +20,6 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/datafinder/sql-generator.ts
21
21
  var sql_generator_exports = {};
22
22
  __export(sql_generator_exports, {
23
- SelectOperation: () => SelectOperation,
24
23
  buildQueryOperation: () => buildQueryOperation,
25
24
  selectSqlToString: () => selectSqlToString,
26
25
  toSql: () => toSql
@@ -264,13 +263,19 @@ var Table = class {
264
263
  }
265
264
  };
266
265
  var ColumnWithJoin = class extends RelationalOperationElement {
267
- constructor(column, parent) {
266
+ /**
267
+ * `embedded` is an alternate reference to a flat (denormalized) column on the owning table that
268
+ * holds the same value without the join; the SQL generator uses it when the join can be elided.
269
+ */
270
+ constructor(column, parent, embedded) {
268
271
  super();
269
272
  this.column = column;
270
273
  this.parent = parent;
274
+ this.embedded = embedded;
271
275
  }
272
276
  column;
273
277
  parent;
278
+ embedded;
274
279
  };
275
280
  var SortOperation = class {
276
281
  constructor(column, direction) {
@@ -287,18 +292,67 @@ var CountAllOperation = class extends RelationalOperationElement {
287
292
  }
288
293
  table;
289
294
  };
295
+ var Alias = class extends RelationalOperationElement {
296
+ constructor(element, name) {
297
+ super();
298
+ this.element = element;
299
+ this.name = name;
300
+ }
301
+ element;
302
+ name;
303
+ };
304
+ var ExistsOperation = class extends RelationalOperationElement {
305
+ constructor(node) {
306
+ super();
307
+ this.node = node;
308
+ }
309
+ node;
310
+ andOp(other) {
311
+ return new LogicalOperation(this, "AND" /* AND */, other);
312
+ }
313
+ };
314
+ var NotExistsOperation = class extends RelationalOperationElement {
315
+ constructor(node) {
316
+ super();
317
+ this.node = node;
318
+ }
319
+ node;
320
+ andOp(other) {
321
+ return new LogicalOperation(this, "AND" /* AND */, other);
322
+ }
323
+ };
324
+ var SelectOperation = class {
325
+ constructor(display, filter, orderBy = [], groupBy = [], limit, table, joinFilters = /* @__PURE__ */ new Map()) {
326
+ this.display = display;
327
+ this.filter = filter;
328
+ this.orderBy = orderBy;
329
+ this.groupBy = groupBy;
330
+ this.limit = limit;
331
+ this.table = table;
332
+ this.joinFilters = joinFilters;
333
+ }
334
+ display;
335
+ filter;
336
+ orderBy;
337
+ groupBy;
338
+ limit;
339
+ table;
340
+ joinFilters;
341
+ };
290
342
 
291
343
  // src/datafinder/attribute.ts
292
- var Attribute = class {
344
+ var Attribute = class _Attribute {
293
345
  _displayName;
294
346
  _column;
295
347
  _owner;
296
348
  _parent;
297
- constructor(displayName, columnName, columnDbType, owner, parent) {
349
+ _embedded;
350
+ constructor(displayName, columnName, columnDbType, owner, parent, embedded) {
298
351
  this._displayName = displayName;
299
352
  this._column = new Column(columnName, columnDbType, owner);
300
353
  this._owner = owner;
301
354
  this._parent = parent;
355
+ this._embedded = embedded;
302
356
  }
303
357
  column() {
304
358
  return this._column;
@@ -312,33 +366,58 @@ var Attribute = class {
312
366
  displayName() {
313
367
  return this._displayName;
314
368
  }
369
+ /** Alternate attribute on a flat column of the owning table, used in place of this one when its join is elided. */
370
+ embedded() {
371
+ return this._embedded;
372
+ }
315
373
  cwj() {
316
- return new ColumnWithJoin(this._column, this._parent);
374
+ return new ColumnWithJoin(this._column, this._parent, this._embedded?.cwj());
317
375
  }
376
+ /** Count the number of non-null values. Use in a projection with `groupByOp` to aggregate per group. */
318
377
  count() {
319
378
  return new AggregateOperation(
320
- new ColumnWithJoin(this._column, this._parent),
379
+ this.cwj(),
321
380
  "COUNT" /* COUNT */,
322
381
  this._displayName + " Count"
323
382
  );
324
383
  }
384
+ /** Sort this attribute in ascending order. Pass to `orderByOp` or a window function's `orderBy`. */
325
385
  ascending() {
326
- return new SortOperation(new ColumnWithJoin(this._column, this._parent), "ASC" /* ASC */);
386
+ return new SortOperation(this.cwj(), "ASC" /* ASC */);
327
387
  }
388
+ /** Sort this attribute in descending order. Pass to `orderByOp` or a window function's `orderBy`. */
328
389
  descending() {
329
- return new SortOperation(new ColumnWithJoin(this._column, this._parent), "DESC" /* DESC */);
390
+ return new SortOperation(this.cwj(), "DESC" /* DESC */);
330
391
  }
392
+ /** Filter to rows where this attribute has no value. */
331
393
  isNull() {
332
- return new IsNullOperation(new ColumnWithJoin(this._column, this._parent));
394
+ return new IsNullOperation(this.cwj());
333
395
  }
396
+ /** Filter to rows where this attribute has a value. */
334
397
  isNotNull() {
335
- return new IsNotNullOperation(new ColumnWithJoin(this._column, this._parent));
398
+ return new IsNotNullOperation(this.cwj());
336
399
  }
337
400
  _windowSpec(partitionBy, orderBy) {
338
- const pb = partitionBy === void 0 ? [] : Array.isArray(partitionBy) ? partitionBy : [partitionBy];
401
+ const pbArr = partitionBy === void 0 ? [] : Array.isArray(partitionBy) ? partitionBy : [partitionBy];
402
+ const pb = pbArr.map((x) => x instanceof _Attribute ? x.cwj() : x);
339
403
  const ob = orderBy === void 0 ? [] : Array.isArray(orderBy) ? orderBy : [orderBy];
340
404
  return new WindowSpecification(pb, ob);
341
405
  }
406
+ /**
407
+ * Assign a rank to each row within the ordered window, following pandas `Series.rank` conventions.
408
+ *
409
+ * `method` controls tie-breaking (default `'min'`):
410
+ * - `'min'` — tied rows share the lowest rank; the next rank skips.
411
+ * - `'dense'` — like `'min'` but ranks are contiguous (no gaps).
412
+ * - `'first'` — each row gets a unique sequential integer (no ties).
413
+ * - `'max'` — only meaningful with `pct: true` (see below).
414
+ *
415
+ * When `pct: true` the result is a relative rank between 0 and 1:
416
+ * - `method: 'min'` (default) → fraction of values strictly below this row (PERCENT_RANK).
417
+ * - `method: 'max'` → fraction of values at or below this row (cumulative distribution).
418
+ *
419
+ * `partitionBy` restarts the ranking within each group of distinct values.
420
+ */
342
421
  rank(opts = {}) {
343
422
  const { method = "min", pct = false, partitionBy, orderBy } = opts;
344
423
  let func;
@@ -363,6 +442,11 @@ var Attribute = class {
363
442
  }
364
443
  return new WindowFunctionOperation(null, func, name, void 0, [], this._windowSpec(partitionBy, orderBy));
365
444
  }
445
+ /**
446
+ * Split rows into `buckets` equal-sized quantile bins ordered by `orderBy`.
447
+ * Each row receives a bucket number from 1 (lowest) to `buckets` (highest).
448
+ * Named after `pandas.qcut`.
449
+ */
366
450
  qcut(buckets, opts = {}) {
367
451
  return new WindowFunctionOperation(
368
452
  null,
@@ -373,12 +457,17 @@ var Attribute = class {
373
457
  this._windowSpec(opts.partitionBy, opts.orderBy)
374
458
  );
375
459
  }
460
+ /**
461
+ * Return the value of this attribute from `periods` rows earlier (positive) or later (negative)
462
+ * within the ordered window, following `pandas.Series.shift`.
463
+ * Rows with no neighbour at the given offset return `null` (or `fillValue` if provided).
464
+ */
376
465
  shift(periods = 1, opts = {}) {
377
466
  const extraArgs = opts.fillValue !== void 0 ? [opts.fillValue] : [];
378
467
  const func = periods >= 0 ? "LAG" /* LAG */ : "LEAD" /* LEAD */;
379
468
  const label = periods >= 0 ? "Lag" : "Lead";
380
469
  return new WindowFunctionOperation(
381
- new ColumnWithJoin(this._column, this._parent),
470
+ this.cwj(),
382
471
  func,
383
472
  label + " " + this._displayName,
384
473
  Math.abs(periods),
@@ -386,9 +475,13 @@ var Attribute = class {
386
475
  this._windowSpec(opts.partitionBy, opts.orderBy)
387
476
  );
388
477
  }
478
+ /**
479
+ * Return the first value of this attribute in the window frame.
480
+ * Use `partitionBy` to restart the frame for each group.
481
+ */
389
482
  first(opts = {}) {
390
483
  return new WindowFunctionOperation(
391
- new ColumnWithJoin(this._column, this._parent),
484
+ this.cwj(),
392
485
  "FIRST_VALUE" /* FIRST_VALUE */,
393
486
  "First " + this._displayName,
394
487
  void 0,
@@ -396,9 +489,13 @@ var Attribute = class {
396
489
  this._windowSpec(opts.partitionBy, opts.orderBy)
397
490
  );
398
491
  }
492
+ /**
493
+ * Return the last value of this attribute in the window frame.
494
+ * Use `partitionBy` to restart the frame for each group.
495
+ */
399
496
  last(opts = {}) {
400
497
  return new WindowFunctionOperation(
401
- new ColumnWithJoin(this._column, this._parent),
498
+ this.cwj(),
402
499
  "LAST_VALUE" /* LAST_VALUE */,
403
500
  "Last " + this._displayName,
404
501
  void 0,
@@ -493,209 +590,233 @@ function parseDate(value) {
493
590
  return d;
494
591
  }
495
592
  var DateAttribute = class extends Attribute {
496
- constructor(displayName, columnName, columnDbType, owner, parent) {
497
- super(displayName, columnName, columnDbType, owner, parent);
593
+ constructor(displayName, columnName, columnDbType, owner, parent, embedded) {
594
+ super(displayName, columnName, columnDbType, owner, parent, embedded);
498
595
  }
596
+ /** Filter to rows where this date equals `value`. */
499
597
  eq(value) {
500
598
  return new ComparisonOperation(this.cwj(), "EQUAL" /* EQUAL */, new DateConstantOperation(parseDate(value)));
501
599
  }
600
+ /** Filter to rows where this date does not equal `value`. */
502
601
  ne(value) {
503
602
  return new ComparisonOperation(this.cwj(), "NOT_EQUAL" /* NOT_EQUAL */, new DateConstantOperation(parseDate(value)));
504
603
  }
604
+ /** Filter to rows where this date is after `value`. */
505
605
  gt(value) {
506
606
  return new ComparisonOperation(this.cwj(), "GREATER_THAN" /* GREATER_THAN */, new DateConstantOperation(parseDate(value)));
507
607
  }
608
+ /** Filter to rows where this date is before `value`. */
508
609
  lt(value) {
509
610
  return new ComparisonOperation(this.cwj(), "LESS_THAN" /* LESS_THAN */, new DateConstantOperation(parseDate(value)));
510
611
  }
612
+ /** Filter to rows where this date is on or after `value`. */
511
613
  gte(value) {
512
614
  return new ComparisonOperation(this.cwj(), "GREATER_THAN_OR_EQUAL_TO" /* GREATER_THAN_OR_EQUAL_TO */, new DateConstantOperation(parseDate(value)));
513
615
  }
616
+ /** Filter to rows where this date is on or before `value`. */
514
617
  lte(value) {
515
618
  return new ComparisonOperation(this.cwj(), "LESS_THAN_OR_EQUAL_TO" /* LESS_THAN_OR_EQUAL_TO */, new DateConstantOperation(parseDate(value)));
516
619
  }
620
+ /** Extract the four-digit calendar year. */
517
621
  year() {
518
622
  return new DateExtractOperation(this.cwj(), "YEAR" /* YEAR */, "Year " + this.displayName());
519
623
  }
624
+ /** Extract the month number (1–12). */
520
625
  month() {
521
626
  return new DateExtractOperation(this.cwj(), "MONTH" /* MONTH */, "Month " + this.displayName());
522
627
  }
628
+ /** Extract the day of the month (1–31). */
523
629
  day() {
524
630
  return new DateExtractOperation(this.cwj(), "DAY" /* DAY */, "Day " + this.displayName());
525
631
  }
632
+ /** Extract the quarter (1–4). */
526
633
  quarter() {
527
634
  return new DateExtractOperation(this.cwj(), "QUARTER" /* QUARTER */, "Quarter " + this.displayName());
528
635
  }
636
+ /** Extract the ISO week number (1–53). */
529
637
  week() {
530
638
  return new DateExtractOperation(this.cwj(), "WEEK" /* WEEK */, "Week " + this.displayName());
531
639
  }
640
+ /** Extract the day of the week (0 = Sunday through 6 = Saturday). */
532
641
  dayOfWeek() {
533
642
  return new DateExtractOperation(this.cwj(), "DOW" /* DOW */, "Day Of Week " + this.displayName());
534
643
  }
644
+ /** Add `n` days to this date. */
535
645
  addDays(n) {
536
646
  return new DateArithmeticOperation(this.cwj(), n, "DAY" /* DAY */, true, "Add Days " + this.displayName());
537
647
  }
648
+ /** Add `n` months to this date. */
538
649
  addMonths(n) {
539
650
  return new DateArithmeticOperation(this.cwj(), n, "MONTH" /* MONTH */, true, "Add Months " + this.displayName());
540
651
  }
652
+ /** Add `n` years to this date. */
541
653
  addYears(n) {
542
654
  return new DateArithmeticOperation(this.cwj(), n, "YEAR" /* YEAR */, true, "Add Years " + this.displayName());
543
655
  }
656
+ /** Subtract `n` days from this date. */
544
657
  subtractDays(n) {
545
658
  return new DateArithmeticOperation(this.cwj(), n, "DAY" /* DAY */, false, "Subtract Days " + this.displayName());
546
659
  }
660
+ /** Subtract `n` months from this date. */
547
661
  subtractMonths(n) {
548
662
  return new DateArithmeticOperation(this.cwj(), n, "MONTH" /* MONTH */, false, "Subtract Months " + this.displayName());
549
663
  }
664
+ /** Subtract `n` years from this date. */
550
665
  subtractYears(n) {
551
666
  return new DateArithmeticOperation(this.cwj(), n, "YEAR" /* YEAR */, false, "Subtract Years " + this.displayName());
552
667
  }
668
+ /** Number of whole days between this date and `other`. */
553
669
  diffDays(other) {
554
670
  return new DateDiffOperation(this.cwj(), other, "DAY" /* DAY */, "Diff Days " + this.displayName());
555
671
  }
672
+ /** Number of whole months between this date and `other`. */
556
673
  diffMonths(other) {
557
674
  return new DateDiffOperation(this.cwj(), other, "MONTH" /* MONTH */, "Diff Months " + this.displayName());
558
675
  }
676
+ /** Number of whole years between this date and `other`. */
559
677
  diffYears(other) {
560
678
  return new DateDiffOperation(this.cwj(), other, "YEAR" /* YEAR */, "Diff Years " + this.displayName());
561
679
  }
562
680
  };
563
681
  var DateTimeAttribute = class extends Attribute {
564
- constructor(displayName, columnName, columnDbType, owner, parent) {
565
- super(displayName, columnName, columnDbType, owner, parent);
682
+ constructor(displayName, columnName, columnDbType, owner, parent, embedded) {
683
+ super(displayName, columnName, columnDbType, owner, parent, embedded);
566
684
  }
685
+ /** Filter to rows where this timestamp equals `value`. */
567
686
  eq(value) {
568
687
  return new ComparisonOperation(this.cwj(), "EQUAL" /* EQUAL */, new DateTimeConstantOperation(parseDate(value)));
569
688
  }
689
+ /** Filter to rows where this timestamp does not equal `value`. */
570
690
  ne(value) {
571
691
  return new ComparisonOperation(this.cwj(), "NOT_EQUAL" /* NOT_EQUAL */, new DateTimeConstantOperation(parseDate(value)));
572
692
  }
693
+ /** Filter to rows where this timestamp is after `value`. */
573
694
  gt(value) {
574
695
  return new ComparisonOperation(this.cwj(), "GREATER_THAN" /* GREATER_THAN */, new DateTimeConstantOperation(parseDate(value)));
575
696
  }
697
+ /** Filter to rows where this timestamp is before `value`. */
576
698
  lt(value) {
577
699
  return new ComparisonOperation(this.cwj(), "LESS_THAN" /* LESS_THAN */, new DateTimeConstantOperation(parseDate(value)));
578
700
  }
701
+ /** Filter to rows where this timestamp is on or after `value`. */
579
702
  gte(value) {
580
703
  return new ComparisonOperation(this.cwj(), "GREATER_THAN_OR_EQUAL_TO" /* GREATER_THAN_OR_EQUAL_TO */, new DateTimeConstantOperation(parseDate(value)));
581
704
  }
705
+ /** Filter to rows where this timestamp is on or before `value`. */
582
706
  lte(value) {
583
707
  return new ComparisonOperation(this.cwj(), "LESS_THAN_OR_EQUAL_TO" /* LESS_THAN_OR_EQUAL_TO */, new DateTimeConstantOperation(parseDate(value)));
584
708
  }
709
+ /** Extract the four-digit calendar year. */
585
710
  year() {
586
711
  return new DateExtractOperation(this.cwj(), "YEAR" /* YEAR */, "Year " + this.displayName());
587
712
  }
713
+ /** Extract the month number (1–12). */
588
714
  month() {
589
715
  return new DateExtractOperation(this.cwj(), "MONTH" /* MONTH */, "Month " + this.displayName());
590
716
  }
717
+ /** Extract the day of the month (1–31). */
591
718
  day() {
592
719
  return new DateExtractOperation(this.cwj(), "DAY" /* DAY */, "Day " + this.displayName());
593
720
  }
721
+ /** Extract the hour (0–23). */
594
722
  hour() {
595
723
  return new DateExtractOperation(this.cwj(), "HOUR" /* HOUR */, "Hour " + this.displayName());
596
724
  }
725
+ /** Extract the minute (0–59). */
597
726
  minute() {
598
727
  return new DateExtractOperation(this.cwj(), "MINUTE" /* MINUTE */, "Minute " + this.displayName());
599
728
  }
729
+ /** Extract the second (0–59). */
600
730
  second() {
601
731
  return new DateExtractOperation(this.cwj(), "SECOND" /* SECOND */, "Second " + this.displayName());
602
732
  }
733
+ /** Extract the quarter (1–4). */
603
734
  quarter() {
604
735
  return new DateExtractOperation(this.cwj(), "QUARTER" /* QUARTER */, "Quarter " + this.displayName());
605
736
  }
737
+ /** Extract the ISO week number (1–53). */
606
738
  week() {
607
739
  return new DateExtractOperation(this.cwj(), "WEEK" /* WEEK */, "Week " + this.displayName());
608
740
  }
741
+ /** Extract the day of the week (0 = Sunday through 6 = Saturday). */
609
742
  dayOfWeek() {
610
743
  return new DateExtractOperation(this.cwj(), "DOW" /* DOW */, "Day Of Week " + this.displayName());
611
744
  }
745
+ /** Add `n` days to this timestamp. */
612
746
  addDays(n) {
613
747
  return new DateArithmeticOperation(this.cwj(), n, "DAY" /* DAY */, true, "Add Days " + this.displayName());
614
748
  }
749
+ /** Add `n` months to this timestamp. */
615
750
  addMonths(n) {
616
751
  return new DateArithmeticOperation(this.cwj(), n, "MONTH" /* MONTH */, true, "Add Months " + this.displayName());
617
752
  }
753
+ /** Add `n` years to this timestamp. */
618
754
  addYears(n) {
619
755
  return new DateArithmeticOperation(this.cwj(), n, "YEAR" /* YEAR */, true, "Add Years " + this.displayName());
620
756
  }
757
+ /** Add `n` hours to this timestamp. */
621
758
  addHours(n) {
622
759
  return new DateArithmeticOperation(this.cwj(), n, "HOUR" /* HOUR */, true, "Add Hours " + this.displayName());
623
760
  }
761
+ /** Add `n` minutes to this timestamp. */
624
762
  addMinutes(n) {
625
763
  return new DateArithmeticOperation(this.cwj(), n, "MINUTE" /* MINUTE */, true, "Add Minutes " + this.displayName());
626
764
  }
765
+ /** Add `n` seconds to this timestamp. */
627
766
  addSeconds(n) {
628
767
  return new DateArithmeticOperation(this.cwj(), n, "SECOND" /* SECOND */, true, "Add Seconds " + this.displayName());
629
768
  }
769
+ /** Subtract `n` days from this timestamp. */
630
770
  subtractDays(n) {
631
771
  return new DateArithmeticOperation(this.cwj(), n, "DAY" /* DAY */, false, "Subtract Days " + this.displayName());
632
772
  }
773
+ /** Subtract `n` months from this timestamp. */
633
774
  subtractMonths(n) {
634
775
  return new DateArithmeticOperation(this.cwj(), n, "MONTH" /* MONTH */, false, "Subtract Months " + this.displayName());
635
776
  }
777
+ /** Subtract `n` years from this timestamp. */
636
778
  subtractYears(n) {
637
779
  return new DateArithmeticOperation(this.cwj(), n, "YEAR" /* YEAR */, false, "Subtract Years " + this.displayName());
638
780
  }
781
+ /** Subtract `n` hours from this timestamp. */
639
782
  subtractHours(n) {
640
783
  return new DateArithmeticOperation(this.cwj(), n, "HOUR" /* HOUR */, false, "Subtract Hours " + this.displayName());
641
784
  }
785
+ /** Subtract `n` minutes from this timestamp. */
642
786
  subtractMinutes(n) {
643
787
  return new DateArithmeticOperation(this.cwj(), n, "MINUTE" /* MINUTE */, false, "Subtract Minutes " + this.displayName());
644
788
  }
789
+ /** Subtract `n` seconds from this timestamp. */
645
790
  subtractSeconds(n) {
646
791
  return new DateArithmeticOperation(this.cwj(), n, "SECOND" /* SECOND */, false, "Subtract Seconds " + this.displayName());
647
792
  }
793
+ /** Number of whole days between this timestamp and `other`. */
648
794
  diffDays(other) {
649
795
  return new DateDiffOperation(this.cwj(), other, "DAY" /* DAY */, "Diff Days " + this.displayName());
650
796
  }
797
+ /** Number of whole months between this timestamp and `other`. */
651
798
  diffMonths(other) {
652
799
  return new DateDiffOperation(this.cwj(), other, "MONTH" /* MONTH */, "Diff Months " + this.displayName());
653
800
  }
801
+ /** Number of whole years between this timestamp and `other`. */
654
802
  diffYears(other) {
655
803
  return new DateDiffOperation(this.cwj(), other, "YEAR" /* YEAR */, "Diff Years " + this.displayName());
656
804
  }
805
+ /** Number of whole hours between this timestamp and `other`. */
657
806
  diffHours(other) {
658
807
  return new DateDiffOperation(this.cwj(), other, "HOUR" /* HOUR */, "Diff Hours " + this.displayName());
659
808
  }
809
+ /** Number of whole minutes between this timestamp and `other`. */
660
810
  diffMinutes(other) {
661
811
  return new DateDiffOperation(this.cwj(), other, "MINUTE" /* MINUTE */, "Diff Minutes " + this.displayName());
662
812
  }
813
+ /** Number of whole seconds between this timestamp and `other`. */
663
814
  diffSeconds(other) {
664
815
  return new DateDiffOperation(this.cwj(), other, "SECOND" /* SECOND */, "Diff Seconds " + this.displayName());
665
816
  }
666
817
  };
667
818
 
668
- // src/datafinder/finder.ts
669
- var ExistsOperation = class extends RelationalOperationElement {
670
- constructor(node) {
671
- super();
672
- this.node = node;
673
- }
674
- node;
675
- andOp(other) {
676
- return new LogicalOperation(this, "AND" /* AND */, other);
677
- }
678
- };
679
- var NotExistsOperation = class extends RelationalOperationElement {
680
- constructor(node) {
681
- super();
682
- this.node = node;
683
- }
684
- node;
685
- andOp(other) {
686
- return new LogicalOperation(this, "AND" /* AND */, other);
687
- }
688
- };
689
-
690
819
  // src/datafinder/sql-generator.ts
691
- var Alias = class {
692
- constructor(element, name) {
693
- this.element = element;
694
- this.name = name;
695
- }
696
- element;
697
- name;
698
- };
699
820
  var TableAlias = class {
700
821
  constructor(table, alias) {
701
822
  this.table = table;
@@ -723,22 +844,6 @@ var Join = class {
723
844
  target;
724
845
  filterOp;
725
846
  };
726
- var SelectOperation = class {
727
- constructor(display, filter, orderBy = [], groupBy = [], limit, table) {
728
- this.display = display;
729
- this.filter = filter;
730
- this.orderBy = orderBy;
731
- this.groupBy = groupBy;
732
- this.limit = limit;
733
- this.table = table;
734
- }
735
- display;
736
- filter;
737
- orderBy;
738
- groupBy;
739
- limit;
740
- table;
741
- };
742
847
  function sqlFormatDatetime(value) {
743
848
  const pad = (n, w = 2) => String(n).padStart(w, "0");
744
849
  return `'${value.getUTCFullYear()}-${pad(value.getUTCMonth() + 1)}-${pad(value.getUTCDate())} ${pad(value.getUTCHours())}:${pad(value.getUTCMinutes())}:${pad(value.getUTCSeconds())}'`;
@@ -870,6 +975,9 @@ function sqlOperationToString(operation) {
870
975
  }
871
976
  throw new TypeError("Unknown operation in sqlOperationToString: " + operation.constructor.name);
872
977
  }
978
+ function embeddedOf(ref) {
979
+ return ref instanceof Attribute ? ref.embedded() : ref.embedded;
980
+ }
873
981
  function findColumn(operation) {
874
982
  if (operation instanceof UnaryOperation) return findColumn(operation.element);
875
983
  if (operation instanceof ColumnWithJoin) return operation;
@@ -919,38 +1027,125 @@ function buildMilestoningFilterOperation(businessDate, processingDatetime, table
919
1027
  if (ops.length === 1) return ops[0];
920
1028
  return new LogicalOperation(ops[0], "AND" /* AND */, ops[1]);
921
1029
  }
922
- function buildQueryOperation(businessDate, processingDatetime, columns, table, op, orderBy = [], groupBy = [], limit) {
1030
+ function buildMilestoningFilterOperationForDateRange(businessDateFrom, businessDateTo, processingDatetime, table, joinNode) {
1031
+ const mc = table.milestoningColumns;
1032
+ const ops = [];
1033
+ const hasRange = businessDateFrom !== null && businessDateTo !== null;
1034
+ const processingOp = (m) => {
1035
+ const startAt = new DateTimeAttribute("start_at", m.startAtColumn.name, m.startAtColumn.type, m.startAtColumn.table.qualifiedName, joinNode);
1036
+ const endAt = new DateTimeAttribute("end_at", m.endAtColumn.name, m.endAtColumn.type, m.endAtColumn.table.qualifiedName, joinNode);
1037
+ return new LogicalOperation(startAt.lte(processingDatetime), "AND" /* AND */, openEndClause(endAt, processingDatetime, m.infiniteDatetime));
1038
+ };
1039
+ if (mc instanceof BiTemporalColumns) {
1040
+ if (hasRange) {
1041
+ const dateFrom = new DateAttribute("business_date_from", mc.businessDateFromColumn.name, mc.businessDateFromColumn.type, mc.businessDateFromColumn.table.qualifiedName, joinNode);
1042
+ const dateTo = new DateAttribute("business_date_to", mc.businessDateToColumn.name, mc.businessDateToColumn.type, mc.businessDateToColumn.table.qualifiedName, joinNode);
1043
+ ops.push(new LogicalOperation(dateFrom.lte(businessDateTo), "AND" /* AND */, openEndClause(dateTo, businessDateFrom, mc.infiniteDatetime)));
1044
+ }
1045
+ if (processingDatetime !== null) ops.push(processingOp(mc));
1046
+ } else if (mc instanceof BusinessDateAndProcessingTemporalColumns) {
1047
+ if (hasRange) {
1048
+ const businessAtt = new DateAttribute("business_date", mc.businessDateColumn.name, mc.businessDateColumn.type, mc.businessDateColumn.table.qualifiedName, joinNode);
1049
+ ops.push(new LogicalOperation(businessAtt.gte(businessDateFrom), "AND" /* AND */, businessAtt.lte(businessDateTo)));
1050
+ }
1051
+ if (processingDatetime !== null) ops.push(processingOp(mc));
1052
+ } else if (mc instanceof ProcessingTemporalColumns) {
1053
+ if (processingDatetime !== null) ops.push(processingOp(mc));
1054
+ } else if (mc instanceof SingleBusinessDateColumn && hasRange) {
1055
+ const businessAtt = new DateAttribute("business_date", mc.businessDateColumn.name, mc.businessDateColumn.type, mc.businessDateColumn.table.qualifiedName, joinNode);
1056
+ ops.push(new LogicalOperation(businessAtt.gte(businessDateFrom), "AND" /* AND */, businessAtt.lte(businessDateTo)));
1057
+ }
1058
+ if (ops.length === 0) return null;
1059
+ if (ops.length === 1) return ops[0];
1060
+ return new LogicalOperation(ops[0], "AND" /* AND */, ops[1]);
1061
+ }
1062
+ function walkRefs(op, visit, visitExists) {
1063
+ if (op === null || op === void 0) return;
1064
+ if (op instanceof Attribute || op instanceof ColumnWithJoin) {
1065
+ visit(op);
1066
+ } else if (op instanceof ExistsOperation || op instanceof NotExistsOperation) {
1067
+ visitExists?.(op.node);
1068
+ } else if (op instanceof AggregateOperation) {
1069
+ walkRefs(op.element, visit, visitExists);
1070
+ if (op.window) walkWindowSpec(op.window, visit, visitExists);
1071
+ } else if (op instanceof WindowFunctionOperation) {
1072
+ if (op.element) walkRefs(op.element, visit, visitExists);
1073
+ if (op.window) walkWindowSpec(op.window, visit, visitExists);
1074
+ } else if (op instanceof ScalarFunctionOperation || op instanceof DateExtractOperation || op instanceof DateArithmeticOperation || op instanceof DateDiffOperation || op instanceof IsNullOperation || op instanceof IsNotNullOperation) {
1075
+ walkRefs(op.element, visit, visitExists);
1076
+ } else if (op instanceof SortOperation) {
1077
+ walkRefs(op.column, visit, visitExists);
1078
+ } else if (op instanceof LogicalOperation || op instanceof ComparisonOperation) {
1079
+ walkRefs(op.left, visit, visitExists);
1080
+ walkRefs(op.right, visit, visitExists);
1081
+ }
1082
+ }
1083
+ function walkWindowSpec(window, visit, visitExists) {
1084
+ for (const p of window.partitionBy) walkRefs(p, visit, visitExists);
1085
+ for (const s of window.orderBy) walkRefs(s.column, visit, visitExists);
1086
+ }
1087
+ function buildJoinFilterFromProperties(node, filter, columnMap) {
1088
+ const ops = [];
1089
+ for (const [key, value] of Object.entries(filter)) {
1090
+ const entry = columnMap[key];
1091
+ if (entry === void 0) {
1092
+ throw new Error(`Unknown property '${key}' \u2014 valid properties are: ${Object.keys(columnMap).sort().join(", ")}`);
1093
+ }
1094
+ const [name, type, table] = entry;
1095
+ const col = new ColumnWithJoin(new Column(name, type, table), node);
1096
+ let constant;
1097
+ if (typeof value === "boolean") constant = new BooleanConstantOperation(value);
1098
+ else if (typeof value === "number") constant = Number.isInteger(value) ? new IntegerConstantOperation(value) : new FloatConstantOperation(value);
1099
+ else if (value instanceof Date) constant = type.toUpperCase() === "DATE" ? new DateConstantOperation(value) : new DateTimeConstantOperation(value);
1100
+ else constant = new StringConstantOperation(String(value));
1101
+ ops.push(new ComparisonOperation(col, "EQUAL" /* EQUAL */, constant));
1102
+ }
1103
+ return ops.reduce((acc, op) => new LogicalOperation(acc, "AND" /* AND */, op));
1104
+ }
1105
+ function withAncestors(nodes) {
1106
+ const ordered = /* @__PURE__ */ new Set();
1107
+ const add = (node) => {
1108
+ if (ordered.has(node)) return;
1109
+ if (node.parent !== void 0) add(node.parent);
1110
+ ordered.add(node);
1111
+ };
1112
+ for (const node of nodes) add(node);
1113
+ return [...ordered];
1114
+ }
1115
+ function buildQueryOperation(businessDate, processingDatetime, columns, table, op, orderBy = [], groupBy = [], limit, businessDateTo = null) {
923
1116
  let filter = op;
1117
+ const milestoningFor = (t, node) => businessDateTo !== null ? buildMilestoningFilterOperationForDateRange(businessDate, businessDateTo, processingDatetime, t, node) : buildMilestoningFilterOperation(businessDate, processingDatetime, t, node);
924
1118
  if (table instanceof MilestonedTable) {
925
- const milestonedOp = buildMilestoningFilterOperation(businessDate, processingDatetime, table);
1119
+ const milestonedOp = milestoningFor(table);
926
1120
  if (milestonedOp !== null) {
927
1121
  filter = filter instanceof NoOperation ? milestonedOp : new LogicalOperation(filter, "AND" /* AND */, milestonedOp);
928
1122
  }
929
1123
  }
930
- const requiredJoins = [];
931
- const requiredJoinIds = /* @__PURE__ */ new Set();
932
- for (const col of columns) {
933
- if (col instanceof CountAllOperation) continue;
934
- let node;
935
- if (col instanceof Attribute) {
936
- node = col.parent();
937
- } else {
938
- node = findColumn(col).parent;
939
- }
940
- if (node !== void 0 && !requiredJoinIds.has(node)) {
941
- requiredJoinIds.add(node);
942
- requiredJoins.push(node);
1124
+ const requiredJoins = /* @__PURE__ */ new Set();
1125
+ const collect = (ref) => {
1126
+ const parent = ref instanceof Attribute ? ref.parent() : ref.parent;
1127
+ if (parent !== void 0) requiredJoins.add(parent);
1128
+ };
1129
+ const collectNode = (node) => requiredJoins.add(node);
1130
+ for (const col of columns) walkRefs(col, collect, collectNode);
1131
+ for (const expr of groupBy) walkRefs(expr, collect, collectNode);
1132
+ for (const sort of orderBy) walkRefs(sort, collect, collectNode);
1133
+ walkRefs(op, collect, collectNode);
1134
+ const joinFilters = /* @__PURE__ */ new Map();
1135
+ for (const node of withAncestors(requiredJoins)) {
1136
+ let combined;
1137
+ if (Object.keys(node.join.filterKwargs).length > 0) {
1138
+ combined = buildJoinFilterFromProperties(node, node.join.filterKwargs, node.join.filterColumnMap);
943
1139
  }
944
- }
945
- for (const node of requiredJoins) {
946
1140
  if (node.join.target instanceof MilestonedTable) {
947
- const milestonedOp = buildMilestoningFilterOperation(businessDate, processingDatetime, node.join.target, node);
1141
+ const milestonedOp = milestoningFor(node.join.target, node);
948
1142
  if (milestonedOp !== null) {
949
- node.join.filter = milestonedOp;
1143
+ combined = combined === void 0 ? milestonedOp : new LogicalOperation(combined, "AND" /* AND */, milestonedOp);
950
1144
  }
951
1145
  }
1146
+ if (combined !== void 0) joinFilters.set(node, combined);
952
1147
  }
953
- return new SelectOperation(columns, filter, orderBy, groupBy, limit, table);
1148
+ return new SelectOperation(columns, filter, orderBy, groupBy, limit, table, joinFilters);
954
1149
  }
955
1150
  var SQLQueryGenerator = class {
956
1151
  _select = [];
@@ -964,8 +1159,12 @@ var SQLQueryGenerator = class {
964
1159
  _tableAliasesByTable = /* @__PURE__ */ new Map();
965
1160
  _addedJoinIds = /* @__PURE__ */ new Set();
966
1161
  _rootTable;
1162
+ _elidableNodes = /* @__PURE__ */ new Set();
1163
+ _joinFilters = /* @__PURE__ */ new Map();
967
1164
  generate(select) {
968
1165
  this._rootTable = select.table;
1166
+ this._elidableNodes = this._computeElidableNodes(select);
1167
+ this._joinFilters = select.joinFilters;
969
1168
  if (this._rootTable !== void 0) {
970
1169
  this._from.add(this._tableAliasForTable(this._rootTable.qualifiedName, this._rootTable.qualifiedName));
971
1170
  }
@@ -985,39 +1184,49 @@ var SQLQueryGenerator = class {
985
1184
  this._limit = select.limit;
986
1185
  }
987
1186
  _attrToColString(attr) {
988
- const node = attr.parent();
989
- const ta = this._tableAliasForTable(attr.owner(), node ?? attr.owner());
990
- return ta.alias + "." + attr.column().name;
1187
+ const { column, parent } = this._resolve(attr);
1188
+ const ta = this._tableAliasForTable(column.owner, parent ?? column.owner);
1189
+ return ta.alias + "." + column.name;
991
1190
  }
992
1191
  _collectRequiredJoins(op, out) {
993
- if (op === null || op === void 0) return;
994
- if (op instanceof Attribute) {
995
- const p = op.parent();
996
- if (p !== void 0) out.set(p, p);
997
- } else if (op instanceof ColumnWithJoin) {
998
- if (op.parent !== void 0) out.set(op.parent, op.parent);
999
- } else if (op instanceof AggregateOperation) {
1000
- this._collectRequiredJoins(op.element, out);
1001
- if (op.window) this._collectRequiredJoins(op.window, out);
1002
- } else if (op instanceof WindowFunctionOperation) {
1003
- if (op.element) this._collectRequiredJoins(op.element, out);
1004
- if (op.window) this._collectRequiredJoinsFromWindowSpec(op.window, out);
1005
- } else if (op instanceof ScalarFunctionOperation || op instanceof DateExtractOperation || op instanceof DateArithmeticOperation || op instanceof DateDiffOperation) {
1006
- this._collectRequiredJoins(op.element, out);
1007
- } else if (op instanceof SortOperation) {
1008
- this._collectRequiredJoins(op.column, out);
1009
- } else if (op instanceof LogicalOperation || op instanceof ComparisonOperation) {
1010
- this._collectRequiredJoins(op.left, out);
1011
- this._collectRequiredJoins(op.right, out);
1192
+ walkRefs(op, (ref) => {
1193
+ const { parent } = this._resolve(ref);
1194
+ if (parent !== void 0) out.set(parent, parent);
1195
+ });
1196
+ }
1197
+ /**
1198
+ * Determine upfront which join nodes can be satisfied entirely by embedded (join-less) alternates:
1199
+ * a node is elidable when every reference to it has an embedded alternate. A reference without one
1200
+ * (e.g. a milestoning column) keeps the join for every reference to that node.
1201
+ */
1202
+ _computeElidableNodes(select) {
1203
+ const refsByNode = /* @__PURE__ */ new Map();
1204
+ const record = (ref) => {
1205
+ const parent = ref instanceof Attribute ? ref.parent() : ref.parent;
1206
+ if (parent === void 0) return;
1207
+ const refs = refsByNode.get(parent);
1208
+ if (refs) refs.push(ref);
1209
+ else refsByNode.set(parent, [ref]);
1210
+ };
1211
+ for (const col of select.display) walkRefs(col, record);
1212
+ for (const expr of select.groupBy) walkRefs(expr, record);
1213
+ for (const sort of select.orderBy) walkRefs(sort, record);
1214
+ walkRefs(select.filter, record);
1215
+ const elidable = /* @__PURE__ */ new Set();
1216
+ for (const [node, refs] of refsByNode) {
1217
+ if (refs.every((ref) => embeddedOf(ref) !== void 0)) elidable.add(node);
1012
1218
  }
1013
- }
1014
- _collectRequiredJoinsFromWindowSpec(window, out) {
1015
- for (const p of window.partitionBy) {
1016
- this._collectRequiredJoins(p, out);
1017
- }
1018
- for (const s of window.orderBy) {
1019
- this._collectRequiredJoins(s.column, out);
1219
+ return elidable;
1220
+ }
1221
+ /** The (column, parent) a reference should resolve to, substituting its embedded alternate when its join is elided. */
1222
+ _resolve(ref) {
1223
+ const column = ref instanceof Attribute ? ref.column() : ref.column;
1224
+ const parent = ref instanceof Attribute ? ref.parent() : ref.parent;
1225
+ if (parent !== void 0 && this._elidableNodes.has(parent)) {
1226
+ const embedded = embeddedOf(ref);
1227
+ if (embedded !== void 0) return this._resolve(embedded);
1020
1228
  }
1229
+ return { column, parent };
1021
1230
  }
1022
1231
  _rewriteWindowSpec(window) {
1023
1232
  const partitionBy = window.partitionBy.map((p) => this._rewriteOperation(p));
@@ -1025,13 +1234,9 @@ var SQLQueryGenerator = class {
1025
1234
  return new WindowSpecification(partitionBy, orderBy);
1026
1235
  }
1027
1236
  _rewriteOperation(op) {
1028
- if (op instanceof Attribute) {
1029
- const ta = this._tableAliasForTable(op.owner(), op.parent() ?? op.owner());
1030
- return new TableAliasColumn(op.column(), ta);
1031
- }
1032
- if (op instanceof ColumnWithJoin) {
1033
- const ta = op.parent !== void 0 ? this._tableAliasForTable(op.column.owner, op.parent) : this._tableAliasForTable(op.column.owner, op.column.owner);
1034
- return new TableAliasColumn(op.column, ta);
1237
+ if (op instanceof Attribute || op instanceof ColumnWithJoin) {
1238
+ const { column, parent } = this._resolve(op);
1239
+ return new TableAliasColumn(column, this._tableAliasForTable(column.owner, parent ?? column.owner));
1035
1240
  }
1036
1241
  if (op instanceof Column) {
1037
1242
  const ta = this._tableAliasForTable(op.owner, op.owner);
@@ -1080,15 +1285,15 @@ var SQLQueryGenerator = class {
1080
1285
  }
1081
1286
  for (const col of cols) {
1082
1287
  if (col instanceof Attribute) {
1083
- const node = col.parent();
1288
+ const { column, parent: node } = this._resolve(col);
1084
1289
  let ta;
1085
1290
  if (node !== void 0) {
1086
- ta = this._tableAliasForTable(col.owner(), node);
1291
+ ta = this._tableAliasForTable(column.owner, node);
1087
1292
  } else {
1088
- ta = this._tableAliasForTable(col.owner(), col.owner());
1293
+ ta = this._tableAliasForTable(column.owner, column.owner);
1089
1294
  this._from.add(ta);
1090
1295
  }
1091
- this._select.push(new Alias(new TableAliasColumn(col.column(), ta), col.displayName()));
1296
+ this._select.push(new Alias(new TableAliasColumn(column, ta), col.displayName()));
1092
1297
  } else if (col instanceof WindowFunctionOperation) {
1093
1298
  const rewritten = this._rewriteOperation(col);
1094
1299
  let alias;
@@ -1103,7 +1308,7 @@ var SQLQueryGenerator = class {
1103
1308
  }
1104
1309
  this._select.push(new Alias(rewritten, alias));
1105
1310
  } else if (col instanceof AggregateOperation) {
1106
- const colNested = findColumn(col);
1311
+ const colNested = this._resolve(findColumn(col));
1107
1312
  const node = colNested.parent;
1108
1313
  let ta;
1109
1314
  if (node !== void 0) {
@@ -1112,7 +1317,7 @@ var SQLQueryGenerator = class {
1112
1317
  ta = this._tableAliasForTable(colNested.column.owner, colNested.column.owner);
1113
1318
  this._from.add(ta);
1114
1319
  }
1115
- const alias = col.displayName ?? col.operator + " " + colNested.column.name;
1320
+ const alias = col.displayName ?? col.operator + " " + findColumn(col).column.name;
1116
1321
  const rewrittenAgg = new AggregateOperation(
1117
1322
  new TableAliasColumn(colNested.column, ta),
1118
1323
  col.operator,
@@ -1121,7 +1326,7 @@ var SQLQueryGenerator = class {
1121
1326
  );
1122
1327
  this._select.push(new Alias(rewrittenAgg, alias));
1123
1328
  } else if (col instanceof ScalarFunctionOperation) {
1124
- const colNested = findColumn(col);
1329
+ const colNested = this._resolve(findColumn(col));
1125
1330
  const node = colNested.parent;
1126
1331
  let ta;
1127
1332
  if (node !== void 0) {
@@ -1130,13 +1335,13 @@ var SQLQueryGenerator = class {
1130
1335
  ta = this._tableAliasForTable(colNested.column.owner, colNested.column.owner);
1131
1336
  this._from.add(ta);
1132
1337
  }
1133
- const alias = col.displayName ?? col.func + " " + colNested.column.name;
1338
+ const alias = col.displayName ?? col.func + " " + findColumn(col).column.name;
1134
1339
  this._select.push(new Alias(
1135
1340
  new ScalarFunctionOperation(new TableAliasColumn(colNested.column, ta), col.func, void 0, col.secondArg, col.extraArgs),
1136
1341
  alias
1137
1342
  ));
1138
1343
  } else if (col instanceof DateExtractOperation || col instanceof DateArithmeticOperation || col instanceof DateDiffOperation) {
1139
- const colNested = findColumn(col);
1344
+ const colNested = this._resolve(findColumn(col));
1140
1345
  const node = colNested.parent;
1141
1346
  let ta;
1142
1347
  if (node !== void 0) {
@@ -1145,7 +1350,7 @@ var SQLQueryGenerator = class {
1145
1350
  ta = this._tableAliasForTable(colNested.column.owner, colNested.column.owner);
1146
1351
  this._from.add(ta);
1147
1352
  }
1148
- const alias = col.displayName ?? colNested.column.name;
1353
+ const alias = col.displayName ?? findColumn(col).column.name;
1149
1354
  let aliasedOp;
1150
1355
  if (col instanceof DateExtractOperation) {
1151
1356
  aliasedOp = new DateExtractOperation(new TableAliasColumn(colNested.column, ta), col.part);
@@ -1173,7 +1378,9 @@ var SQLQueryGenerator = class {
1173
1378
  const sc = new TableAliasColumn(left, srcTa);
1174
1379
  const right = join.right;
1175
1380
  const tc = new TableAliasColumn(right, this._tableAliasForTable(right.owner, node));
1176
- this._join.push(new Join(sc, tc, join.filter));
1381
+ const queryFilter = this._joinFilters.get(node);
1382
+ const filterOp = join.filter !== void 0 && queryFilter !== void 0 ? new LogicalOperation(join.filter, "AND" /* AND */, queryFilter) : join.filter ?? queryFilter;
1383
+ this._join.push(new Join(sc, tc, filterOp));
1177
1384
  }
1178
1385
  buildFilter(op) {
1179
1386
  if (op instanceof NoOperation) return "";
@@ -1199,15 +1406,15 @@ var SQLQueryGenerator = class {
1199
1406
  }
1200
1407
  if (op instanceof ConstantOperation) return constantValueString(op);
1201
1408
  if (op instanceof ColumnWithJoin) {
1202
- const node = op.parent;
1409
+ const { column, parent: node } = this._resolve(op);
1203
1410
  let ta;
1204
1411
  if (node !== void 0) {
1205
- ta = this._tableAliasForTable(op.column.owner, node);
1412
+ ta = this._tableAliasForTable(column.owner, node);
1206
1413
  this._addJoin(node);
1207
1414
  } else {
1208
- ta = this._tableAliasForTable(op.column.owner, op.column.owner);
1415
+ ta = this._tableAliasForTable(column.owner, column.owner);
1209
1416
  }
1210
- return ta.alias + "." + op.column.name;
1417
+ return ta.alias + "." + column.name;
1211
1418
  }
1212
1419
  if (op instanceof Column) {
1213
1420
  const ta = this._tableAliasForTable(op.owner, op.owner);
@@ -1247,13 +1454,12 @@ function selectSqlToString(selectOperation) {
1247
1454
  qg.generate(selectOperation);
1248
1455
  return qg.buildQueryString();
1249
1456
  }
1250
- function toSql(businessDate, processingDatetime, columns, table, op, orderBy = [], groupBy = [], limit) {
1251
- const selectOp = buildQueryOperation(businessDate, processingDatetime, columns, table, op, orderBy, groupBy, limit);
1457
+ function toSql(businessDate, processingDatetime, columns, table, op, orderBy = [], groupBy = [], limit, businessDateTo = null) {
1458
+ const selectOp = buildQueryOperation(businessDate, processingDatetime, columns, table, op, orderBy, groupBy, limit, businessDateTo);
1252
1459
  return selectSqlToString(selectOp);
1253
1460
  }
1254
1461
  // Annotate the CommonJS export names for ESM import in node:
1255
1462
  0 && (module.exports = {
1256
- SelectOperation,
1257
1463
  buildQueryOperation,
1258
1464
  selectSqlToString,
1259
1465
  toSql