rawsql-ts 0.27.0 → 0.29.0

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 (36) hide show
  1. package/dist/esm/index.min.js +1 -1
  2. package/dist/esm/index.min.js.map +4 -4
  3. package/dist/esm/transformers/ConditionDeduplicationOptimizer.d.ts +22 -0
  4. package/dist/esm/transformers/ConditionDeduplicationOptimizer.js +198 -0
  5. package/dist/esm/transformers/ConditionDeduplicationOptimizer.js.map +1 -0
  6. package/dist/esm/transformers/ConditionOptimization.d.ts +35 -1
  7. package/dist/esm/transformers/ConditionOptimization.js +359 -24
  8. package/dist/esm/transformers/ConditionOptimization.js.map +1 -1
  9. package/dist/esm/transformers/ParameterConditionPlacementOptimizer.d.ts +13 -0
  10. package/dist/esm/transformers/ParameterConditionPlacementOptimizer.js +246 -27
  11. package/dist/esm/transformers/ParameterConditionPlacementOptimizer.js.map +1 -1
  12. package/dist/esm/transformers/StaticPredicatePlacementOptimizer.d.ts +12 -0
  13. package/dist/esm/transformers/StaticPredicatePlacementOptimizer.js +211 -18
  14. package/dist/esm/transformers/StaticPredicatePlacementOptimizer.js.map +1 -1
  15. package/dist/esm/transformers/TopLevelAndConditionDeduper.d.ts +10 -0
  16. package/dist/esm/transformers/TopLevelAndConditionDeduper.js +66 -0
  17. package/dist/esm/transformers/TopLevelAndConditionDeduper.js.map +1 -0
  18. package/dist/index.min.js +1 -1
  19. package/dist/index.min.js.map +4 -4
  20. package/dist/src/transformers/ConditionDeduplicationOptimizer.d.ts +22 -0
  21. package/dist/src/transformers/ConditionOptimization.d.ts +35 -1
  22. package/dist/src/transformers/ParameterConditionPlacementOptimizer.d.ts +13 -0
  23. package/dist/src/transformers/StaticPredicatePlacementOptimizer.d.ts +12 -0
  24. package/dist/src/transformers/TopLevelAndConditionDeduper.d.ts +10 -0
  25. package/dist/transformers/ConditionDeduplicationOptimizer.js +202 -0
  26. package/dist/transformers/ConditionDeduplicationOptimizer.js.map +1 -0
  27. package/dist/transformers/ConditionOptimization.js +362 -22
  28. package/dist/transformers/ConditionOptimization.js.map +1 -1
  29. package/dist/transformers/ParameterConditionPlacementOptimizer.js +245 -26
  30. package/dist/transformers/ParameterConditionPlacementOptimizer.js.map +1 -1
  31. package/dist/transformers/StaticPredicatePlacementOptimizer.js +210 -17
  32. package/dist/transformers/StaticPredicatePlacementOptimizer.js.map +1 -1
  33. package/dist/transformers/TopLevelAndConditionDeduper.js +72 -0
  34. package/dist/transformers/TopLevelAndConditionDeduper.js.map +1 -0
  35. package/dist/tsconfig.browser.tsbuildinfo +1 -1
  36. package/package.json +1 -1
@@ -1,13 +1,22 @@
1
- import { DistinctOn, SubQuerySource, TableSource, WhereClause } from "../models/Clause";
1
+ import { DistinctOn, JoinOnClause, SubQuerySource, TableSource, WhereClause } from "../models/Clause";
2
2
  import { BinarySelectQuery, SimpleSelectQuery } from "../models/SelectQuery";
3
3
  import { ArrayExpression, ArrayQueryExpression, BetweenExpression, BinaryExpression, CaseExpression, CastExpression, ColumnReference, FunctionCall, InlineQuery, JsonPredicateExpression, ParameterExpression, ParenExpression, TupleExpression, TypeValue, UnaryExpression, ValueList } from "../models/ValueComponent";
4
4
  import { SelectQueryParser } from "../parsers/SelectQueryParser";
5
5
  import { ValueParser } from "../parsers/ValueParser";
6
6
  import { formatSqlComponent, hasSqlComponentFormatOverride } from "./SqlComponentFormatter";
7
7
  import { SelectOutputCollector } from "./SelectOutputCollector";
8
+ import { dedupeTopLevelAndConditions, dedupeWhereTopLevelAndConditions } from "./TopLevelAndConditionDeduper";
8
9
  const SUPPORTED_OPERATORS = new Set(["=", "<>", "!=", "<", "<=", ">", ">=", "like", "ilike", "in"]);
9
10
  const VOLATILE_OR_UNSUPPORTED_FUNCTION_REASON = "Condition contains a function call; volatile and expression predicates are not moved in the safe-only implementation.";
10
11
  const normalizeIdentifier = (value) => value.trim().toLowerCase();
12
+ const isCaseSensitiveIdentifier = (value) => /[A-Z]/.test(value.trim());
13
+ const identifiersEqual = (left, right) => {
14
+ const trimmedLeft = left.trim();
15
+ const trimmedRight = right.trim();
16
+ return isCaseSensitiveIdentifier(trimmedLeft) || isCaseSensitiveIdentifier(trimmedRight)
17
+ ? trimmedLeft === trimmedRight
18
+ : trimmedLeft.toLowerCase() === trimmedRight.toLowerCase();
19
+ };
11
20
  const unwrapParens = (expression) => {
12
21
  let candidate = expression;
13
22
  while (candidate instanceof ParenExpression) {
@@ -59,8 +68,8 @@ const columnReferenceText = (reference) => {
59
68
  return namespace ? `${namespace}.${reference.column.name}` : reference.column.name;
60
69
  };
61
70
  const sameColumnReference = (left, right) => {
62
- return normalizeIdentifier(left.column.name) === normalizeIdentifier(right.column.name)
63
- && normalizeIdentifier(left.getNamespace()) === normalizeIdentifier(right.getNamespace());
71
+ return identifiersEqual(left.column.name, right.column.name)
72
+ && identifiersEqual(left.getNamespace(), right.getNamespace());
64
73
  };
65
74
  const appendUnique = (items, value) => {
66
75
  if (!items.includes(value)) {
@@ -120,7 +129,11 @@ export class ParameterConditionPlacementOptimizer {
120
129
  continue;
121
130
  }
122
131
  let appliedReason = "";
123
- if (target.kind === "simple") {
132
+ if (target.kind === "join_on") {
133
+ this.appendJoinOnCondition(target.join, candidate.expression, options);
134
+ appliedReason = target.reason;
135
+ }
136
+ else if (target.kind === "simple") {
124
137
  const targetColumns = this.resolveTargetColumns(query, target.query, candidate.references);
125
138
  if ("code" in targetColumns) {
126
139
  skipped.push(this.makeSkipped(term, targetColumns, options));
@@ -133,6 +146,7 @@ export class ParameterConditionPlacementOptimizer {
133
146
  }
134
147
  const movedCondition = this.rebaseCondition(candidate.expression, targetColumns, options);
135
148
  target.query.appendWhere(movedCondition);
149
+ dedupeWhereTopLevelAndConditions(target.query, options);
136
150
  appliedReason = placement.reason;
137
151
  }
138
152
  else {
@@ -153,6 +167,7 @@ export class ParameterConditionPlacementOptimizer {
153
167
  for (const branch of target.branches) {
154
168
  const movedCondition = this.rebaseCondition(candidate.expression, branch.targetColumns, options);
155
169
  branch.query.appendWhere(movedCondition);
170
+ dedupeWhereTopLevelAndConditions(branch.query, options);
156
171
  }
157
172
  appliedReason = placements.some(item => /group by/i.test(item.reason))
158
173
  ? "Condition is distributed to every UNION branch by output column position; grouped branches only receive GROUP BY-key predicates."
@@ -351,9 +366,15 @@ export class ParameterConditionPlacementOptimizer {
351
366
  }
352
367
  return null;
353
368
  }
369
+ if (candidate instanceof UnaryExpression) {
370
+ const operator = candidate.operator.value.trim().toLowerCase();
371
+ if (operator === "not") {
372
+ return visit(candidate.expression);
373
+ }
374
+ }
354
375
  return {
355
376
  code: "UNSUPPORTED_PARAMETER_CONDITION",
356
- reason: "Only simple binary, BETWEEN, and whole OR/AND parameter predicates are moved in the safe-only implementation."
377
+ reason: "Only simple binary, BETWEEN, and whole OR/AND/NOT parameter predicates are moved in the safe-only implementation."
357
378
  };
358
379
  };
359
380
  return visit(expression);
@@ -374,6 +395,7 @@ export class ParameterConditionPlacementOptimizer {
374
395
  && right.values.every(value => unwrapParens(value) instanceof ParameterExpression);
375
396
  }
376
397
  resolveTarget(root, candidate) {
398
+ var _a;
377
399
  const boundary = this.findRootQueryBoundary(root);
378
400
  if (boundary) {
379
401
  return boundary;
@@ -401,12 +423,25 @@ export class ParameterConditionPlacementOptimizer {
401
423
  };
402
424
  }
403
425
  const binding = bindings[0];
426
+ if ((_a = binding.join) === null || _a === void 0 ? void 0 : _a.lateral) {
427
+ return {
428
+ code: "LATERAL_JOIN_BOUNDARY",
429
+ reason: "Condition crosses a LATERAL JOIN boundary; moving it may change semantics."
430
+ };
431
+ }
404
432
  const nullableSide = this.findNullableSideBoundary(root.fromClause, binding);
405
433
  if (nullableSide) {
406
434
  return nullableSide;
407
435
  }
408
436
  const upstream = this.resolveUpstreamQuery(root, binding, candidate.references);
409
437
  if ("code" in upstream) {
438
+ if (upstream.code === "NO_SAFE_UPSTREAM_QUERY") {
439
+ const joinOnTarget = this.resolveBaseTableJoinOnTarget(root, binding);
440
+ if (!("code" in joinOnTarget)) {
441
+ return joinOnTarget;
442
+ }
443
+ return joinOnTarget;
444
+ }
410
445
  return upstream;
411
446
  }
412
447
  return upstream;
@@ -488,10 +523,10 @@ export class ParameterConditionPlacementOptimizer {
488
523
  };
489
524
  }
490
525
  const bindings = this.getSourceBindings(fromClause);
491
- const namespace = normalizeIdentifier(column.getNamespace());
526
+ const namespace = column.getNamespace();
492
527
  const columnName = column.column.name;
493
528
  if (namespace) {
494
- const matches = bindings.filter(binding => normalizeIdentifier(binding.alias) === namespace);
529
+ const matches = bindings.filter(binding => identifiersEqual(binding.alias, namespace));
495
530
  if (matches.length !== 1) {
496
531
  return {
497
532
  code: "AMBIGUOUS_COLUMN_SOURCE",
@@ -499,6 +534,9 @@ export class ParameterConditionPlacementOptimizer {
499
534
  };
500
535
  }
501
536
  const matchCount = this.getOutputColumnMatchCount(contextRoot, matches[0], columnName);
537
+ if (matchCount === 0 && this.isBaseTableBinding(contextRoot, matches[0])) {
538
+ return matches[0];
539
+ }
502
540
  if (matchCount === 0) {
503
541
  return {
504
542
  code: "COLUMN_NOT_AVAILABLE_UPSTREAM",
@@ -627,7 +665,7 @@ export class ParameterConditionPlacementOptimizer {
627
665
  resolveTargetColumns(root, query, references) {
628
666
  const resolved = [];
629
667
  for (const reference of references) {
630
- const matches = this.collectSelectOutputs(root, query).filter(item => normalizeIdentifier(item.name) === normalizeIdentifier(reference.column.name));
668
+ const matches = this.collectDirectOutputMatches(root, query, reference.column.name);
631
669
  if (matches.length !== 1) {
632
670
  return {
633
671
  code: "AMBIGUOUS_TARGET_COLUMN",
@@ -654,6 +692,57 @@ export class ParameterConditionPlacementOptimizer {
654
692
  }
655
693
  return resolved;
656
694
  }
695
+ resolveBaseTableJoinOnTarget(root, binding) {
696
+ var _a, _b, _c;
697
+ if (!root.fromClause || !this.isBaseTableBinding(root, binding)) {
698
+ return {
699
+ code: "NO_SAFE_UPSTREAM_QUERY",
700
+ reason: "The referenced source is a base table, so there is no upstream query block to move into."
701
+ };
702
+ }
703
+ if (this.hasOuterJoin(root.fromClause)) {
704
+ return {
705
+ code: "OUTER_JOIN_BOUNDARY",
706
+ reason: "Condition crosses an OUTER JOIN boundary; moving it into JOIN ON may change semantics."
707
+ };
708
+ }
709
+ const join = binding.isPrimary
710
+ ? (_b = (_a = root.fromClause.joins) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : null
711
+ : binding.join;
712
+ if (join === null || join === void 0 ? void 0 : join.lateral) {
713
+ return {
714
+ code: "LATERAL_JOIN_BOUNDARY",
715
+ reason: "Condition crosses a LATERAL JOIN boundary; moving it into JOIN ON may change semantics."
716
+ };
717
+ }
718
+ if (!join || !this.isInnerJoin(join)) {
719
+ return {
720
+ code: "NO_SAFE_JOIN_ON_TARGET",
721
+ reason: "Base-table conditions are moved only into INNER JOIN ON clauses in the safe-only implementation."
722
+ };
723
+ }
724
+ if (!(join.condition instanceof JoinOnClause)) {
725
+ return {
726
+ code: "NO_SAFE_JOIN_ON_TARGET",
727
+ reason: "Base-table conditions are moved only into existing JOIN ON clauses, not USING or conditionless joins."
728
+ };
729
+ }
730
+ return {
731
+ kind: "join_on",
732
+ join,
733
+ scopeId: `join_on:${(_c = join.source.getAliasName()) !== null && _c !== void 0 ? _c : "unknown"}`,
734
+ reason: binding.isPrimary
735
+ ? "Condition references the primary source of an INNER JOIN; it is moved into the first JOIN ON clause."
736
+ : "Condition references the joined source of an INNER JOIN; it is moved into that JOIN ON clause."
737
+ };
738
+ }
739
+ appendJoinOnCondition(join, expression, options) {
740
+ if (!(join.condition instanceof JoinOnClause)) {
741
+ return;
742
+ }
743
+ join.condition.condition = new BinaryExpression(join.condition.condition, "and", cloneValueComponent(expression, options));
744
+ join.condition.condition = dedupeTopLevelAndConditions(join.condition.condition, options);
745
+ }
657
746
  resolveTargetColumnByOutputIndex(root, query, outputIndex, sourceColumn) {
658
747
  const output = this.collectSelectOutputs(root, query)[outputIndex];
659
748
  if (!output) {
@@ -662,6 +751,15 @@ export class ParameterConditionPlacementOptimizer {
662
751
  reason: `UNION branch does not expose column '${sourceColumn.column.name}' at output position ${outputIndex + 1}.`
663
752
  };
664
753
  }
754
+ else if (identifiersEqual(output.name, sourceColumn.column.name)) {
755
+ const matches = this.collectDirectOutputMatches(root, query, sourceColumn.column.name);
756
+ if (matches.length > 1) {
757
+ return {
758
+ code: "AMBIGUOUS_TARGET_COLUMN",
759
+ reason: `UNION branch exposes multiple '${sourceColumn.column.name}' columns.`
760
+ };
761
+ }
762
+ }
665
763
  if (!(output.value instanceof ColumnReference)) {
666
764
  return {
667
765
  code: "EXPRESSION_OUTPUT_UNSUPPORTED",
@@ -704,7 +802,10 @@ export class ParameterConditionPlacementOptimizer {
704
802
  return { query, targetColumns: [...targetColumns] };
705
803
  }
706
804
  const upstream = this.resolveUpstreamQuery(contextRoot, binding, targetColumns.map(item => item.targetColumn));
707
- if ("code" in upstream || upstream.kind === "union") {
805
+ if ("code" in upstream) {
806
+ return { query, targetColumns: [...targetColumns] };
807
+ }
808
+ if (upstream.kind !== "simple") {
708
809
  return { query, targetColumns: [...targetColumns] };
709
810
  }
710
811
  const upstreamColumns = this.resolveTargetColumns(contextRoot, upstream.query, targetColumns.map(item => item.targetColumn));
@@ -729,9 +830,9 @@ export class ParameterConditionPlacementOptimizer {
729
830
  };
730
831
  }
731
832
  const bindings = this.getSourceBindings(query.fromClause);
732
- const namespace = normalizeIdentifier(column.getNamespace());
833
+ const namespace = column.getNamespace();
733
834
  if (namespace) {
734
- const matches = bindings.filter(binding => normalizeIdentifier(binding.alias) === namespace);
835
+ const matches = bindings.filter(binding => identifiersEqual(binding.alias, namespace));
735
836
  return matches.length === 1
736
837
  ? null
737
838
  : {
@@ -762,7 +863,7 @@ export class ParameterConditionPlacementOptimizer {
762
863
  if (sameColumnReference(left, right)) {
763
864
  return true;
764
865
  }
765
- if (normalizeIdentifier(left.column.name) !== normalizeIdentifier(right.column.name)) {
866
+ if (!identifiersEqual(left.column.name, right.column.name)) {
766
867
  return false;
767
868
  }
768
869
  const leftSource = this.resolveColumnSourceAlias(query, left);
@@ -774,12 +875,12 @@ export class ParameterConditionPlacementOptimizer {
774
875
  return null;
775
876
  }
776
877
  const bindings = this.getSourceBindings(query.fromClause);
777
- const namespace = normalizeIdentifier(column.getNamespace());
878
+ const namespace = column.getNamespace();
778
879
  if (namespace) {
779
- const matches = bindings.filter(binding => normalizeIdentifier(binding.alias) === namespace);
780
- return matches.length === 1 ? normalizeIdentifier(matches[0].alias) : null;
880
+ const matches = bindings.filter(binding => identifiersEqual(binding.alias, namespace));
881
+ return matches.length === 1 ? matches[0].alias : null;
781
882
  }
782
- return bindings.length === 1 ? normalizeIdentifier(bindings[0].alias) : null;
883
+ return bindings.length === 1 ? bindings[0].alias : null;
783
884
  }
784
885
  rebaseCondition(expression, targetColumns, options) {
785
886
  const cloned = cloneValueComponent(expression, options);
@@ -797,33 +898,45 @@ export class ParameterConditionPlacementOptimizer {
797
898
  source: fromClause.source,
798
899
  alias: (_a = fromClause.source.getAliasName()) !== null && _a !== void 0 ? _a : "",
799
900
  join: null,
901
+ joinIndex: -1,
800
902
  isPrimary: true
801
903
  }];
802
- for (const join of (_b = fromClause.joins) !== null && _b !== void 0 ? _b : []) {
904
+ for (let index = 0; index < ((_b = fromClause.joins) !== null && _b !== void 0 ? _b : []).length; index += 1) {
905
+ const join = fromClause.joins[index];
803
906
  bindings.push({
804
907
  source: join.source,
805
908
  alias: (_c = join.source.getAliasName()) !== null && _c !== void 0 ? _c : "",
806
909
  join,
910
+ joinIndex: index,
807
911
  isPrimary: false
808
912
  });
809
913
  }
810
914
  return bindings;
811
915
  }
916
+ isBaseTableBinding(root, binding) {
917
+ const source = binding.source.datasource;
918
+ return source instanceof TableSource && !this.findCte(root, source.table.name);
919
+ }
920
+ isInnerJoin(join) {
921
+ const joinType = join.joinType.value.trim().toLowerCase();
922
+ return joinType === "join" || joinType === "inner join";
923
+ }
812
924
  findNullableSideBoundary(fromClause, binding) {
813
925
  var _a;
814
- if (!binding.join) {
815
- const rightOrFull = ((_a = fromClause.joins) !== null && _a !== void 0 ? _a : []).some(join => {
816
- const joinType = join.joinType.value.toLowerCase();
817
- return joinType.includes("right") || joinType.includes("full");
818
- });
819
- return rightOrFull
926
+ const joins = (_a = fromClause.joins) !== null && _a !== void 0 ? _a : [];
927
+ if (binding.isPrimary) {
928
+ return this.hasLaterJoinThatNullsPriorSources(joins, -1)
820
929
  ? {
821
930
  code: "OUTER_JOIN_NULLABLE_SIDE",
822
931
  reason: "Condition crosses OUTER JOIN nullable side; moving it may change semantics."
823
932
  }
824
933
  : null;
825
934
  }
826
- const joinType = binding.join.joinType.value.toLowerCase();
935
+ const join = binding.join;
936
+ if (!join) {
937
+ return null;
938
+ }
939
+ const joinType = join.joinType.value.toLowerCase();
827
940
  if (joinType.includes("left")) {
828
941
  return {
829
942
  code: "OUTER_JOIN_NULLABLE_SIDE",
@@ -836,8 +949,22 @@ export class ParameterConditionPlacementOptimizer {
836
949
  reason: "Condition crosses FULL JOIN nullable side; moving it may change semantics."
837
950
  };
838
951
  }
952
+ if (this.hasLaterJoinThatNullsPriorSources(joins, binding.joinIndex)) {
953
+ return {
954
+ code: "OUTER_JOIN_NULLABLE_SIDE",
955
+ reason: "Condition crosses later RIGHT/FULL JOIN nullable side; moving it may change semantics."
956
+ };
957
+ }
839
958
  return null;
840
959
  }
960
+ hasLaterJoinThatNullsPriorSources(joins, sourceJoinIndex) {
961
+ return joins
962
+ .slice(sourceJoinIndex + 1)
963
+ .some(join => {
964
+ const joinType = join.joinType.value.toLowerCase();
965
+ return joinType.includes("right") || joinType.includes("full");
966
+ });
967
+ }
841
968
  hasOuterJoin(fromClause) {
842
969
  var _a;
843
970
  return ((_a = fromClause.joins) !== null && _a !== void 0 ? _a : []).some(join => {
@@ -861,12 +988,12 @@ export class ParameterConditionPlacementOptimizer {
861
988
  if ("code" in branches) {
862
989
  return 0;
863
990
  }
864
- return this.collectSelectOutputs(root, branches[0]).filter(item => normalizeIdentifier(item.name) === normalizeIdentifier(columnName)).length;
991
+ return this.collectDirectOutputMatches(root, branches[0], columnName).length;
865
992
  }
866
993
  if (!(target instanceof SimpleSelectQuery)) {
867
994
  return 0;
868
995
  }
869
- return this.collectSelectOutputs(root, target).filter(item => normalizeIdentifier(item.name) === normalizeIdentifier(columnName)).length;
996
+ return this.collectDirectOutputMatches(root, target, columnName, true).length;
870
997
  }
871
998
  collectUnionBranches(query) {
872
999
  const branches = [];
@@ -897,7 +1024,7 @@ export class ParameterConditionPlacementOptimizer {
897
1024
  resolveUnionOutputIndex(root, firstBranch, outputColumnName) {
898
1025
  const matches = [];
899
1026
  this.collectSelectOutputs(root, firstBranch).forEach((item, index) => {
900
- if (normalizeIdentifier(item.name) === normalizeIdentifier(outputColumnName)) {
1027
+ if (identifiersEqual(item.name, outputColumnName)) {
901
1028
  matches.push(index);
902
1029
  }
903
1030
  });
@@ -920,6 +1047,98 @@ export class ParameterConditionPlacementOptimizer {
920
1047
  const collector = new SelectOutputCollector(null, commonTables.length > 0 ? commonTables : null);
921
1048
  return collector.collect(query);
922
1049
  }
1050
+ collectDirectOutputMatches(root, query, columnName, includeUnprovenPotential = false) {
1051
+ const collectedMatches = this.collectSelectOutputs(root, query).filter(item => identifiersEqual(item.name, columnName));
1052
+ if (collectedMatches.length > 0) {
1053
+ return this.hasExplicitOutputMatch(query, columnName)
1054
+ ? [...collectedMatches, ...this.inferWildcardOutputMatches(root, query, columnName, true)]
1055
+ : collectedMatches;
1056
+ }
1057
+ return this.inferWildcardOutputMatches(root, query, columnName, includeUnprovenPotential);
1058
+ }
1059
+ hasExplicitOutputMatch(query, columnName) {
1060
+ return query.selectClause.items.some(item => {
1061
+ if (item.identifier) {
1062
+ return identifiersEqual(item.identifier.name, columnName);
1063
+ }
1064
+ return item.value instanceof ColumnReference
1065
+ && item.value.column.name !== "*"
1066
+ && identifiersEqual(item.value.column.name, columnName);
1067
+ });
1068
+ }
1069
+ inferWildcardOutputMatches(root, query, columnName, includeUnprovenPotential) {
1070
+ const matches = [];
1071
+ query.selectClause.items.forEach((item, outputIndex) => {
1072
+ if (item.identifier || !(item.value instanceof ColumnReference) || item.value.column.name !== "*") {
1073
+ return;
1074
+ }
1075
+ const targetColumn = this.inferWildcardTargetColumn(root, query, item.value, columnName, includeUnprovenPotential);
1076
+ if (!targetColumn) {
1077
+ return;
1078
+ }
1079
+ if (targetColumn === "ambiguous") {
1080
+ matches.push(this.createInferredOutputColumn(columnName, new ColumnReference(null, columnName), outputIndex), this.createInferredOutputColumn(columnName, new ColumnReference(null, columnName), outputIndex));
1081
+ return;
1082
+ }
1083
+ matches.push(this.createInferredOutputColumn(columnName, targetColumn, outputIndex));
1084
+ });
1085
+ return matches;
1086
+ }
1087
+ inferWildcardTargetColumn(root, query, wildcard, columnName, includeUnprovenPotential) {
1088
+ if (!query.fromClause) {
1089
+ return null;
1090
+ }
1091
+ const bindings = this.getSourceBindings(query.fromClause);
1092
+ if (wildcard.namespaces === null) {
1093
+ if (bindings.length !== 1) {
1094
+ return "ambiguous";
1095
+ }
1096
+ return this.resolveWildcardColumnFromBinding(root, query, bindings[0], columnName, includeUnprovenPotential);
1097
+ }
1098
+ const namespace = wildcard.getNamespace();
1099
+ const matches = bindings.filter(binding => identifiersEqual(binding.alias, namespace));
1100
+ if (matches.length === 0) {
1101
+ return null;
1102
+ }
1103
+ return matches.length === 1
1104
+ ? this.resolveWildcardColumnFromBinding(root, query, matches[0], columnName, includeUnprovenPotential)
1105
+ : "ambiguous";
1106
+ }
1107
+ resolveWildcardColumnFromBinding(root, query, binding, columnName, includeUnprovenPotential) {
1108
+ const matches = this.collectSourceOutputMatches(root, query, binding.source, columnName);
1109
+ if (matches.length > 1) {
1110
+ return "ambiguous";
1111
+ }
1112
+ if (matches.length === 1) {
1113
+ const value = matches[0].value;
1114
+ return value instanceof ColumnReference ? value : null;
1115
+ }
1116
+ return includeUnprovenPotential && binding.source.datasource instanceof TableSource
1117
+ ? this.createColumnForBinding(binding, columnName)
1118
+ : null;
1119
+ }
1120
+ collectSourceOutputMatches(root, query, source, columnName) {
1121
+ var _a, _b, _c, _d;
1122
+ const commonTables = [
1123
+ ...((_b = (_a = query.withClause) === null || _a === void 0 ? void 0 : _a.tables) !== null && _b !== void 0 ? _b : []),
1124
+ ...((_d = (_c = root.withClause) === null || _c === void 0 ? void 0 : _c.tables) !== null && _d !== void 0 ? _d : [])
1125
+ ];
1126
+ const collector = new SelectOutputCollector(null, commonTables.length > 0 ? commonTables : null);
1127
+ return collector.collect(source).filter(item => identifiersEqual(item.name, columnName));
1128
+ }
1129
+ createColumnForBinding(binding, columnName) {
1130
+ return new ColumnReference(binding.alias ? [binding.alias] : null, columnName);
1131
+ }
1132
+ createInferredOutputColumn(name, value, outputIndex) {
1133
+ return {
1134
+ name,
1135
+ value,
1136
+ outputIndex,
1137
+ sourceAlias: value.getNamespace() || null,
1138
+ sourceName: null,
1139
+ sourceColumnName: name
1140
+ };
1141
+ }
923
1142
  resolveSourceQueryForColumns(root, source) {
924
1143
  var _a;
925
1144
  if (source.datasource instanceof SubQuerySource) {