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
@@ -1,11 +1,20 @@
1
1
  import {
2
2
  toSql
3
- } from "./chunk-DFYZVBII.js";
3
+ } from "./chunk-MH4XMYVB.js";
4
4
  import {
5
5
  NoOperation
6
- } from "./chunk-3SSWFES4.js";
6
+ } from "./chunk-UYMOE6YU.js";
7
7
 
8
8
  // src/datafinder/runner.ts
9
+ var DEFAULT_TIMEOUT_MS = 6e4;
10
+ var QueryTimeoutError = class extends Error {
11
+ constructor(timeoutMs) {
12
+ super(`Query exceeded ${timeoutMs}ms timeout`);
13
+ this.timeoutMs = timeoutMs;
14
+ this.name = "QueryTimeoutError";
15
+ }
16
+ timeoutMs;
17
+ };
9
18
  var _runner = null;
10
19
  function registerRunner(runner) {
11
20
  _runner = runner;
@@ -18,21 +27,24 @@ function getRunner() {
18
27
  return _runner;
19
28
  }
20
29
  var FinderResult = class {
21
- constructor(_businessDate, _processingDatetime, _columns, _table, _op) {
30
+ constructor(_businessDate, _processingDatetime, _columns, _table, _op, _businessDateTo = null) {
22
31
  this._businessDate = _businessDate;
23
32
  this._processingDatetime = _processingDatetime;
24
33
  this._columns = _columns;
25
34
  this._table = _table;
26
35
  this._op = _op;
36
+ this._businessDateTo = _businessDateTo;
27
37
  }
28
38
  _businessDate;
29
39
  _processingDatetime;
30
40
  _columns;
31
41
  _table;
32
42
  _op;
43
+ _businessDateTo;
33
44
  _orderBy = [];
34
45
  _groupBy = [];
35
46
  _limit;
47
+ _timeoutMs = DEFAULT_TIMEOUT_MS;
36
48
  orderByOp(...sorts) {
37
49
  this._orderBy = sorts;
38
50
  return this;
@@ -45,6 +57,11 @@ var FinderResult = class {
45
57
  this._limit = n;
46
58
  return this;
47
59
  }
60
+ /** Abort the query and throw QueryTimeoutError if it runs longer than `milliseconds` (default 60000). */
61
+ timeout(milliseconds) {
62
+ this._timeoutMs = milliseconds;
63
+ return this;
64
+ }
48
65
  toSql() {
49
66
  return toSql(
50
67
  this._businessDate,
@@ -54,7 +71,8 @@ var FinderResult = class {
54
71
  this._op,
55
72
  this._orderBy,
56
73
  this._groupBy,
57
- this._limit
74
+ this._limit,
75
+ this._businessDateTo
58
76
  );
59
77
  }
60
78
  async toRows() {
@@ -66,14 +84,18 @@ var FinderResult = class {
66
84
  this._op,
67
85
  this._orderBy,
68
86
  this._groupBy,
69
- this._limit
87
+ this._limit,
88
+ this._timeoutMs,
89
+ this._businessDateTo
70
90
  );
71
91
  }
72
92
  };
73
93
  function convertDate(value) {
74
94
  if (value === null) return null;
75
95
  if (value instanceof Date) return value;
76
- const normalized = /^\d{4}-\d{2}-\d{2}$/.test(value) ? value + "T00:00:00Z" : value;
96
+ let normalized = value;
97
+ if (/^\d{4}-\d{2}-\d{2}$/.test(value)) normalized = value + "T00:00:00Z";
98
+ else if (/^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}(:\d{2}(\.\d+)?)?$/.test(value)) normalized = value.replace(" ", "T") + "Z";
77
99
  const d = new Date(normalized);
78
100
  if (isNaN(d.getTime())) throw new Error(`Cannot parse date: ${value}`);
79
101
  return d;
@@ -87,12 +109,28 @@ function convertInputsAndSelect(businessDate, processingDatetime, columns, table
87
109
  op
88
110
  );
89
111
  }
112
+ function convertInputsAndSelectForDateRange(businessDateFrom, businessDateTo, processingDatetime, columns, table, op = new NoOperation()) {
113
+ if (businessDateFrom == null) throw new Error("businessDateFrom is required for findForDateRange");
114
+ if (businessDateTo == null) throw new Error("businessDateTo is required for findForDateRange");
115
+ if (processingDatetime == null) throw new Error("processingValidAt is required for findForDateRange");
116
+ return new FinderResult(
117
+ convertDate(businessDateFrom),
118
+ convertDate(processingDatetime),
119
+ columns,
120
+ table,
121
+ op,
122
+ convertDate(businessDateTo)
123
+ );
124
+ }
90
125
 
91
126
  export {
127
+ DEFAULT_TIMEOUT_MS,
128
+ QueryTimeoutError,
92
129
  registerRunner,
93
130
  clearRunner,
94
131
  getRunner,
95
132
  FinderResult,
96
- convertInputsAndSelect
133
+ convertInputsAndSelect,
134
+ convertInputsAndSelectForDateRange
97
135
  };
98
- //# sourceMappingURL=chunk-6QTCGJWX.js.map
136
+ //# sourceMappingURL=chunk-FJYA2ASS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/datafinder/runner.ts"],"sourcesContent":["import { Attribute } from './attribute';\nimport { toSql } from './sql-generator';\nimport {\n Table,\n Operation,\n SortOperation,\n NoOperation,\n RelationalOperationElement,\n} from '../model/relational';\n\nexport type Row = unknown[];\n\nexport const DEFAULT_TIMEOUT_MS = 60_000;\n\n/** Thrown by a QueryRunner when a query runs longer than the timeout set on its FinderResult. */\nexport class QueryTimeoutError extends Error {\n constructor(readonly timeoutMs: number) {\n super(`Query exceeded ${timeoutMs}ms timeout`);\n this.name = 'QueryTimeoutError';\n }\n}\n\n/** Minimum interface satisfied by both Table (SQL) and GraphQLQuery (GraphQL). */\nexport interface QueryTarget {\n readonly name: string;\n}\n\nexport interface QueryRunner {\n select(\n businessDate: Date | null,\n processingDatetime: Date | null,\n columns: (Attribute | RelationalOperationElement)[],\n table: QueryTarget,\n op: RelationalOperationElement,\n orderBy?: SortOperation[],\n groupBy?: Attribute[],\n limit?: number,\n timeoutMs?: number,\n businessDateTo?: Date | null,\n ): Promise<Row[]>;\n}\n\nlet _runner: QueryRunner | null = null;\n\nexport function registerRunner(runner: QueryRunner): void { _runner = runner; }\nexport function clearRunner(): void { _runner = null; }\nexport function getRunner(): QueryRunner {\n if (!_runner) throw new Error('No query runner registered. Call registerRunner() first.');\n return _runner;\n}\n\nexport class FinderResult {\n private _orderBy: SortOperation[] = [];\n private _groupBy: Attribute[] = [];\n private _limit?: number;\n private _timeoutMs: number = DEFAULT_TIMEOUT_MS;\n\n constructor(\n private readonly _businessDate: Date | null,\n private readonly _processingDatetime: Date | null,\n private readonly _columns: (Attribute | RelationalOperationElement)[],\n private readonly _table: QueryTarget,\n private readonly _op: RelationalOperationElement,\n private readonly _businessDateTo: Date | null = null,\n ) {}\n\n orderByOp(...sorts: SortOperation[]): this {\n this._orderBy = sorts;\n return this;\n }\n\n groupByOp(...attrs: Attribute[]): this {\n this._groupBy = attrs;\n return this;\n }\n\n limit(n: number): this {\n this._limit = n;\n return this;\n }\n\n /** Abort the query and throw QueryTimeoutError if it runs longer than `milliseconds` (default 60000). */\n timeout(milliseconds: number): this {\n this._timeoutMs = milliseconds;\n return this;\n }\n\n toSql(): string {\n return toSql(\n this._businessDate,\n this._processingDatetime,\n this._columns,\n this._table as Table,\n this._op,\n this._orderBy,\n this._groupBy,\n this._limit,\n this._businessDateTo,\n );\n }\n\n async toRows(): Promise<Row[]> {\n return getRunner().select(\n this._businessDate,\n this._processingDatetime,\n this._columns,\n this._table,\n this._op,\n this._orderBy,\n this._groupBy,\n this._limit,\n this._timeoutMs,\n this._businessDateTo,\n );\n }\n}\n\nfunction convertDate(value: Date | string | null): Date | null {\n if (value === null) return null;\n if (value instanceof Date) return value;\n // Zone-less strings (YYYY-MM-DD, or YYYY-MM-DD HH:MM[:SS]) are read as UTC, matching how\n // dates are formatted into SQL, so the value doesn't shift with the machine's timezone.\n let normalized = value;\n if (/^\\d{4}-\\d{2}-\\d{2}$/.test(value)) normalized = value + 'T00:00:00Z';\n else if (/^\\d{4}-\\d{2}-\\d{2}[ T]\\d{2}:\\d{2}(:\\d{2}(\\.\\d+)?)?$/.test(value)) normalized = value.replace(' ', 'T') + 'Z';\n const d = new Date(normalized);\n if (isNaN(d.getTime())) throw new Error(`Cannot parse date: ${value}`);\n return d;\n}\n\nexport function convertInputsAndSelect(\n businessDate: Date | string | null,\n processingDatetime: Date | string | null,\n columns: (Attribute | RelationalOperationElement)[],\n table: QueryTarget,\n op: RelationalOperationElement = new NoOperation(),\n): FinderResult {\n return new FinderResult(\n convertDate(businessDate),\n convertDate(processingDatetime),\n columns,\n table,\n op,\n );\n}\n\nexport function convertInputsAndSelectForDateRange(\n businessDateFrom: Date | string,\n businessDateTo: Date | string,\n processingDatetime: Date | string,\n columns: (Attribute | RelationalOperationElement)[],\n table: QueryTarget,\n op: RelationalOperationElement = new NoOperation(),\n): FinderResult {\n if (businessDateFrom == null) throw new Error('businessDateFrom is required for findForDateRange');\n if (businessDateTo == null) throw new Error('businessDateTo is required for findForDateRange');\n if (processingDatetime == null) throw new Error('processingValidAt is required for findForDateRange');\n return new FinderResult(\n convertDate(businessDateFrom),\n convertDate(processingDatetime),\n columns,\n table,\n op,\n convertDate(businessDateTo),\n );\n}\n"],"mappings":"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","names":[]}
@@ -4,16 +4,17 @@ import {
4
4
  MilestonedTable,
5
5
  ProcessingTemporalColumns,
6
6
  SingleBusinessDateColumn
7
- } from "./chunk-EYXBYV2X.js";
7
+ } from "./chunk-PMPLCEWQ.js";
8
8
  import {
9
9
  DateAttribute,
10
10
  DateTimeAttribute
11
- } from "./chunk-5K2Z3YDY.js";
11
+ } from "./chunk-4LNZV6EN.js";
12
12
  import {
13
13
  Attribute
14
- } from "./chunk-V647VNMY.js";
14
+ } from "./chunk-4JVW4TAB.js";
15
15
  import {
16
16
  AggregateOperation,
17
+ Alias,
17
18
  BooleanConstantOperation,
18
19
  Column,
19
20
  ColumnWithJoin,
@@ -26,64 +27,25 @@ import {
26
27
  DateExtractOperation,
27
28
  DateTimeConstantOperation,
28
29
  DecimalConstantOperation,
30
+ ExistsOperation,
29
31
  FloatConstantOperation,
30
32
  IntegerConstantOperation,
31
33
  IsNotNullOperation,
32
34
  IsNullOperation,
33
35
  LogicalOperation,
34
36
  NoOperation,
37
+ NotExistsOperation,
35
38
  RelationalOperationElement,
36
39
  ScalarFunctionOperation,
40
+ SelectOperation,
37
41
  SortOperation,
38
42
  StringConstantOperation,
39
43
  UnaryOperation,
40
44
  WindowFunctionOperation,
41
45
  WindowSpecification
42
- } from "./chunk-3SSWFES4.js";
43
-
44
- // src/datafinder/finder.ts
45
- var ExistsOperation = class extends RelationalOperationElement {
46
- constructor(node) {
47
- super();
48
- this.node = node;
49
- }
50
- node;
51
- andOp(other) {
52
- return new LogicalOperation(this, "AND" /* AND */, other);
53
- }
54
- };
55
- var NotExistsOperation = class extends RelationalOperationElement {
56
- constructor(node) {
57
- super();
58
- this.node = node;
59
- }
60
- node;
61
- andOp(other) {
62
- return new LogicalOperation(this, "AND" /* AND */, other);
63
- }
64
- };
65
- var RelatedFinder = class {
66
- constructor(_node) {
67
- this._node = _node;
68
- }
69
- _node;
70
- exists() {
71
- return new ExistsOperation(this._node);
72
- }
73
- notExists() {
74
- return new NotExistsOperation(this._node);
75
- }
76
- };
46
+ } from "./chunk-UYMOE6YU.js";
77
47
 
78
48
  // src/datafinder/sql-generator.ts
79
- var Alias = class {
80
- constructor(element, name) {
81
- this.element = element;
82
- this.name = name;
83
- }
84
- element;
85
- name;
86
- };
87
49
  var TableAlias = class {
88
50
  constructor(table, alias) {
89
51
  this.table = table;
@@ -111,22 +73,6 @@ var Join = class {
111
73
  target;
112
74
  filterOp;
113
75
  };
114
- var SelectOperation = class {
115
- constructor(display, filter, orderBy = [], groupBy = [], limit, table) {
116
- this.display = display;
117
- this.filter = filter;
118
- this.orderBy = orderBy;
119
- this.groupBy = groupBy;
120
- this.limit = limit;
121
- this.table = table;
122
- }
123
- display;
124
- filter;
125
- orderBy;
126
- groupBy;
127
- limit;
128
- table;
129
- };
130
76
  function sqlFormatDatetime(value) {
131
77
  const pad = (n, w = 2) => String(n).padStart(w, "0");
132
78
  return `'${value.getUTCFullYear()}-${pad(value.getUTCMonth() + 1)}-${pad(value.getUTCDate())} ${pad(value.getUTCHours())}:${pad(value.getUTCMinutes())}:${pad(value.getUTCSeconds())}'`;
@@ -258,6 +204,9 @@ function sqlOperationToString(operation) {
258
204
  }
259
205
  throw new TypeError("Unknown operation in sqlOperationToString: " + operation.constructor.name);
260
206
  }
207
+ function embeddedOf(ref) {
208
+ return ref instanceof Attribute ? ref.embedded() : ref.embedded;
209
+ }
261
210
  function findColumn(operation) {
262
211
  if (operation instanceof UnaryOperation) return findColumn(operation.element);
263
212
  if (operation instanceof ColumnWithJoin) return operation;
@@ -307,38 +256,125 @@ function buildMilestoningFilterOperation(businessDate, processingDatetime, table
307
256
  if (ops.length === 1) return ops[0];
308
257
  return new LogicalOperation(ops[0], "AND" /* AND */, ops[1]);
309
258
  }
310
- function buildQueryOperation(businessDate, processingDatetime, columns, table, op, orderBy = [], groupBy = [], limit) {
259
+ function buildMilestoningFilterOperationForDateRange(businessDateFrom, businessDateTo, processingDatetime, table, joinNode) {
260
+ const mc = table.milestoningColumns;
261
+ const ops = [];
262
+ const hasRange = businessDateFrom !== null && businessDateTo !== null;
263
+ const processingOp = (m) => {
264
+ const startAt = new DateTimeAttribute("start_at", m.startAtColumn.name, m.startAtColumn.type, m.startAtColumn.table.qualifiedName, joinNode);
265
+ const endAt = new DateTimeAttribute("end_at", m.endAtColumn.name, m.endAtColumn.type, m.endAtColumn.table.qualifiedName, joinNode);
266
+ return new LogicalOperation(startAt.lte(processingDatetime), "AND" /* AND */, openEndClause(endAt, processingDatetime, m.infiniteDatetime));
267
+ };
268
+ if (mc instanceof BiTemporalColumns) {
269
+ if (hasRange) {
270
+ const dateFrom = new DateAttribute("business_date_from", mc.businessDateFromColumn.name, mc.businessDateFromColumn.type, mc.businessDateFromColumn.table.qualifiedName, joinNode);
271
+ const dateTo = new DateAttribute("business_date_to", mc.businessDateToColumn.name, mc.businessDateToColumn.type, mc.businessDateToColumn.table.qualifiedName, joinNode);
272
+ ops.push(new LogicalOperation(dateFrom.lte(businessDateTo), "AND" /* AND */, openEndClause(dateTo, businessDateFrom, mc.infiniteDatetime)));
273
+ }
274
+ if (processingDatetime !== null) ops.push(processingOp(mc));
275
+ } else if (mc instanceof BusinessDateAndProcessingTemporalColumns) {
276
+ if (hasRange) {
277
+ const businessAtt = new DateAttribute("business_date", mc.businessDateColumn.name, mc.businessDateColumn.type, mc.businessDateColumn.table.qualifiedName, joinNode);
278
+ ops.push(new LogicalOperation(businessAtt.gte(businessDateFrom), "AND" /* AND */, businessAtt.lte(businessDateTo)));
279
+ }
280
+ if (processingDatetime !== null) ops.push(processingOp(mc));
281
+ } else if (mc instanceof ProcessingTemporalColumns) {
282
+ if (processingDatetime !== null) ops.push(processingOp(mc));
283
+ } else if (mc instanceof SingleBusinessDateColumn && hasRange) {
284
+ const businessAtt = new DateAttribute("business_date", mc.businessDateColumn.name, mc.businessDateColumn.type, mc.businessDateColumn.table.qualifiedName, joinNode);
285
+ ops.push(new LogicalOperation(businessAtt.gte(businessDateFrom), "AND" /* AND */, businessAtt.lte(businessDateTo)));
286
+ }
287
+ if (ops.length === 0) return null;
288
+ if (ops.length === 1) return ops[0];
289
+ return new LogicalOperation(ops[0], "AND" /* AND */, ops[1]);
290
+ }
291
+ function walkRefs(op, visit, visitExists) {
292
+ if (op === null || op === void 0) return;
293
+ if (op instanceof Attribute || op instanceof ColumnWithJoin) {
294
+ visit(op);
295
+ } else if (op instanceof ExistsOperation || op instanceof NotExistsOperation) {
296
+ visitExists?.(op.node);
297
+ } else if (op instanceof AggregateOperation) {
298
+ walkRefs(op.element, visit, visitExists);
299
+ if (op.window) walkWindowSpec(op.window, visit, visitExists);
300
+ } else if (op instanceof WindowFunctionOperation) {
301
+ if (op.element) walkRefs(op.element, visit, visitExists);
302
+ if (op.window) walkWindowSpec(op.window, visit, visitExists);
303
+ } else if (op instanceof ScalarFunctionOperation || op instanceof DateExtractOperation || op instanceof DateArithmeticOperation || op instanceof DateDiffOperation || op instanceof IsNullOperation || op instanceof IsNotNullOperation) {
304
+ walkRefs(op.element, visit, visitExists);
305
+ } else if (op instanceof SortOperation) {
306
+ walkRefs(op.column, visit, visitExists);
307
+ } else if (op instanceof LogicalOperation || op instanceof ComparisonOperation) {
308
+ walkRefs(op.left, visit, visitExists);
309
+ walkRefs(op.right, visit, visitExists);
310
+ }
311
+ }
312
+ function walkWindowSpec(window, visit, visitExists) {
313
+ for (const p of window.partitionBy) walkRefs(p, visit, visitExists);
314
+ for (const s of window.orderBy) walkRefs(s.column, visit, visitExists);
315
+ }
316
+ function buildJoinFilterFromProperties(node, filter, columnMap) {
317
+ const ops = [];
318
+ for (const [key, value] of Object.entries(filter)) {
319
+ const entry = columnMap[key];
320
+ if (entry === void 0) {
321
+ throw new Error(`Unknown property '${key}' \u2014 valid properties are: ${Object.keys(columnMap).sort().join(", ")}`);
322
+ }
323
+ const [name, type, table] = entry;
324
+ const col = new ColumnWithJoin(new Column(name, type, table), node);
325
+ let constant;
326
+ if (typeof value === "boolean") constant = new BooleanConstantOperation(value);
327
+ else if (typeof value === "number") constant = Number.isInteger(value) ? new IntegerConstantOperation(value) : new FloatConstantOperation(value);
328
+ else if (value instanceof Date) constant = type.toUpperCase() === "DATE" ? new DateConstantOperation(value) : new DateTimeConstantOperation(value);
329
+ else constant = new StringConstantOperation(String(value));
330
+ ops.push(new ComparisonOperation(col, "EQUAL" /* EQUAL */, constant));
331
+ }
332
+ return ops.reduce((acc, op) => new LogicalOperation(acc, "AND" /* AND */, op));
333
+ }
334
+ function withAncestors(nodes) {
335
+ const ordered = /* @__PURE__ */ new Set();
336
+ const add = (node) => {
337
+ if (ordered.has(node)) return;
338
+ if (node.parent !== void 0) add(node.parent);
339
+ ordered.add(node);
340
+ };
341
+ for (const node of nodes) add(node);
342
+ return [...ordered];
343
+ }
344
+ function buildQueryOperation(businessDate, processingDatetime, columns, table, op, orderBy = [], groupBy = [], limit, businessDateTo = null) {
311
345
  let filter = op;
346
+ const milestoningFor = (t, node) => businessDateTo !== null ? buildMilestoningFilterOperationForDateRange(businessDate, businessDateTo, processingDatetime, t, node) : buildMilestoningFilterOperation(businessDate, processingDatetime, t, node);
312
347
  if (table instanceof MilestonedTable) {
313
- const milestonedOp = buildMilestoningFilterOperation(businessDate, processingDatetime, table);
348
+ const milestonedOp = milestoningFor(table);
314
349
  if (milestonedOp !== null) {
315
350
  filter = filter instanceof NoOperation ? milestonedOp : new LogicalOperation(filter, "AND" /* AND */, milestonedOp);
316
351
  }
317
352
  }
318
- const requiredJoins = [];
319
- const requiredJoinIds = /* @__PURE__ */ new Set();
320
- for (const col of columns) {
321
- if (col instanceof CountAllOperation) continue;
322
- let node;
323
- if (col instanceof Attribute) {
324
- node = col.parent();
325
- } else {
326
- node = findColumn(col).parent;
327
- }
328
- if (node !== void 0 && !requiredJoinIds.has(node)) {
329
- requiredJoinIds.add(node);
330
- requiredJoins.push(node);
353
+ const requiredJoins = /* @__PURE__ */ new Set();
354
+ const collect = (ref) => {
355
+ const parent = ref instanceof Attribute ? ref.parent() : ref.parent;
356
+ if (parent !== void 0) requiredJoins.add(parent);
357
+ };
358
+ const collectNode = (node) => requiredJoins.add(node);
359
+ for (const col of columns) walkRefs(col, collect, collectNode);
360
+ for (const expr of groupBy) walkRefs(expr, collect, collectNode);
361
+ for (const sort of orderBy) walkRefs(sort, collect, collectNode);
362
+ walkRefs(op, collect, collectNode);
363
+ const joinFilters = /* @__PURE__ */ new Map();
364
+ for (const node of withAncestors(requiredJoins)) {
365
+ let combined;
366
+ if (Object.keys(node.join.filterKwargs).length > 0) {
367
+ combined = buildJoinFilterFromProperties(node, node.join.filterKwargs, node.join.filterColumnMap);
331
368
  }
332
- }
333
- for (const node of requiredJoins) {
334
369
  if (node.join.target instanceof MilestonedTable) {
335
- const milestonedOp = buildMilestoningFilterOperation(businessDate, processingDatetime, node.join.target, node);
370
+ const milestonedOp = milestoningFor(node.join.target, node);
336
371
  if (milestonedOp !== null) {
337
- node.join.filter = milestonedOp;
372
+ combined = combined === void 0 ? milestonedOp : new LogicalOperation(combined, "AND" /* AND */, milestonedOp);
338
373
  }
339
374
  }
375
+ if (combined !== void 0) joinFilters.set(node, combined);
340
376
  }
341
- return new SelectOperation(columns, filter, orderBy, groupBy, limit, table);
377
+ return new SelectOperation(columns, filter, orderBy, groupBy, limit, table, joinFilters);
342
378
  }
343
379
  var SQLQueryGenerator = class {
344
380
  _select = [];
@@ -352,8 +388,12 @@ var SQLQueryGenerator = class {
352
388
  _tableAliasesByTable = /* @__PURE__ */ new Map();
353
389
  _addedJoinIds = /* @__PURE__ */ new Set();
354
390
  _rootTable;
391
+ _elidableNodes = /* @__PURE__ */ new Set();
392
+ _joinFilters = /* @__PURE__ */ new Map();
355
393
  generate(select) {
356
394
  this._rootTable = select.table;
395
+ this._elidableNodes = this._computeElidableNodes(select);
396
+ this._joinFilters = select.joinFilters;
357
397
  if (this._rootTable !== void 0) {
358
398
  this._from.add(this._tableAliasForTable(this._rootTable.qualifiedName, this._rootTable.qualifiedName));
359
399
  }
@@ -373,39 +413,49 @@ var SQLQueryGenerator = class {
373
413
  this._limit = select.limit;
374
414
  }
375
415
  _attrToColString(attr) {
376
- const node = attr.parent();
377
- const ta = this._tableAliasForTable(attr.owner(), node ?? attr.owner());
378
- return ta.alias + "." + attr.column().name;
416
+ const { column, parent } = this._resolve(attr);
417
+ const ta = this._tableAliasForTable(column.owner, parent ?? column.owner);
418
+ return ta.alias + "." + column.name;
379
419
  }
380
420
  _collectRequiredJoins(op, out) {
381
- if (op === null || op === void 0) return;
382
- if (op instanceof Attribute) {
383
- const p = op.parent();
384
- if (p !== void 0) out.set(p, p);
385
- } else if (op instanceof ColumnWithJoin) {
386
- if (op.parent !== void 0) out.set(op.parent, op.parent);
387
- } else if (op instanceof AggregateOperation) {
388
- this._collectRequiredJoins(op.element, out);
389
- if (op.window) this._collectRequiredJoins(op.window, out);
390
- } else if (op instanceof WindowFunctionOperation) {
391
- if (op.element) this._collectRequiredJoins(op.element, out);
392
- if (op.window) this._collectRequiredJoinsFromWindowSpec(op.window, out);
393
- } else if (op instanceof ScalarFunctionOperation || op instanceof DateExtractOperation || op instanceof DateArithmeticOperation || op instanceof DateDiffOperation) {
394
- this._collectRequiredJoins(op.element, out);
395
- } else if (op instanceof SortOperation) {
396
- this._collectRequiredJoins(op.column, out);
397
- } else if (op instanceof LogicalOperation || op instanceof ComparisonOperation) {
398
- this._collectRequiredJoins(op.left, out);
399
- this._collectRequiredJoins(op.right, out);
400
- }
401
- }
402
- _collectRequiredJoinsFromWindowSpec(window, out) {
403
- for (const p of window.partitionBy) {
404
- this._collectRequiredJoins(p, out);
405
- }
406
- for (const s of window.orderBy) {
407
- this._collectRequiredJoins(s.column, out);
408
- }
421
+ walkRefs(op, (ref) => {
422
+ const { parent } = this._resolve(ref);
423
+ if (parent !== void 0) out.set(parent, parent);
424
+ });
425
+ }
426
+ /**
427
+ * Determine upfront which join nodes can be satisfied entirely by embedded (join-less) alternates:
428
+ * a node is elidable when every reference to it has an embedded alternate. A reference without one
429
+ * (e.g. a milestoning column) keeps the join for every reference to that node.
430
+ */
431
+ _computeElidableNodes(select) {
432
+ const refsByNode = /* @__PURE__ */ new Map();
433
+ const record = (ref) => {
434
+ const parent = ref instanceof Attribute ? ref.parent() : ref.parent;
435
+ if (parent === void 0) return;
436
+ const refs = refsByNode.get(parent);
437
+ if (refs) refs.push(ref);
438
+ else refsByNode.set(parent, [ref]);
439
+ };
440
+ for (const col of select.display) walkRefs(col, record);
441
+ for (const expr of select.groupBy) walkRefs(expr, record);
442
+ for (const sort of select.orderBy) walkRefs(sort, record);
443
+ walkRefs(select.filter, record);
444
+ const elidable = /* @__PURE__ */ new Set();
445
+ for (const [node, refs] of refsByNode) {
446
+ if (refs.every((ref) => embeddedOf(ref) !== void 0)) elidable.add(node);
447
+ }
448
+ return elidable;
449
+ }
450
+ /** The (column, parent) a reference should resolve to, substituting its embedded alternate when its join is elided. */
451
+ _resolve(ref) {
452
+ const column = ref instanceof Attribute ? ref.column() : ref.column;
453
+ const parent = ref instanceof Attribute ? ref.parent() : ref.parent;
454
+ if (parent !== void 0 && this._elidableNodes.has(parent)) {
455
+ const embedded = embeddedOf(ref);
456
+ if (embedded !== void 0) return this._resolve(embedded);
457
+ }
458
+ return { column, parent };
409
459
  }
410
460
  _rewriteWindowSpec(window) {
411
461
  const partitionBy = window.partitionBy.map((p) => this._rewriteOperation(p));
@@ -413,13 +463,9 @@ var SQLQueryGenerator = class {
413
463
  return new WindowSpecification(partitionBy, orderBy);
414
464
  }
415
465
  _rewriteOperation(op) {
416
- if (op instanceof Attribute) {
417
- const ta = this._tableAliasForTable(op.owner(), op.parent() ?? op.owner());
418
- return new TableAliasColumn(op.column(), ta);
419
- }
420
- if (op instanceof ColumnWithJoin) {
421
- const ta = op.parent !== void 0 ? this._tableAliasForTable(op.column.owner, op.parent) : this._tableAliasForTable(op.column.owner, op.column.owner);
422
- return new TableAliasColumn(op.column, ta);
466
+ if (op instanceof Attribute || op instanceof ColumnWithJoin) {
467
+ const { column, parent } = this._resolve(op);
468
+ return new TableAliasColumn(column, this._tableAliasForTable(column.owner, parent ?? column.owner));
423
469
  }
424
470
  if (op instanceof Column) {
425
471
  const ta = this._tableAliasForTable(op.owner, op.owner);
@@ -468,15 +514,15 @@ var SQLQueryGenerator = class {
468
514
  }
469
515
  for (const col of cols) {
470
516
  if (col instanceof Attribute) {
471
- const node = col.parent();
517
+ const { column, parent: node } = this._resolve(col);
472
518
  let ta;
473
519
  if (node !== void 0) {
474
- ta = this._tableAliasForTable(col.owner(), node);
520
+ ta = this._tableAliasForTable(column.owner, node);
475
521
  } else {
476
- ta = this._tableAliasForTable(col.owner(), col.owner());
522
+ ta = this._tableAliasForTable(column.owner, column.owner);
477
523
  this._from.add(ta);
478
524
  }
479
- this._select.push(new Alias(new TableAliasColumn(col.column(), ta), col.displayName()));
525
+ this._select.push(new Alias(new TableAliasColumn(column, ta), col.displayName()));
480
526
  } else if (col instanceof WindowFunctionOperation) {
481
527
  const rewritten = this._rewriteOperation(col);
482
528
  let alias;
@@ -491,7 +537,7 @@ var SQLQueryGenerator = class {
491
537
  }
492
538
  this._select.push(new Alias(rewritten, alias));
493
539
  } else if (col instanceof AggregateOperation) {
494
- const colNested = findColumn(col);
540
+ const colNested = this._resolve(findColumn(col));
495
541
  const node = colNested.parent;
496
542
  let ta;
497
543
  if (node !== void 0) {
@@ -500,7 +546,7 @@ var SQLQueryGenerator = class {
500
546
  ta = this._tableAliasForTable(colNested.column.owner, colNested.column.owner);
501
547
  this._from.add(ta);
502
548
  }
503
- const alias = col.displayName ?? col.operator + " " + colNested.column.name;
549
+ const alias = col.displayName ?? col.operator + " " + findColumn(col).column.name;
504
550
  const rewrittenAgg = new AggregateOperation(
505
551
  new TableAliasColumn(colNested.column, ta),
506
552
  col.operator,
@@ -509,7 +555,7 @@ var SQLQueryGenerator = class {
509
555
  );
510
556
  this._select.push(new Alias(rewrittenAgg, alias));
511
557
  } else if (col instanceof ScalarFunctionOperation) {
512
- const colNested = findColumn(col);
558
+ const colNested = this._resolve(findColumn(col));
513
559
  const node = colNested.parent;
514
560
  let ta;
515
561
  if (node !== void 0) {
@@ -518,13 +564,13 @@ var SQLQueryGenerator = class {
518
564
  ta = this._tableAliasForTable(colNested.column.owner, colNested.column.owner);
519
565
  this._from.add(ta);
520
566
  }
521
- const alias = col.displayName ?? col.func + " " + colNested.column.name;
567
+ const alias = col.displayName ?? col.func + " " + findColumn(col).column.name;
522
568
  this._select.push(new Alias(
523
569
  new ScalarFunctionOperation(new TableAliasColumn(colNested.column, ta), col.func, void 0, col.secondArg, col.extraArgs),
524
570
  alias
525
571
  ));
526
572
  } else if (col instanceof DateExtractOperation || col instanceof DateArithmeticOperation || col instanceof DateDiffOperation) {
527
- const colNested = findColumn(col);
573
+ const colNested = this._resolve(findColumn(col));
528
574
  const node = colNested.parent;
529
575
  let ta;
530
576
  if (node !== void 0) {
@@ -533,7 +579,7 @@ var SQLQueryGenerator = class {
533
579
  ta = this._tableAliasForTable(colNested.column.owner, colNested.column.owner);
534
580
  this._from.add(ta);
535
581
  }
536
- const alias = col.displayName ?? colNested.column.name;
582
+ const alias = col.displayName ?? findColumn(col).column.name;
537
583
  let aliasedOp;
538
584
  if (col instanceof DateExtractOperation) {
539
585
  aliasedOp = new DateExtractOperation(new TableAliasColumn(colNested.column, ta), col.part);
@@ -561,7 +607,9 @@ var SQLQueryGenerator = class {
561
607
  const sc = new TableAliasColumn(left, srcTa);
562
608
  const right = join.right;
563
609
  const tc = new TableAliasColumn(right, this._tableAliasForTable(right.owner, node));
564
- this._join.push(new Join(sc, tc, join.filter));
610
+ const queryFilter = this._joinFilters.get(node);
611
+ const filterOp = join.filter !== void 0 && queryFilter !== void 0 ? new LogicalOperation(join.filter, "AND" /* AND */, queryFilter) : join.filter ?? queryFilter;
612
+ this._join.push(new Join(sc, tc, filterOp));
565
613
  }
566
614
  buildFilter(op) {
567
615
  if (op instanceof NoOperation) return "";
@@ -587,15 +635,15 @@ var SQLQueryGenerator = class {
587
635
  }
588
636
  if (op instanceof ConstantOperation) return constantValueString(op);
589
637
  if (op instanceof ColumnWithJoin) {
590
- const node = op.parent;
638
+ const { column, parent: node } = this._resolve(op);
591
639
  let ta;
592
640
  if (node !== void 0) {
593
- ta = this._tableAliasForTable(op.column.owner, node);
641
+ ta = this._tableAliasForTable(column.owner, node);
594
642
  this._addJoin(node);
595
643
  } else {
596
- ta = this._tableAliasForTable(op.column.owner, op.column.owner);
644
+ ta = this._tableAliasForTable(column.owner, column.owner);
597
645
  }
598
- return ta.alias + "." + op.column.name;
646
+ return ta.alias + "." + column.name;
599
647
  }
600
648
  if (op instanceof Column) {
601
649
  const ta = this._tableAliasForTable(op.owner, op.owner);
@@ -635,18 +683,14 @@ function selectSqlToString(selectOperation) {
635
683
  qg.generate(selectOperation);
636
684
  return qg.buildQueryString();
637
685
  }
638
- function toSql(businessDate, processingDatetime, columns, table, op, orderBy = [], groupBy = [], limit) {
639
- const selectOp = buildQueryOperation(businessDate, processingDatetime, columns, table, op, orderBy, groupBy, limit);
686
+ function toSql(businessDate, processingDatetime, columns, table, op, orderBy = [], groupBy = [], limit, businessDateTo = null) {
687
+ const selectOp = buildQueryOperation(businessDate, processingDatetime, columns, table, op, orderBy, groupBy, limit, businessDateTo);
640
688
  return selectSqlToString(selectOp);
641
689
  }
642
690
 
643
691
  export {
644
- ExistsOperation,
645
- NotExistsOperation,
646
- RelatedFinder,
647
- SelectOperation,
648
692
  buildQueryOperation,
649
693
  selectSqlToString,
650
694
  toSql
651
695
  };
652
- //# sourceMappingURL=chunk-DFYZVBII.js.map
696
+ //# sourceMappingURL=chunk-MH4XMYVB.js.map