rawsql-ts 0.29.0 → 0.30.1

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 (40) hide show
  1. package/dist/esm/index.d.ts +1 -0
  2. package/dist/esm/index.js +1 -0
  3. package/dist/esm/index.js.map +1 -1
  4. package/dist/esm/index.min.js +2 -2
  5. package/dist/esm/index.min.js.map +4 -4
  6. package/dist/esm/transformers/ConditionOptimization.d.ts +16 -0
  7. package/dist/esm/transformers/ConditionOptimization.js +124 -2
  8. package/dist/esm/transformers/ConditionOptimization.js.map +1 -1
  9. package/dist/esm/transformers/ParameterConditionPlacementOptimizer.js +3 -71
  10. package/dist/esm/transformers/ParameterConditionPlacementOptimizer.js.map +1 -1
  11. package/dist/esm/transformers/PredicateExpressionUtils.d.ts +16 -0
  12. package/dist/esm/transformers/PredicateExpressionUtils.js +74 -0
  13. package/dist/esm/transformers/PredicateExpressionUtils.js.map +1 -0
  14. package/dist/esm/transformers/PredicateReachabilityAnalyzer.d.ts +92 -0
  15. package/dist/esm/transformers/PredicateReachabilityAnalyzer.js +516 -0
  16. package/dist/esm/transformers/PredicateReachabilityAnalyzer.js.map +1 -0
  17. package/dist/esm/transformers/StaticPredicatePlacementOptimizer.d.ts +2 -0
  18. package/dist/esm/transformers/StaticPredicatePlacementOptimizer.js +156 -162
  19. package/dist/esm/transformers/StaticPredicatePlacementOptimizer.js.map +1 -1
  20. package/dist/index.js +1 -0
  21. package/dist/index.js.map +1 -1
  22. package/dist/index.min.js +2 -2
  23. package/dist/index.min.js.map +4 -4
  24. package/dist/src/index.d.ts +1 -0
  25. package/dist/src/transformers/ConditionOptimization.d.ts +16 -0
  26. package/dist/src/transformers/PredicateExpressionUtils.d.ts +16 -0
  27. package/dist/src/transformers/PredicateReachabilityAnalyzer.d.ts +92 -0
  28. package/dist/src/transformers/StaticPredicatePlacementOptimizer.d.ts +2 -0
  29. package/dist/transformers/ConditionOptimization.js +138 -2
  30. package/dist/transformers/ConditionOptimization.js.map +1 -1
  31. package/dist/transformers/ParameterConditionPlacementOptimizer.js +38 -106
  32. package/dist/transformers/ParameterConditionPlacementOptimizer.js.map +1 -1
  33. package/dist/transformers/PredicateExpressionUtils.js +88 -0
  34. package/dist/transformers/PredicateExpressionUtils.js.map +1 -0
  35. package/dist/transformers/PredicateReachabilityAnalyzer.js +537 -0
  36. package/dist/transformers/PredicateReachabilityAnalyzer.js.map +1 -0
  37. package/dist/transformers/StaticPredicatePlacementOptimizer.js +190 -196
  38. package/dist/transformers/StaticPredicatePlacementOptimizer.js.map +1 -1
  39. package/dist/tsconfig.browser.tsbuildinfo +1 -1
  40. package/package.json +1 -1
@@ -5,79 +5,11 @@ const Clause_1 = require("../models/Clause");
5
5
  const SelectQuery_1 = require("../models/SelectQuery");
6
6
  const ValueComponent_1 = require("../models/ValueComponent");
7
7
  const SelectQueryParser_1 = require("../parsers/SelectQueryParser");
8
- const ValueParser_1 = require("../parsers/ValueParser");
9
8
  const SqlComponentFormatter_1 = require("./SqlComponentFormatter");
10
9
  const SelectOutputCollector_1 = require("./SelectOutputCollector");
11
10
  const TopLevelAndConditionDeduper_1 = require("./TopLevelAndConditionDeduper");
11
+ const PredicateExpressionUtils_1 = require("./PredicateExpressionUtils");
12
12
  const VOLATILE_OR_UNSUPPORTED_FUNCTION_REASON = "Predicate contains a function call; volatile and expression predicates are not moved in the safe-only implementation.";
13
- const normalizeIdentifier = (value) => value.trim().toLowerCase();
14
- const isCaseSensitiveIdentifier = (value) => /[A-Z]/.test(value.trim());
15
- const identifiersEqual = (left, right) => {
16
- const trimmedLeft = left.trim();
17
- const trimmedRight = right.trim();
18
- return isCaseSensitiveIdentifier(trimmedLeft) || isCaseSensitiveIdentifier(trimmedRight)
19
- ? trimmedLeft === trimmedRight
20
- : trimmedLeft.toLowerCase() === trimmedRight.toLowerCase();
21
- };
22
- const unwrapParens = (expression) => {
23
- let candidate = expression;
24
- while (candidate instanceof ValueComponent_1.ParenExpression) {
25
- candidate = candidate.expression;
26
- }
27
- return candidate;
28
- };
29
- const isBinaryOperator = (expression, operator) => {
30
- const candidate = unwrapParens(expression);
31
- return candidate instanceof ValueComponent_1.BinaryExpression
32
- && candidate.operator.value.trim().toLowerCase() === operator;
33
- };
34
- const collectTopLevelAndTerms = (expression) => {
35
- const candidate = unwrapParens(expression);
36
- if (!isBinaryOperator(candidate, "and")) {
37
- return [expression];
38
- }
39
- return [
40
- ...collectTopLevelAndTerms(candidate.left),
41
- ...collectTopLevelAndTerms(candidate.right)
42
- ];
43
- };
44
- const rebuildWhereWithoutTerms = (query, termsToRemove) => {
45
- if (!query.whereClause || termsToRemove.size === 0) {
46
- return;
47
- }
48
- const remaining = collectTopLevelAndTerms(query.whereClause.condition)
49
- .filter(term => !termsToRemove.has(term));
50
- if (remaining.length === 0) {
51
- query.whereClause = null;
52
- return;
53
- }
54
- let rebuilt = remaining[0];
55
- for (let index = 1; index < remaining.length; index += 1) {
56
- rebuilt = new ValueComponent_1.BinaryExpression(rebuilt, "and", remaining[index]);
57
- }
58
- query.whereClause = new Clause_1.WhereClause(rebuilt);
59
- };
60
- const cloneValueComponent = (expression, options) => {
61
- return ValueParser_1.ValueParser.parse((0, SqlComponentFormatter_1.formatSqlComponent)(expression, options));
62
- };
63
- const cloneColumnReference = (reference) => {
64
- var _a, _b;
65
- const namespaces = (_b = (_a = reference.namespaces) === null || _a === void 0 ? void 0 : _a.map(namespace => namespace.name)) !== null && _b !== void 0 ? _b : null;
66
- return new ValueComponent_1.ColumnReference(namespaces, reference.column.name);
67
- };
68
- const columnReferenceText = (reference) => {
69
- const namespace = reference.getNamespace();
70
- return namespace ? `${namespace}.${reference.column.name}` : reference.column.name;
71
- };
72
- const sameColumnReference = (left, right) => {
73
- return identifiersEqual(left.column.name, right.column.name)
74
- && identifiersEqual(left.getNamespace(), right.getNamespace());
75
- };
76
- const appendUnique = (items, value) => {
77
- if (!items.includes(value)) {
78
- items.push(value);
79
- }
80
- };
81
13
  class StaticPredicatePlacementOptimizer {
82
14
  plan(input, options = {}) {
83
15
  var _a, _b, _c;
@@ -115,77 +47,8 @@ class StaticPredicatePlacementOptimizer {
115
47
  const query = parsed.query;
116
48
  const applied = [];
117
49
  const skipped = [];
118
- const movedTerms = [];
119
- for (const term of query.whereClause ? collectTopLevelAndTerms(query.whereClause.condition) : []) {
120
- const candidate = this.analyzeCandidate(query, term, options);
121
- if (!candidate) {
122
- continue;
123
- }
124
- if ("code" in candidate) {
125
- skipped.push(this.makeSkipped(term, candidate, options));
126
- continue;
127
- }
128
- const target = this.resolveTarget(query, candidate);
129
- if ("code" in target) {
130
- skipped.push(this.makeSkipped(term, target, options));
131
- continue;
132
- }
133
- let appliedReason = "";
134
- if (target.kind === "join_on") {
135
- this.appendJoinOnPredicate(target.join, candidate.expression, options);
136
- appliedReason = target.reason;
137
- }
138
- else if (target.kind === "simple") {
139
- const targetColumns = this.resolveTargetColumns(query, target.query, candidate.references);
140
- if ("code" in targetColumns) {
141
- skipped.push(this.makeSkipped(term, targetColumns, options));
142
- continue;
143
- }
144
- const placement = this.resolveTargetPlacement(target.query, targetColumns);
145
- if ("code" in placement) {
146
- skipped.push(this.makeSkipped(term, placement, options));
147
- continue;
148
- }
149
- const movedPredicate = this.rebasePredicate(candidate.expression, targetColumns, options);
150
- target.query.appendWhere(movedPredicate);
151
- (0, TopLevelAndConditionDeduper_1.dedupeWhereTopLevelAndConditions)(target.query, options);
152
- appliedReason = placement.reason;
153
- }
154
- else {
155
- const placements = [];
156
- let skip = null;
157
- for (const branch of target.branches) {
158
- const placement = this.resolveTargetPlacement(branch.query, branch.targetColumns);
159
- if ("code" in placement) {
160
- skip = placement;
161
- break;
162
- }
163
- placements.push(placement);
164
- }
165
- if (skip) {
166
- skipped.push(this.makeSkipped(term, skip, options));
167
- continue;
168
- }
169
- for (const branch of target.branches) {
170
- const movedPredicate = this.rebasePredicate(candidate.expression, branch.targetColumns, options);
171
- branch.query.appendWhere(movedPredicate);
172
- (0, TopLevelAndConditionDeduper_1.dedupeWhereTopLevelAndConditions)(branch.query, options);
173
- }
174
- appliedReason = placements.some(item => /group by/i.test(item.reason))
175
- ? "Predicate is distributed to every UNION branch by output column position; grouped branches only receive GROUP BY-key predicates."
176
- : "Predicate is distributed to every UNION branch by output column position before unsafe query boundaries.";
177
- }
178
- movedTerms.push(term);
179
- applied.push({
180
- kind: "move_static_predicate",
181
- predicateSql: candidate.predicateSql,
182
- fromScopeId: "scope:root",
183
- toScopeId: target.scopeId,
184
- reason: appliedReason,
185
- columnReferences: candidate.references.map(columnReferenceText)
186
- });
187
- }
188
- rebuildWhereWithoutTerms(query, new Set(movedTerms));
50
+ this.placePredicatesInScopes(query, options, applied, skipped);
51
+ // API output shape review: keep result.sql/result.query compatibility while expanding scope-aware placement.
189
52
  const sql = applied.length > 0 || (0, SqlComponentFormatter_1.hasSqlComponentFormatOverride)(options)
190
53
  ? (0, SqlComponentFormatter_1.formatSqlComponent)(query, options)
191
54
  : parsed.sql;
@@ -200,6 +63,121 @@ class StaticPredicatePlacementOptimizer {
200
63
  formatterGeneratedSource: parsed.formatterGeneratedSource
201
64
  });
202
65
  }
66
+ placePredicatesInScopes(contextRoot, options, applied, skipped) {
67
+ var _a;
68
+ const queue = [{ query: contextRoot, scopeId: "scope:root" }];
69
+ let processed = 0;
70
+ while (queue.length > 0) {
71
+ processed += 1;
72
+ if (processed > 1000) {
73
+ skipped.push({
74
+ predicateSql: "",
75
+ scopeId: "scope:root",
76
+ code: "RECURSIVE_PLACEMENT_LIMIT",
77
+ reason: "Static predicate recursive placement stopped after reaching the safety iteration limit."
78
+ });
79
+ return;
80
+ }
81
+ const work = queue.shift();
82
+ const movedTerms = [];
83
+ const reportSkipped = work.pendingTerms === undefined;
84
+ const terms = (_a = work.pendingTerms) !== null && _a !== void 0 ? _a : (work.query.whereClause
85
+ ? (0, PredicateExpressionUtils_1.collectTopLevelAndTerms)(work.query.whereClause.condition)
86
+ : []);
87
+ for (const term of terms) {
88
+ const candidate = this.analyzeCandidate(work.query, term, options);
89
+ if (!candidate) {
90
+ continue;
91
+ }
92
+ if ("code" in candidate) {
93
+ if (reportSkipped) {
94
+ skipped.push(this.makeSkipped(term, work.scopeId, candidate, options));
95
+ }
96
+ continue;
97
+ }
98
+ const target = this.resolveTarget(contextRoot, work.query, candidate);
99
+ if ("code" in target) {
100
+ if (reportSkipped) {
101
+ skipped.push(this.makeSkipped(term, work.scopeId, target, options));
102
+ }
103
+ continue;
104
+ }
105
+ let appliedReason = "";
106
+ if (target.kind === "join_on") {
107
+ this.appendJoinOnPredicate(target.join, candidate.expression, options);
108
+ appliedReason = target.reason;
109
+ }
110
+ else if (target.kind === "simple") {
111
+ const targetColumns = this.resolveTargetColumns(contextRoot, target.query, candidate.references);
112
+ if ("code" in targetColumns) {
113
+ if (reportSkipped) {
114
+ skipped.push(this.makeSkipped(term, work.scopeId, targetColumns, options));
115
+ }
116
+ continue;
117
+ }
118
+ const placement = this.resolveTargetPlacement(contextRoot, target.query, targetColumns);
119
+ if ("code" in placement) {
120
+ if (reportSkipped) {
121
+ skipped.push(this.makeSkipped(term, work.scopeId, placement, options));
122
+ }
123
+ continue;
124
+ }
125
+ const movedPredicate = this.rebasePredicate(candidate.expression, targetColumns, options);
126
+ target.query.appendWhere(movedPredicate);
127
+ (0, TopLevelAndConditionDeduper_1.dedupeWhereTopLevelAndConditions)(target.query, options);
128
+ appliedReason = work.scopeId === "scope:root"
129
+ ? placement.reason
130
+ : `${placement.reason} Predicate was safely rebased from a previously moved predicate.`;
131
+ const retainedTerms = target.query.whereClause
132
+ ? (0, PredicateExpressionUtils_1.collectTopLevelAndTerms)(target.query.whereClause.condition)
133
+ : [];
134
+ if (retainedTerms.includes(movedPredicate)) {
135
+ queue.push({
136
+ query: target.query,
137
+ scopeId: target.scopeId,
138
+ pendingTerms: [movedPredicate]
139
+ });
140
+ }
141
+ }
142
+ else {
143
+ const placements = [];
144
+ let skip = null;
145
+ for (const branch of target.branches) {
146
+ const placement = this.resolveTargetPlacement(contextRoot, branch.query, branch.targetColumns);
147
+ if ("code" in placement) {
148
+ skip = placement;
149
+ break;
150
+ }
151
+ placements.push(placement);
152
+ }
153
+ if (skip) {
154
+ if (reportSkipped) {
155
+ skipped.push(this.makeSkipped(term, work.scopeId, skip, options));
156
+ }
157
+ continue;
158
+ }
159
+ for (const branch of target.branches) {
160
+ const movedPredicate = this.rebasePredicate(candidate.expression, branch.targetColumns, options);
161
+ branch.query.appendWhere(movedPredicate);
162
+ (0, TopLevelAndConditionDeduper_1.dedupeWhereTopLevelAndConditions)(branch.query, options);
163
+ }
164
+ appliedReason = placements.some(item => /group by/i.test(item.reason))
165
+ ? "Predicate is distributed to every UNION branch by output column position; grouped branches only receive GROUP BY-key predicates."
166
+ : "Predicate is distributed to every UNION branch by output column position before unsafe query boundaries.";
167
+ }
168
+ movedTerms.push(term);
169
+ applied.push({
170
+ kind: "move_static_predicate",
171
+ predicateSql: candidate.predicateSql,
172
+ fromScopeId: work.scopeId,
173
+ toScopeId: target.scopeId,
174
+ reason: appliedReason,
175
+ columnReferences: candidate.references.map(PredicateExpressionUtils_1.columnReferenceText)
176
+ });
177
+ }
178
+ (0, PredicateExpressionUtils_1.rebuildWhereWithoutTerms)(work.query, new Set(movedTerms));
179
+ }
180
+ }
203
181
  optimize(input, options = {}) {
204
182
  var _a;
205
183
  return this.plan(input, { ...options, dryRun: (_a = options.dryRun) !== null && _a !== void 0 ? _a : false });
@@ -272,12 +250,12 @@ class StaticPredicatePlacementOptimizer {
272
250
  };
273
251
  }
274
252
  isExistsPredicate(expression) {
275
- const candidate = unwrapParens(expression);
253
+ const candidate = (0, PredicateExpressionUtils_1.unwrapParens)(expression);
276
254
  if (!(candidate instanceof ValueComponent_1.UnaryExpression)) {
277
255
  return false;
278
256
  }
279
257
  const operator = candidate.operator.value.trim().toLowerCase();
280
- return operator === "exists" && unwrapParens(candidate.expression) instanceof ValueComponent_1.InlineQuery;
258
+ return operator === "exists" && (0, PredicateExpressionUtils_1.unwrapParens)(candidate.expression) instanceof ValueComponent_1.InlineQuery;
281
259
  }
282
260
  findUnsupportedExpression(expression, allowExistsSubquery) {
283
261
  let found = null;
@@ -326,7 +304,7 @@ class StaticPredicatePlacementOptimizer {
326
304
  if (found) {
327
305
  return;
328
306
  }
329
- const candidate = unwrapParens(value);
307
+ const candidate = (0, PredicateExpressionUtils_1.unwrapParens)(value);
330
308
  if (candidate instanceof ValueComponent_1.BinaryExpression) {
331
309
  visit(candidate.left);
332
310
  visit(candidate.right);
@@ -395,13 +373,13 @@ class StaticPredicatePlacementOptimizer {
395
373
  visit(expression);
396
374
  return found;
397
375
  }
398
- resolveTarget(root, candidate) {
376
+ resolveTarget(contextRoot, currentQuery, candidate) {
399
377
  var _a;
400
- const boundary = this.findRootQueryBoundary(root);
378
+ const boundary = this.findRootQueryBoundary(currentQuery);
401
379
  if (boundary) {
402
380
  return boundary;
403
381
  }
404
- if (!root.fromClause) {
382
+ if (!currentQuery.fromClause) {
405
383
  return {
406
384
  code: "NO_FROM_CLAUSE",
407
385
  reason: "Predicate has no FROM source that can receive it safely."
@@ -409,7 +387,7 @@ class StaticPredicatePlacementOptimizer {
409
387
  }
410
388
  const bindings = [];
411
389
  for (const reference of candidate.references) {
412
- const binding = this.resolveSourceBinding(root, root, reference);
390
+ const binding = this.resolveSourceBinding(contextRoot, currentQuery, reference);
413
391
  if ("code" in binding) {
414
392
  return binding;
415
393
  }
@@ -430,14 +408,14 @@ class StaticPredicatePlacementOptimizer {
430
408
  reason: "Predicate crosses a LATERAL JOIN boundary; moving it may change semantics."
431
409
  };
432
410
  }
433
- const nullableSide = this.findNullableSideBoundary(root.fromClause, binding);
411
+ const nullableSide = this.findNullableSideBoundary(currentQuery.fromClause, binding);
434
412
  if (nullableSide) {
435
413
  return nullableSide;
436
414
  }
437
- const upstream = this.resolveUpstreamQuery(root, binding, candidate.references);
415
+ const upstream = this.resolveUpstreamQuery(contextRoot, binding, candidate.references);
438
416
  if ("code" in upstream) {
439
417
  if (upstream.code === "NO_SAFE_UPSTREAM_QUERY") {
440
- const joinOnTarget = this.resolveBaseTableJoinOnTarget(root, binding);
418
+ const joinOnTarget = this.resolveBaseTableJoinOnTarget(contextRoot, currentQuery, binding);
441
419
  if (!("code" in joinOnTarget)) {
442
420
  return joinOnTarget;
443
421
  }
@@ -462,7 +440,7 @@ class StaticPredicatePlacementOptimizer {
462
440
  }
463
441
  return null;
464
442
  }
465
- resolveTargetPlacement(query, targetColumns) {
443
+ resolveTargetPlacement(contextRoot, query, targetColumns) {
466
444
  const hasOrdinaryDistinct = this.hasOrdinaryDistinct(query);
467
445
  if (this.hasDistinctOnBoundary(query)) {
468
446
  return {
@@ -482,11 +460,11 @@ class StaticPredicatePlacementOptimizer {
482
460
  reason: "Predicate crosses LIMIT/OFFSET/FETCH boundary; moving it may change row selection semantics."
483
461
  };
484
462
  }
485
- if (query.fromClause && this.hasOuterJoin(query.fromClause)) {
486
- return {
487
- code: "OUTER_JOIN_BOUNDARY",
488
- reason: "Target query contains an OUTER JOIN boundary that is not moved across in the safe-only implementation."
489
- };
463
+ if (query.fromClause) {
464
+ const nullableSide = this.findNullableSideBoundaryForTargetColumns(contextRoot, query, targetColumns);
465
+ if (nullableSide) {
466
+ return nullableSide;
467
+ }
490
468
  }
491
469
  if (query.groupByClause) {
492
470
  const allReferencesAreGroupKeys = targetColumns.every(item => this.isGroupKeyColumn(query, item.targetColumn));
@@ -515,6 +493,22 @@ class StaticPredicatePlacementOptimizer {
515
493
  reason: "All outer references resolve to direct upstream outputs before unsafe query boundaries."
516
494
  };
517
495
  }
496
+ findNullableSideBoundaryForTargetColumns(contextRoot, query, targetColumns) {
497
+ if (!query.fromClause) {
498
+ return null;
499
+ }
500
+ for (const item of targetColumns) {
501
+ const binding = this.resolveSourceBinding(contextRoot, query, item.targetColumn);
502
+ if ("code" in binding) {
503
+ return binding;
504
+ }
505
+ const nullableSide = this.findNullableSideBoundary(query.fromClause, binding);
506
+ if (nullableSide) {
507
+ return nullableSide;
508
+ }
509
+ }
510
+ return null;
511
+ }
518
512
  resolveSourceBinding(contextRoot, query, column) {
519
513
  const fromClause = query.fromClause;
520
514
  if (!fromClause) {
@@ -527,7 +521,7 @@ class StaticPredicatePlacementOptimizer {
527
521
  const namespace = column.getNamespace();
528
522
  const columnName = column.column.name;
529
523
  if (namespace) {
530
- const matches = bindings.filter(binding => identifiersEqual(binding.alias, namespace));
524
+ const matches = bindings.filter(binding => (0, PredicateExpressionUtils_1.identifiersEqual)(binding.alias, namespace));
531
525
  if (matches.length !== 1) {
532
526
  return {
533
527
  code: "AMBIGUOUS_COLUMN_SOURCE",
@@ -541,13 +535,13 @@ class StaticPredicatePlacementOptimizer {
541
535
  if (matchCount === 0) {
542
536
  return {
543
537
  code: "COLUMN_NOT_AVAILABLE_UPSTREAM",
544
- reason: `Column '${columnReferenceText(column)}' is not a direct output of the referenced source.`
538
+ reason: `Column '${(0, PredicateExpressionUtils_1.columnReferenceText)(column)}' is not a direct output of the referenced source.`
545
539
  };
546
540
  }
547
541
  if (matchCount > 1) {
548
542
  return {
549
543
  code: "AMBIGUOUS_COLUMN_REFERENCE",
550
- reason: `Column '${columnReferenceText(column)}' resolves to multiple outputs in the referenced source.`
544
+ reason: `Column '${(0, PredicateExpressionUtils_1.columnReferenceText)(column)}' resolves to multiple outputs in the referenced source.`
551
545
  };
552
546
  }
553
547
  return matches[0];
@@ -693,22 +687,22 @@ class StaticPredicatePlacementOptimizer {
693
687
  }
694
688
  return resolved;
695
689
  }
696
- resolveBaseTableJoinOnTarget(root, binding) {
690
+ resolveBaseTableJoinOnTarget(contextRoot, currentQuery, binding) {
697
691
  var _a, _b, _c;
698
- if (!root.fromClause || !this.isBaseTableBinding(root, binding)) {
692
+ if (!currentQuery.fromClause || !this.isBaseTableBinding(contextRoot, binding)) {
699
693
  return {
700
694
  code: "NO_SAFE_UPSTREAM_QUERY",
701
695
  reason: "The referenced source is a base table, so there is no upstream query block to move into."
702
696
  };
703
697
  }
704
- if (this.hasOuterJoin(root.fromClause)) {
698
+ if (this.hasOuterJoin(currentQuery.fromClause)) {
705
699
  return {
706
700
  code: "OUTER_JOIN_BOUNDARY",
707
701
  reason: "Predicate crosses an OUTER JOIN boundary; moving it into JOIN ON may change semantics."
708
702
  };
709
703
  }
710
704
  const join = binding.isPrimary
711
- ? (_b = (_a = root.fromClause.joins) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : null
705
+ ? (_b = (_a = currentQuery.fromClause.joins) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : null
712
706
  : binding.join;
713
707
  if (join === null || join === void 0 ? void 0 : join.lateral) {
714
708
  return {
@@ -741,7 +735,7 @@ class StaticPredicatePlacementOptimizer {
741
735
  if (!(join.condition instanceof Clause_1.JoinOnClause)) {
742
736
  return;
743
737
  }
744
- join.condition.condition = new ValueComponent_1.BinaryExpression(join.condition.condition, "and", cloneValueComponent(expression, options));
738
+ join.condition.condition = new ValueComponent_1.BinaryExpression(join.condition.condition, "and", (0, PredicateExpressionUtils_1.cloneValueComponent)(expression, options));
745
739
  join.condition.condition = (0, TopLevelAndConditionDeduper_1.dedupeTopLevelAndConditions)(join.condition.condition, options);
746
740
  }
747
741
  resolveDeepestBranchTarget(contextRoot, query, targetColumns, visited = new Set()) {
@@ -781,7 +775,7 @@ class StaticPredicatePlacementOptimizer {
781
775
  if ("code" in upstreamColumns) {
782
776
  return { query, targetColumns: [...targetColumns] };
783
777
  }
784
- const placement = this.resolveTargetPlacement(upstream.query, upstreamColumns);
778
+ const placement = this.resolveTargetPlacement(contextRoot, upstream.query, upstreamColumns);
785
779
  if ("code" in placement) {
786
780
  return { query, targetColumns: [...targetColumns] };
787
781
  }
@@ -801,12 +795,12 @@ class StaticPredicatePlacementOptimizer {
801
795
  const bindings = this.getSourceBindings(query.fromClause);
802
796
  const namespace = column.getNamespace();
803
797
  if (namespace) {
804
- const matches = bindings.filter(binding => identifiersEqual(binding.alias, namespace));
798
+ const matches = bindings.filter(binding => (0, PredicateExpressionUtils_1.identifiersEqual)(binding.alias, namespace));
805
799
  return matches.length === 1
806
800
  ? null
807
801
  : {
808
802
  code: "AMBIGUOUS_TARGET_COLUMN",
809
- reason: `Target column '${columnReferenceText(column)}' is not uniquely resolvable in the destination query.`
803
+ reason: `Target column '${(0, PredicateExpressionUtils_1.columnReferenceText)(column)}' is not uniquely resolvable in the destination query.`
810
804
  };
811
805
  }
812
806
  if (bindings.length === 1) {
@@ -823,16 +817,16 @@ class StaticPredicatePlacementOptimizer {
823
817
  return false;
824
818
  }
825
819
  return groupBy.grouping.some(grouping => {
826
- const candidate = unwrapParens(grouping);
820
+ const candidate = (0, PredicateExpressionUtils_1.unwrapParens)(grouping);
827
821
  return candidate instanceof ValueComponent_1.ColumnReference
828
822
  && this.sameResolvableColumnInQuery(query, candidate, column);
829
823
  });
830
824
  }
831
825
  sameResolvableColumnInQuery(query, left, right) {
832
- if (sameColumnReference(left, right)) {
826
+ if ((0, PredicateExpressionUtils_1.sameColumnReference)(left, right)) {
833
827
  return true;
834
828
  }
835
- if (!identifiersEqual(left.column.name, right.column.name)) {
829
+ if (!(0, PredicateExpressionUtils_1.identifiersEqual)(left.column.name, right.column.name)) {
836
830
  return false;
837
831
  }
838
832
  const leftSource = this.resolveColumnSourceAlias(query, left);
@@ -846,13 +840,13 @@ class StaticPredicatePlacementOptimizer {
846
840
  const bindings = this.getSourceBindings(query.fromClause);
847
841
  const namespace = column.getNamespace();
848
842
  if (namespace) {
849
- const matches = bindings.filter(binding => identifiersEqual(binding.alias, namespace));
843
+ const matches = bindings.filter(binding => (0, PredicateExpressionUtils_1.identifiersEqual)(binding.alias, namespace));
850
844
  return matches.length === 1 ? matches[0].alias : null;
851
845
  }
852
846
  return bindings.length === 1 ? bindings[0].alias : null;
853
847
  }
854
848
  rebasePredicate(expression, targetColumns, options) {
855
- const cloned = cloneValueComponent(expression, options);
849
+ const cloned = (0, PredicateExpressionUtils_1.cloneValueComponent)(expression, options);
856
850
  const visitSelect = (query, inheritedLocalAliases) => {
857
851
  var _a, _b, _c, _d;
858
852
  if (!(query instanceof SelectQuery_1.SimpleSelectQuery)) {
@@ -885,15 +879,15 @@ class StaticPredicatePlacementOptimizer {
885
879
  }
886
880
  };
887
881
  const visit = (value, localAliases) => {
888
- const candidate = unwrapParens(value);
882
+ const candidate = (0, PredicateExpressionUtils_1.unwrapParens)(value);
889
883
  if (candidate instanceof ValueComponent_1.ColumnReference) {
890
- const namespace = normalizeIdentifier(candidate.getNamespace());
884
+ const namespace = (0, PredicateExpressionUtils_1.normalizeIdentifier)(candidate.getNamespace());
891
885
  if (namespace && localAliases.has(namespace)) {
892
886
  return;
893
887
  }
894
- const target = targetColumns.find(item => sameColumnReference(candidate, item.sourceColumn));
888
+ const target = targetColumns.find(item => (0, PredicateExpressionUtils_1.sameColumnReference)(candidate, item.sourceColumn));
895
889
  if (target) {
896
- candidate.qualifiedName = cloneColumnReference(target.targetColumn).qualifiedName;
890
+ candidate.qualifiedName = (0, PredicateExpressionUtils_1.cloneColumnReference)(target.targetColumn).qualifiedName;
897
891
  }
898
892
  return;
899
893
  }
@@ -1097,7 +1091,7 @@ class StaticPredicatePlacementOptimizer {
1097
1091
  resolveUnionOutputIndex(root, firstBranch, outputColumnName) {
1098
1092
  const matches = [];
1099
1093
  this.collectSelectOutputs(root, firstBranch).forEach((item, index) => {
1100
- if (identifiersEqual(item.name, outputColumnName)) {
1094
+ if ((0, PredicateExpressionUtils_1.identifiersEqual)(item.name, outputColumnName)) {
1101
1095
  matches.push(index);
1102
1096
  }
1103
1097
  });
@@ -1119,7 +1113,7 @@ class StaticPredicatePlacementOptimizer {
1119
1113
  reason: `UNION branch does not expose column '${sourceColumn.column.name}' at output position ${outputIndex + 1}.`
1120
1114
  };
1121
1115
  }
1122
- else if (identifiersEqual(output.name, sourceColumn.column.name)) {
1116
+ else if ((0, PredicateExpressionUtils_1.identifiersEqual)(output.name, sourceColumn.column.name)) {
1123
1117
  const matches = this.collectDirectOutputMatches(root, query, sourceColumn.column.name);
1124
1118
  if (matches.length > 1) {
1125
1119
  return {
@@ -1153,7 +1147,7 @@ class StaticPredicatePlacementOptimizer {
1153
1147
  return collector.collect(query);
1154
1148
  }
1155
1149
  collectDirectOutputMatches(root, query, columnName) {
1156
- const collectedMatches = this.collectSelectOutputs(root, query).filter(item => identifiersEqual(item.name, columnName));
1150
+ const collectedMatches = this.collectSelectOutputs(root, query).filter(item => (0, PredicateExpressionUtils_1.identifiersEqual)(item.name, columnName));
1157
1151
  if (collectedMatches.length > 0) {
1158
1152
  return this.hasExplicitOutputMatch(query, columnName)
1159
1153
  ? [...collectedMatches, ...this.inferWildcardOutputMatches(root, query, columnName, true)]
@@ -1164,11 +1158,11 @@ class StaticPredicatePlacementOptimizer {
1164
1158
  hasExplicitOutputMatch(query, columnName) {
1165
1159
  return query.selectClause.items.some(item => {
1166
1160
  if (item.identifier) {
1167
- return identifiersEqual(item.identifier.name, columnName);
1161
+ return (0, PredicateExpressionUtils_1.identifiersEqual)(item.identifier.name, columnName);
1168
1162
  }
1169
1163
  return item.value instanceof ValueComponent_1.ColumnReference
1170
1164
  && item.value.column.name !== "*"
1171
- && identifiersEqual(item.value.column.name, columnName);
1165
+ && (0, PredicateExpressionUtils_1.identifiersEqual)(item.value.column.name, columnName);
1172
1166
  });
1173
1167
  }
1174
1168
  inferWildcardOutputMatches(root, query, columnName, includeUnprovenPotential) {
@@ -1201,7 +1195,7 @@ class StaticPredicatePlacementOptimizer {
1201
1195
  return this.resolveWildcardColumnFromBinding(root, query, bindings[0], columnName, includeUnprovenPotential);
1202
1196
  }
1203
1197
  const namespace = wildcard.getNamespace();
1204
- const matches = bindings.filter(binding => identifiersEqual(binding.alias, namespace));
1198
+ const matches = bindings.filter(binding => (0, PredicateExpressionUtils_1.identifiersEqual)(binding.alias, namespace));
1205
1199
  if (matches.length === 0) {
1206
1200
  return null;
1207
1201
  }
@@ -1227,7 +1221,7 @@ class StaticPredicatePlacementOptimizer {
1227
1221
  ...((_d = (_c = root.withClause) === null || _c === void 0 ? void 0 : _c.tables) !== null && _d !== void 0 ? _d : [])
1228
1222
  ];
1229
1223
  const collector = new SelectOutputCollector_1.SelectOutputCollector(null, commonTables.length > 0 ? commonTables : null);
1230
- return collector.collect(source).filter(item => identifiersEqual(item.name, columnName));
1224
+ return collector.collect(source).filter(item => (0, PredicateExpressionUtils_1.identifiersEqual)(item.name, columnName));
1231
1225
  }
1232
1226
  createColumnForBinding(binding, columnName) {
1233
1227
  return new ValueComponent_1.ColumnReference(binding.alias ? [binding.alias] : null, columnName);
@@ -1257,13 +1251,13 @@ class StaticPredicatePlacementOptimizer {
1257
1251
  }
1258
1252
  findCte(root, name) {
1259
1253
  var _a, _b;
1260
- const normalized = normalizeIdentifier(name);
1254
+ const normalized = (0, PredicateExpressionUtils_1.normalizeIdentifier)(name);
1261
1255
  const matches = ((_b = (_a = root.withClause) === null || _a === void 0 ? void 0 : _a.tables) !== null && _b !== void 0 ? _b : [])
1262
- .filter(table => normalizeIdentifier(table.getSourceAliasName()) === normalized);
1256
+ .filter(table => (0, PredicateExpressionUtils_1.normalizeIdentifier)(table.getSourceAliasName()) === normalized);
1263
1257
  return matches.length === 1 ? matches[0] : null;
1264
1258
  }
1265
1259
  countTableSourceReferences(query, tableName) {
1266
- const normalized = normalizeIdentifier(tableName);
1260
+ const normalized = (0, PredicateExpressionUtils_1.normalizeIdentifier)(tableName);
1267
1261
  let count = 0;
1268
1262
  const visitSelect = (select) => {
1269
1263
  var _a, _b;
@@ -1278,7 +1272,7 @@ class StaticPredicatePlacementOptimizer {
1278
1272
  if (select.fromClause) {
1279
1273
  for (const binding of this.getSourceBindings(select.fromClause)) {
1280
1274
  const source = binding.source.datasource;
1281
- if (source instanceof Clause_1.TableSource && normalizeIdentifier(source.table.name) === normalized) {
1275
+ if (source instanceof Clause_1.TableSource && (0, PredicateExpressionUtils_1.normalizeIdentifier)(source.table.name) === normalized) {
1282
1276
  count += 1;
1283
1277
  }
1284
1278
  if (source instanceof Clause_1.SubQuerySource) {
@@ -1301,7 +1295,7 @@ class StaticPredicatePlacementOptimizer {
1301
1295
  for (const source of (_b = (_a = query.fromClause) === null || _a === void 0 ? void 0 : _a.getSources()) !== null && _b !== void 0 ? _b : []) {
1302
1296
  const alias = source.getAliasName();
1303
1297
  if (alias) {
1304
- aliases.add(normalizeIdentifier(alias));
1298
+ aliases.add((0, PredicateExpressionUtils_1.normalizeIdentifier)(alias));
1305
1299
  }
1306
1300
  }
1307
1301
  return aliases;
@@ -1341,14 +1335,14 @@ class StaticPredicatePlacementOptimizer {
1341
1335
  }
1342
1336
  };
1343
1337
  const collect = (reference) => {
1344
- if (!references.some(existing => sameColumnReference(existing, reference))) {
1338
+ if (!references.some(existing => (0, PredicateExpressionUtils_1.sameColumnReference)(existing, reference))) {
1345
1339
  references.push(reference);
1346
1340
  }
1347
1341
  };
1348
1342
  const visit = (value, localAliases) => {
1349
- const candidate = unwrapParens(value);
1343
+ const candidate = (0, PredicateExpressionUtils_1.unwrapParens)(value);
1350
1344
  if (candidate instanceof ValueComponent_1.ColumnReference) {
1351
- const namespace = normalizeIdentifier(candidate.getNamespace());
1345
+ const namespace = (0, PredicateExpressionUtils_1.normalizeIdentifier)(candidate.getNamespace());
1352
1346
  if (namespace) {
1353
1347
  if (rootAliases.has(namespace) && !localAliases.has(namespace)) {
1354
1348
  collect(candidate);
@@ -1441,7 +1435,7 @@ class StaticPredicatePlacementOptimizer {
1441
1435
  if (found) {
1442
1436
  return;
1443
1437
  }
1444
- const candidate = unwrapParens(value);
1438
+ const candidate = (0, PredicateExpressionUtils_1.unwrapParens)(value);
1445
1439
  if (candidate instanceof ValueComponent_1.FunctionCall) {
1446
1440
  if (candidate.over) {
1447
1441
  found = true;
@@ -1523,9 +1517,9 @@ class StaticPredicatePlacementOptimizer {
1523
1517
  }
1524
1518
  };
1525
1519
  const visit = (value) => {
1526
- const candidate = unwrapParens(value);
1520
+ const candidate = (0, PredicateExpressionUtils_1.unwrapParens)(value);
1527
1521
  if (candidate instanceof ValueComponent_1.ParameterExpression) {
1528
- appendUnique(names, candidate.name.value);
1522
+ (0, PredicateExpressionUtils_1.appendUnique)(names, candidate.name.value);
1529
1523
  return;
1530
1524
  }
1531
1525
  if (candidate instanceof ValueComponent_1.BinaryExpression) {
@@ -1600,10 +1594,10 @@ class StaticPredicatePlacementOptimizer {
1600
1594
  visit(expression);
1601
1595
  return names;
1602
1596
  }
1603
- makeSkipped(expression, draft, options) {
1597
+ makeSkipped(expression, scopeId, draft, options) {
1604
1598
  return {
1605
1599
  predicateSql: (0, SqlComponentFormatter_1.formatSqlComponent)(expression, options),
1606
- scopeId: "scope:root",
1600
+ scopeId,
1607
1601
  ...draft
1608
1602
  };
1609
1603
  }