rawsql-ts 0.26.0 → 0.27.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 (42) hide show
  1. package/dist/esm/index.d.ts +2 -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 +11 -1
  7. package/dist/esm/transformers/ConditionOptimization.js +122 -66
  8. package/dist/esm/transformers/ConditionOptimization.js.map +1 -1
  9. package/dist/esm/transformers/ParameterConditionPlacementOptimizer.d.ts +26 -7
  10. package/dist/esm/transformers/ParameterConditionPlacementOptimizer.js +408 -141
  11. package/dist/esm/transformers/ParameterConditionPlacementOptimizer.js.map +1 -1
  12. package/dist/esm/transformers/SSSQLFilterBuilder.d.ts +6 -0
  13. package/dist/esm/transformers/SSSQLFilterBuilder.js +84 -8
  14. package/dist/esm/transformers/SSSQLFilterBuilder.js.map +1 -1
  15. package/dist/esm/transformers/SqlComponentFormatter.d.ts +11 -0
  16. package/dist/esm/transformers/SqlComponentFormatter.js +16 -0
  17. package/dist/esm/transformers/SqlComponentFormatter.js.map +1 -0
  18. package/dist/esm/transformers/StaticPredicatePlacementOptimizer.d.ts +103 -0
  19. package/dist/esm/transformers/StaticPredicatePlacementOptimizer.js +1435 -0
  20. package/dist/esm/transformers/StaticPredicatePlacementOptimizer.js.map +1 -0
  21. package/dist/index.js +1 -0
  22. package/dist/index.js.map +1 -1
  23. package/dist/index.min.js +2 -2
  24. package/dist/index.min.js.map +4 -4
  25. package/dist/src/index.d.ts +2 -0
  26. package/dist/src/transformers/ConditionOptimization.d.ts +11 -1
  27. package/dist/src/transformers/ParameterConditionPlacementOptimizer.d.ts +26 -7
  28. package/dist/src/transformers/SSSQLFilterBuilder.d.ts +6 -0
  29. package/dist/src/transformers/SqlComponentFormatter.d.ts +11 -0
  30. package/dist/src/transformers/StaticPredicatePlacementOptimizer.d.ts +103 -0
  31. package/dist/transformers/ConditionOptimization.js +146 -65
  32. package/dist/transformers/ConditionOptimization.js.map +1 -1
  33. package/dist/transformers/ParameterConditionPlacementOptimizer.js +407 -140
  34. package/dist/transformers/ParameterConditionPlacementOptimizer.js.map +1 -1
  35. package/dist/transformers/SSSQLFilterBuilder.js +92 -16
  36. package/dist/transformers/SSSQLFilterBuilder.js.map +1 -1
  37. package/dist/transformers/SqlComponentFormatter.js +21 -0
  38. package/dist/transformers/SqlComponentFormatter.js.map +1 -0
  39. package/dist/transformers/StaticPredicatePlacementOptimizer.js +1445 -0
  40. package/dist/transformers/StaticPredicatePlacementOptimizer.js.map +1 -0
  41. package/dist/tsconfig.browser.tsbuildinfo +1 -1
  42. package/package.json +1 -1
@@ -77,8 +77,10 @@ export * from './transformers/FilterableItemCollector';
77
77
  export { FixtureCteBuilder, FixtureTableDefinition, FixtureColumnDefinition } from './transformers/FixtureCteBuilder';
78
78
  export * from './transformers/DynamicQueryBuilder';
79
79
  export * from './transformers/SSSQLFilterBuilder';
80
+ export type { FormattableSqlComponent, SqlComponentFormatter, SqlComponentFormatOptions } from './transformers/SqlComponentFormatter';
80
81
  export * from './transformers/ConditionOptimization';
81
82
  export * from './transformers/ParameterConditionPlacementOptimizer';
83
+ export * from './transformers/StaticPredicatePlacementOptimizer';
82
84
  export * from './transformers/PruneOptionalConditionBranches';
83
85
  export { SchemaInfo, optimizeUnusedLeftJoins, optimizeUnusedLeftJoinsToFixedPoint, optimizeUnusedCtes, optimizeUnusedCtesToFixedPoint } from './transformers/OptimizeUnusedLeftJoins';
84
86
  export * from './transformers/TableColumnResolver';
@@ -1,8 +1,9 @@
1
1
  import { SelectQuery, SimpleSelectQuery } from "../models/SelectQuery";
2
2
  import { ParameterConditionMove, ParameterConditionOptimizationError, ParameterConditionOptimizationOptions, ParameterConditionOptimizationWarning, ParameterConditionSkipped } from "./ParameterConditionPlacementOptimizer";
3
+ import { StaticPredicateMove, StaticPredicatePlacementError, StaticPredicatePlacementWarning, StaticPredicateSkipped } from "./StaticPredicatePlacementOptimizer";
3
4
  import { OptionalConditionPruningParameters } from "./PruneOptionalConditionBranches";
4
5
  export type ConditionOptimizationInput = string | SelectQuery | SimpleSelectQuery;
5
- export type ConditionOptimizationPhaseKind = "sssql_optional_condition" | "parameter_condition_placement";
6
+ export type ConditionOptimizationPhaseKind = "sssql_optional_condition" | "parameter_condition_placement" | "static_predicate_placement";
6
7
  export interface ConditionOptimizationOptions extends ParameterConditionOptimizationOptions {
7
8
  /**
8
9
  * Explicit opt-in values for SSSQL optional branch pruning.
@@ -36,15 +37,23 @@ export interface SssqlOptionalConditionSkipped {
36
37
  }
37
38
  export type ConditionOptimizationApplied = SssqlOptionalConditionApplied | (ParameterConditionMove & {
38
39
  phaseKind: "parameter_condition_placement";
40
+ }) | (StaticPredicateMove & {
41
+ phaseKind: "static_predicate_placement";
39
42
  });
40
43
  export type ConditionOptimizationSkipped = SssqlOptionalConditionSkipped | (ParameterConditionSkipped & {
41
44
  phaseKind: "parameter_condition_placement";
45
+ }) | (StaticPredicateSkipped & {
46
+ phaseKind: "static_predicate_placement";
42
47
  });
43
48
  export type ConditionOptimizationWarning = (ParameterConditionOptimizationWarning & {
44
49
  phaseKind: ConditionOptimizationPhaseKind;
50
+ }) | (StaticPredicatePlacementWarning & {
51
+ phaseKind: ConditionOptimizationPhaseKind;
45
52
  });
46
53
  export type ConditionOptimizationError = (ParameterConditionOptimizationError & {
47
54
  phaseKind: ConditionOptimizationPhaseKind;
55
+ }) | (StaticPredicatePlacementError & {
56
+ phaseKind: ConditionOptimizationPhaseKind;
48
57
  });
49
58
  export interface ConditionOptimizationSafety {
50
59
  mode: "safe_only";
@@ -55,6 +64,7 @@ export interface ConditionOptimizationSafety {
55
64
  export interface ConditionOptimizationResult {
56
65
  ok: boolean;
57
66
  sql: string;
67
+ query: SelectQuery | null;
58
68
  phases: readonly ConditionOptimizationPhaseSummary[];
59
69
  applied: readonly ConditionOptimizationApplied[];
60
70
  skipped: readonly ConditionOptimizationSkipped[];
@@ -1,15 +1,22 @@
1
1
  import { SelectQuery, SimpleSelectQuery } from "../models/SelectQuery";
2
+ import { SqlComponentFormatOptions } from "./SqlComponentFormatter";
2
3
  export type ParameterConditionOptimizationInput = string | SelectQuery | SimpleSelectQuery;
3
4
  /**
4
5
  * First-phase safe-only placement for ordinary parameter predicates.
5
6
  *
6
7
  * The optimizer intentionally handles only root top-level AND predicates and one
7
8
  * CTE/derived-table hop where the destination output is a direct column reference.
8
- * Unsupported boundaries such as OR, UNION, DISTINCT, GROUP BY, WINDOW, OUTER
9
- * JOIN, expression outputs, and function predicates are reported as skipped.
9
+ * Unsupported boundaries such as OR, DISTINCT ON, WINDOW, OUTER JOIN,
10
+ * expression outputs, and function predicates are reported as skipped.
10
11
  */
11
- export interface ParameterConditionOptimizationOptions {
12
+ export interface ParameterConditionOptimizationOptions extends SqlComponentFormatOptions {
12
13
  dryRun?: boolean;
14
+ /**
15
+ * Whether AST/model inputs should be cloned before optimization.
16
+ * Defaults to true for public-call safety. Internal pipelines can pass false
17
+ * when they own the model and want to avoid AST -> SQL -> AST round trips.
18
+ */
19
+ cloneInput?: boolean;
13
20
  }
14
21
  export interface ParameterConditionOptimizationWarning {
15
22
  code: string;
@@ -45,6 +52,7 @@ export interface ParameterConditionOptimizationSafety {
45
52
  export interface ParameterConditionOptimizationResult {
46
53
  ok: boolean;
47
54
  sql: string;
55
+ query: SelectQuery | null;
48
56
  applied: readonly ParameterConditionMove[];
49
57
  skipped: readonly ParameterConditionSkipped[];
50
58
  warnings: readonly ParameterConditionOptimizationWarning[];
@@ -58,21 +66,32 @@ export declare class ParameterConditionPlacementOptimizer {
58
66
  private parseInput;
59
67
  private analyzeCandidate;
60
68
  private findUnsupportedExpression;
69
+ private findUnsupportedParameterPredicateShape;
61
70
  private isSupportedInPredicate;
62
71
  private resolveTarget;
63
- private findCurrentQueryBoundary;
64
- private findTargetQueryBoundary;
72
+ private findRootQueryBoundary;
73
+ private resolveTargetPlacement;
65
74
  private resolveSourceBinding;
66
75
  private resolveUpstreamQuery;
67
- private resolveTargetColumn;
76
+ private resolveUnionTarget;
77
+ private resolveTargetColumns;
78
+ private resolveTargetColumnByOutputIndex;
79
+ private resolveDeepestBranchTarget;
68
80
  private verifyColumnResolvableInQuery;
81
+ private isGroupKeyColumn;
82
+ private sameResolvableColumnInQuery;
83
+ private resolveColumnSourceAlias;
69
84
  private rebaseCondition;
70
85
  private getSourceBindings;
71
86
  private findNullableSideBoundary;
72
87
  private hasOuterJoin;
88
+ private hasDistinctOnBoundary;
89
+ private hasOrdinaryDistinct;
73
90
  private getOutputColumnMatchCount;
91
+ private collectUnionBranches;
92
+ private resolveUnionOutputIndex;
93
+ private collectSelectOutputs;
74
94
  private resolveSourceQueryForColumns;
75
- private getSelectItemOutputName;
76
95
  private findCte;
77
96
  private countTableSourceReferences;
78
97
  private hasWindowUsage;
@@ -136,6 +136,12 @@ export declare class SSSQLFilterBuilder {
136
136
  private resolveSourceExpressionToUpstreamQuery;
137
137
  private resolveAnchorTargetInQuery;
138
138
  private getSourceAlias;
139
+ private buildScalarRefreshPlan;
140
+ private resolveScalarTargetInQuery;
141
+ private isNullableBranchColumn;
142
+ private hasLaterJoinThatNullsPriorSources;
143
+ private isPriorSourcesNullableJoin;
144
+ private isJoinedSourceNullable;
139
145
  private rebaseMovedBranch;
140
146
  private rebaseMovedBranchByAlias;
141
147
  }
@@ -0,0 +1,11 @@
1
+ import { SelectQuery, SimpleSelectQuery } from "../models/SelectQuery";
2
+ import { ValueComponent } from "../models/ValueComponent";
3
+ import { SqlFormatterOptions } from "./SqlFormatter";
4
+ export type FormattableSqlComponent = SelectQuery | SimpleSelectQuery | ValueComponent;
5
+ export type SqlComponentFormatter = (component: FormattableSqlComponent) => string;
6
+ export interface SqlComponentFormatOptions {
7
+ formatter?: SqlComponentFormatter;
8
+ formatOptions?: SqlFormatterOptions;
9
+ }
10
+ export declare const formatSqlComponent: (component: FormattableSqlComponent, options?: SqlComponentFormatOptions) => string;
11
+ export declare const hasSqlComponentFormatOverride: (options?: SqlComponentFormatOptions) => boolean;
@@ -0,0 +1,103 @@
1
+ import { SelectQuery, SimpleSelectQuery } from "../models/SelectQuery";
2
+ import { SqlComponentFormatOptions } from "./SqlComponentFormatter";
3
+ export type StaticPredicatePlacementInput = string | SelectQuery | SimpleSelectQuery;
4
+ /**
5
+ * Safe-only placement for parameter-free static predicates.
6
+ *
7
+ * The optimizer only moves top-level AND terms whose outer column references can
8
+ * be mechanically rebased to direct outputs of a single-use simple CTE or
9
+ * derived table. Unsupported or ambiguous predicates stay in place.
10
+ */
11
+ export interface StaticPredicatePlacementOptions extends SqlComponentFormatOptions {
12
+ dryRun?: boolean;
13
+ /**
14
+ * Whether AST/model inputs should be cloned before optimization.
15
+ * Defaults to true for public-call safety. Internal pipelines can pass false
16
+ * when they own the model and want to avoid AST -> SQL -> AST round trips.
17
+ */
18
+ cloneInput?: boolean;
19
+ }
20
+ export interface StaticPredicatePlacementWarning {
21
+ code: string;
22
+ message: string;
23
+ detail?: unknown;
24
+ }
25
+ export interface StaticPredicatePlacementError {
26
+ code: string;
27
+ message: string;
28
+ detail?: unknown;
29
+ }
30
+ export interface StaticPredicateMove {
31
+ kind: "move_static_predicate";
32
+ predicateSql: string;
33
+ fromScopeId: string;
34
+ toScopeId: string;
35
+ reason: string;
36
+ columnReferences: readonly string[];
37
+ }
38
+ export interface StaticPredicateSkipped {
39
+ predicateSql: string;
40
+ scopeId: string;
41
+ reason: string;
42
+ code: string;
43
+ }
44
+ export interface StaticPredicatePlacementSafety {
45
+ mode: "safe_only";
46
+ unsafeRewriteApplied: false;
47
+ dryRun: boolean;
48
+ formatterGeneratedSource: boolean;
49
+ }
50
+ export interface StaticPredicatePlacementResult {
51
+ ok: boolean;
52
+ sql: string;
53
+ query: SelectQuery | null;
54
+ applied: readonly StaticPredicateMove[];
55
+ skipped: readonly StaticPredicateSkipped[];
56
+ warnings: readonly StaticPredicatePlacementWarning[];
57
+ errors: readonly StaticPredicatePlacementError[];
58
+ safety: StaticPredicatePlacementSafety;
59
+ staticPredicateMoves: readonly StaticPredicateMove[];
60
+ }
61
+ export declare class StaticPredicatePlacementOptimizer {
62
+ plan(input: StaticPredicatePlacementInput, options?: StaticPredicatePlacementOptions): StaticPredicatePlacementResult;
63
+ optimize(input: StaticPredicatePlacementInput, options?: StaticPredicatePlacementOptions): StaticPredicatePlacementResult;
64
+ private parseInput;
65
+ private analyzeCandidate;
66
+ private isExistsPredicate;
67
+ private findUnsupportedExpression;
68
+ private resolveTarget;
69
+ private findRootQueryBoundary;
70
+ private resolveTargetPlacement;
71
+ private resolveSourceBinding;
72
+ private resolveUpstreamQuery;
73
+ private resolveUnionTarget;
74
+ private resolveTargetColumns;
75
+ private resolveDeepestBranchTarget;
76
+ private verifyColumnResolvableInQuery;
77
+ private isGroupKeyColumn;
78
+ private sameResolvableColumnInQuery;
79
+ private resolveColumnSourceAlias;
80
+ private rebasePredicate;
81
+ private getSourceBindings;
82
+ private findNullableSideBoundary;
83
+ private hasLaterJoinThatNullsPriorSources;
84
+ private hasOuterJoin;
85
+ private hasDistinctOnBoundary;
86
+ private hasOrdinaryDistinct;
87
+ private getOutputColumnMatchCount;
88
+ private collectUnionBranches;
89
+ private resolveUnionOutputIndex;
90
+ private resolveTargetColumnByOutputIndex;
91
+ private collectSelectOutputs;
92
+ private resolveSourceQueryForColumns;
93
+ private findCte;
94
+ private countTableSourceReferences;
95
+ private collectSourceAliases;
96
+ private collectRootColumnReferences;
97
+ private hasWindowUsage;
98
+ private collectParameterNames;
99
+ private makeSkipped;
100
+ private buildResult;
101
+ }
102
+ export declare const planStaticPredicatePlacement: (input: StaticPredicatePlacementInput, options?: StaticPredicatePlacementOptions) => StaticPredicatePlacementResult;
103
+ export declare const optimizeStaticPredicatePlacement: (input: StaticPredicatePlacementInput, options?: StaticPredicatePlacementOptions) => StaticPredicatePlacementResult;
@@ -3,19 +3,26 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.optimizeConditions = exports.planConditionOptimization = void 0;
4
4
  const SelectQueryParser_1 = require("../parsers/SelectQueryParser");
5
5
  const ParameterConditionPlacementOptimizer_1 = require("./ParameterConditionPlacementOptimizer");
6
+ const StaticPredicatePlacementOptimizer_1 = require("./StaticPredicatePlacementOptimizer");
6
7
  const PruneOptionalConditionBranches_1 = require("./PruneOptionalConditionBranches");
7
8
  const SSSQLFilterBuilder_1 = require("./SSSQLFilterBuilder");
8
- const SqlFormatter_1 = require("./SqlFormatter");
9
- const formatSqlComponent = (component) => {
10
- return new SqlFormatter_1.SqlFormatter().format(component).formattedSql;
11
- };
9
+ const SqlComponentFormatter_1 = require("./SqlComponentFormatter");
12
10
  const hasOwnParameter = (parameters, parameterName) => Object.prototype.hasOwnProperty.call(parameters, parameterName);
13
11
  const isAbsentOptionalValue = (parameters, parameterName) => parameters[parameterName] === null || parameters[parameterName] === undefined;
14
- const parseConditionOptimizationInput = (input) => {
12
+ const parseConditionOptimizationInput = (input, options) => {
15
13
  const warnings = [];
16
14
  const errors = [];
17
- const sourceSql = typeof input === "string" ? input : formatSqlComponent(input);
15
+ const sourceSql = typeof input === "string" ? input : (0, SqlComponentFormatter_1.formatSqlComponent)(input, options);
18
16
  const formatterGeneratedSource = typeof input !== "string";
17
+ if (typeof input !== "string" && options.cloneInput === false) {
18
+ return {
19
+ query: input,
20
+ sql: sourceSql,
21
+ formatterGeneratedSource: false,
22
+ warnings,
23
+ errors
24
+ };
25
+ }
19
26
  if (formatterGeneratedSource) {
20
27
  warnings.push({
21
28
  phaseKind: "sssql_optional_condition",
@@ -48,31 +55,31 @@ const parseConditionOptimizationInput = (input) => {
48
55
  };
49
56
  }
50
57
  };
51
- const buildSssqlApplied = (branch) => {
58
+ const buildSssqlApplied = (branch, options) => {
52
59
  return {
53
60
  phaseKind: "sssql_optional_condition",
54
61
  kind: "prune_optional_branch",
55
- conditionSql: formatSqlComponent(branch.expression),
62
+ conditionSql: (0, SqlComponentFormatter_1.formatSqlComponent)(branch.expression, options),
56
63
  parameterName: branch.parameterName,
57
64
  reason: "The optional branch parameter is explicitly absent, so the safe-only SSSQL phase pruned the branch."
58
65
  };
59
66
  };
60
- const buildSssqlRefreshApplied = (branch, previousConditionSql) => {
67
+ const buildSssqlRefreshApplied = (branch, previousConditionSql, options) => {
61
68
  return {
62
69
  phaseKind: "sssql_optional_condition",
63
70
  kind: "refresh_optional_branch",
64
- conditionSql: formatSqlComponent(branch.expression),
71
+ conditionSql: (0, SqlComponentFormatter_1.formatSqlComponent)(branch.expression, options),
65
72
  previousConditionSql,
66
73
  parameterName: branch.parameterName,
67
74
  reason: "The safe-only SSSQL phase refreshed the optional branch placement before ordinary parameter placement."
68
75
  };
69
76
  };
70
- const buildSssqlSkipped = (branch, parameters) => {
77
+ const buildSssqlSkipped = (branch, parameters, options) => {
71
78
  const parameterProvided = hasOwnParameter(parameters, branch.parameterName);
72
79
  return {
73
80
  phaseKind: "sssql_optional_condition",
74
81
  kind: "optional_branch_skipped",
75
- conditionSql: formatSqlComponent(branch.expression),
82
+ conditionSql: (0, SqlComponentFormatter_1.formatSqlComponent)(branch.expression, options),
76
83
  parameterName: branch.parameterName,
77
84
  code: parameterProvided
78
85
  ? "SSSQL_OPTIONAL_PARAMETER_PRESENT"
@@ -82,11 +89,11 @@ const buildSssqlSkipped = (branch, parameters) => {
82
89
  : "No optional branch parameter value was provided, so the branch remains unchanged."
83
90
  };
84
91
  };
85
- const buildSssqlRefreshSkipped = (branch, code, reason) => {
92
+ const buildSssqlRefreshSkipped = (branch, code, reason, options) => {
86
93
  return {
87
94
  phaseKind: "sssql_optional_condition",
88
95
  kind: "optional_branch_skipped",
89
- conditionSql: formatSqlComponent(branch.expression),
96
+ conditionSql: (0, SqlComponentFormatter_1.formatSqlComponent)(branch.expression, options),
90
97
  parameterName: branch.parameterName,
91
98
  code,
92
99
  reason
@@ -101,78 +108,94 @@ const buildSssqlRefreshFilters = (branches, parameters) => {
101
108
  }
102
109
  return filters;
103
110
  };
104
- const refreshRemainingSssqlBranches = (sql, parameters) => {
105
- const parsed = parseConditionOptimizationInput(sql);
111
+ const refreshRemainingSssqlBranches = (query, fallbackSql, parameters, options) => {
106
112
  const applied = [];
107
113
  const skipped = [];
108
- if (!parsed.query) {
109
- return {
110
- sql: parsed.sql,
111
- applied,
112
- skipped,
113
- warnings: parsed.warnings,
114
- errors: parsed.errors,
115
- formatterGeneratedSource: parsed.formatterGeneratedSource
116
- };
117
- }
118
- const beforeBranches = (0, PruneOptionalConditionBranches_1.collectSupportedOptionalConditionBranches)(parsed.query);
114
+ const beforeBranches = (0, PruneOptionalConditionBranches_1.collectSupportedOptionalConditionBranches)(query);
119
115
  if (beforeBranches.length === 0) {
120
116
  return {
121
- sql: parsed.sql,
117
+ query,
118
+ sql: fallbackSql,
122
119
  applied,
123
120
  skipped,
124
- warnings: parsed.warnings,
125
- errors: parsed.errors,
126
- formatterGeneratedSource: parsed.formatterGeneratedSource
121
+ warnings: [],
122
+ errors: [],
123
+ formatterGeneratedSource: false
127
124
  };
128
125
  }
129
126
  const beforeBranchSql = new WeakMap();
130
127
  const beforeBranchQuery = new WeakMap();
131
128
  for (const branch of beforeBranches) {
132
- beforeBranchSql.set(branch.expression, formatSqlComponent(branch.expression));
129
+ beforeBranchSql.set(branch.expression, (0, SqlComponentFormatter_1.formatSqlComponent)(branch.expression, options));
133
130
  beforeBranchQuery.set(branch.expression, branch.query);
134
131
  }
135
132
  try {
136
- new SSSQLFilterBuilder_1.SSSQLFilterBuilder().refresh(parsed.query, buildSssqlRefreshFilters(beforeBranches, parameters));
133
+ new SSSQLFilterBuilder_1.SSSQLFilterBuilder().refresh(query, buildSssqlRefreshFilters(beforeBranches, parameters));
137
134
  }
138
135
  catch (error) {
139
136
  const detail = error instanceof Error ? error.message : String(error);
140
137
  return {
141
- sql,
138
+ query,
139
+ sql: fallbackSql,
142
140
  applied,
143
- skipped: beforeBranches.map(branch => buildSssqlRefreshSkipped(branch, "SSSQL_OPTIONAL_REFRESH_UNSUPPORTED", `SSSQL optional branch refresh was skipped because safe refresh could not be proven: ${detail}`)),
144
- warnings: parsed.warnings,
145
- errors: parsed.errors,
146
- formatterGeneratedSource: parsed.formatterGeneratedSource
141
+ skipped: beforeBranches.map(branch => buildSssqlRefreshSkipped(branch, "SSSQL_OPTIONAL_REFRESH_UNSUPPORTED", `SSSQL optional branch refresh was skipped because safe refresh could not be proven: ${detail}`, options)),
142
+ warnings: [],
143
+ errors: [],
144
+ formatterGeneratedSource: false
147
145
  };
148
146
  }
149
- const afterBranches = (0, PruneOptionalConditionBranches_1.collectSupportedOptionalConditionBranches)(parsed.query);
147
+ const afterBranches = (0, PruneOptionalConditionBranches_1.collectSupportedOptionalConditionBranches)(query);
150
148
  for (const branch of afterBranches) {
151
149
  const previousSql = beforeBranchSql.get(branch.expression);
152
150
  const previousQuery = beforeBranchQuery.get(branch.expression);
153
151
  if (!previousSql || !previousQuery) {
154
- skipped.push(buildSssqlRefreshSkipped(branch, "SSSQL_OPTIONAL_REFRESH_UNSUPPORTED", "SSSQL optional branch refresh left an untracked branch unchanged."));
152
+ skipped.push(buildSssqlRefreshSkipped(branch, "SSSQL_OPTIONAL_REFRESH_UNSUPPORTED", "SSSQL optional branch refresh left an untracked branch unchanged.", options));
155
153
  continue;
156
154
  }
157
- const refreshedSql = formatSqlComponent(branch.expression);
155
+ const refreshedSql = (0, SqlComponentFormatter_1.formatSqlComponent)(branch.expression, options);
158
156
  if (previousQuery !== branch.query || previousSql !== refreshedSql) {
159
- applied.push(buildSssqlRefreshApplied(branch, previousSql));
157
+ applied.push(buildSssqlRefreshApplied(branch, previousSql, options));
160
158
  continue;
161
159
  }
162
- skipped.push(buildSssqlRefreshSkipped(branch, "SSSQL_OPTIONAL_REFRESH_NOOP", "SSSQL optional branch refresh found no safe placement change to apply."));
160
+ skipped.push(buildSssqlRefreshSkipped(branch, "SSSQL_OPTIONAL_REFRESH_NOOP", "SSSQL optional branch refresh found no safe placement change to apply.", options));
163
161
  }
164
162
  return {
165
- sql: applied.length > 0 ? formatSqlComponent(parsed.query) : sql,
163
+ query,
164
+ sql: applied.length > 0 || (0, SqlComponentFormatter_1.hasSqlComponentFormatOverride)(options)
165
+ ? (0, SqlComponentFormatter_1.formatSqlComponent)(query, options)
166
+ : fallbackSql,
166
167
  applied,
167
168
  skipped,
168
- warnings: parsed.warnings,
169
- errors: parsed.errors,
170
- formatterGeneratedSource: parsed.formatterGeneratedSource
169
+ warnings: [],
170
+ errors: [],
171
+ formatterGeneratedSource: false
172
+ };
173
+ };
174
+ const refreshRemainingSssqlBranchesFromSql = (sql, parameters, options) => {
175
+ const parsed = parseConditionOptimizationInput(sql, options);
176
+ if (!parsed.query) {
177
+ return {
178
+ query: null,
179
+ sql: parsed.sql,
180
+ applied: [],
181
+ skipped: [],
182
+ warnings: parsed.warnings,
183
+ errors: parsed.errors,
184
+ formatterGeneratedSource: parsed.formatterGeneratedSource
185
+ };
186
+ }
187
+ const refreshed = refreshRemainingSssqlBranches(parsed.query, sql, parameters, options);
188
+ return {
189
+ ...refreshed,
190
+ warnings: [...parsed.warnings, ...refreshed.warnings],
191
+ errors: [...parsed.errors, ...refreshed.errors],
192
+ formatterGeneratedSource: parsed.formatterGeneratedSource || refreshed.formatterGeneratedSource
171
193
  };
172
194
  };
173
195
  const runSssqlOptionalConditionPhase = (input, options) => {
174
196
  var _a;
175
- const parsed = parseConditionOptimizationInput(input);
197
+ const reuseOwnedModel = options.cloneInput === false && typeof input !== "string";
198
+ const parsed = parseConditionOptimizationInput(input, options);
176
199
  const warnings = [...parsed.warnings];
177
200
  let errors = [...parsed.errors];
178
201
  const applied = [];
@@ -180,6 +203,7 @@ const runSssqlOptionalConditionPhase = (input, options) => {
180
203
  const optionalConditionParameters = (_a = options.optionalConditionParameters) !== null && _a !== void 0 ? _a : {};
181
204
  if (!parsed.query) {
182
205
  return {
206
+ query: null,
183
207
  sql: parsed.sql,
184
208
  applied,
185
209
  skipped,
@@ -189,14 +213,16 @@ const runSssqlOptionalConditionPhase = (input, options) => {
189
213
  };
190
214
  }
191
215
  let currentSql = parsed.sql;
216
+ let currentQuery = parsed.query;
217
+ let formatterGeneratedSource = parsed.formatterGeneratedSource;
192
218
  const branches = (0, PruneOptionalConditionBranches_1.collectSupportedOptionalConditionBranches)(parsed.query);
193
219
  const pruneBranches = branches.filter(branch => hasOwnParameter(optionalConditionParameters, branch.parameterName)
194
220
  && isAbsentOptionalValue(optionalConditionParameters, branch.parameterName));
195
221
  if (pruneBranches.length > 0) {
196
222
  try {
197
223
  (0, PruneOptionalConditionBranches_1.pruneOptionalConditionBranches)(parsed.query, optionalConditionParameters);
198
- currentSql = formatSqlComponent(parsed.query);
199
- applied.push(...pruneBranches.map(buildSssqlApplied));
224
+ currentSql = (0, SqlComponentFormatter_1.formatSqlComponent)(parsed.query, options);
225
+ applied.push(...pruneBranches.map(branch => buildSssqlApplied(branch, options)));
200
226
  }
201
227
  catch (error) {
202
228
  errors = [...errors, {
@@ -208,28 +234,33 @@ const runSssqlOptionalConditionPhase = (input, options) => {
208
234
  }
209
235
  }
210
236
  if (errors.length === 0) {
211
- const refreshPhase = refreshRemainingSssqlBranches(currentSql, optionalConditionParameters);
237
+ const refreshPhase = reuseOwnedModel
238
+ ? refreshRemainingSssqlBranches(parsed.query, currentSql, optionalConditionParameters, options)
239
+ : refreshRemainingSssqlBranchesFromSql(currentSql, optionalConditionParameters, options);
212
240
  applied.push(...refreshPhase.applied);
213
241
  skipped.push(...refreshPhase.skipped);
214
242
  warnings.push(...refreshPhase.warnings);
215
243
  errors.push(...refreshPhase.errors);
216
244
  currentSql = refreshPhase.sql;
245
+ currentQuery = refreshPhase.query;
246
+ formatterGeneratedSource = formatterGeneratedSource || refreshPhase.formatterGeneratedSource;
217
247
  }
218
248
  else {
219
249
  for (const branch of branches) {
220
250
  if (pruneBranches.includes(branch)) {
221
251
  continue;
222
252
  }
223
- skipped.push(buildSssqlSkipped(branch, optionalConditionParameters));
253
+ skipped.push(buildSssqlSkipped(branch, optionalConditionParameters, options));
224
254
  }
225
255
  }
226
256
  return {
257
+ query: errors.length === 0 ? currentQuery : null,
227
258
  sql: errors.length === 0 ? currentSql : parsed.sql,
228
259
  applied,
229
260
  skipped,
230
261
  warnings,
231
262
  errors,
232
- formatterGeneratedSource: parsed.formatterGeneratedSource
263
+ formatterGeneratedSource
233
264
  };
234
265
  };
235
266
  const mapParameterWarnings = (warnings) => warnings.map(warning => ({
@@ -248,6 +279,22 @@ const mapParameterSkipped = (skipped) => skipped.map(item => ({
248
279
  phaseKind: "parameter_condition_placement",
249
280
  ...item
250
281
  }));
282
+ const mapStaticWarnings = (warnings) => warnings.map(warning => ({
283
+ phaseKind: "static_predicate_placement",
284
+ ...warning
285
+ }));
286
+ const mapStaticErrors = (errors) => errors.map(error => ({
287
+ phaseKind: "static_predicate_placement",
288
+ ...error
289
+ }));
290
+ const mapStaticApplied = (applied) => applied.map(item => ({
291
+ phaseKind: "static_predicate_placement",
292
+ ...item
293
+ }));
294
+ const mapStaticSkipped = (skipped) => skipped.map(item => ({
295
+ phaseKind: "static_predicate_placement",
296
+ ...item
297
+ }));
251
298
  const makePhaseSummary = (kind, counts) => ({
252
299
  kind,
253
300
  appliedCount: counts.appliedCount,
@@ -256,24 +303,50 @@ const makePhaseSummary = (kind, counts) => ({
256
303
  errorCount: counts.errorCount
257
304
  });
258
305
  const runConditionOptimization = (input, options, defaultDryRun) => {
259
- var _a;
306
+ var _a, _b, _c;
260
307
  const dryRun = (_a = options.dryRun) !== null && _a !== void 0 ? _a : defaultDryRun;
261
- // Run the semantic SSSQL phase before the generic placement phase so
262
- // optional branches remain owned by SSSQL even if parameter placement grows
263
- // broader OR-predicate support later.
308
+ const reuseOwnedModel = options.cloneInput === false && typeof input !== "string";
309
+ // Run semantic SSSQL handling before generic placement phases so optional
310
+ // branches remain owned by SSSQL even if later phases grow broader support.
264
311
  const sssqlPhase = runSssqlOptionalConditionPhase(input, { ...options, dryRun });
312
+ const parameterOptimizer = new ParameterConditionPlacementOptimizer_1.ParameterConditionPlacementOptimizer();
313
+ const parameterInput = reuseOwnedModel
314
+ ? (_b = sssqlPhase.query) !== null && _b !== void 0 ? _b : sssqlPhase.sql
315
+ : sssqlPhase.sql;
316
+ const parameterOptions = {
317
+ ...options,
318
+ dryRun,
319
+ cloneInput: reuseOwnedModel && sssqlPhase.query ? false : options.cloneInput
320
+ };
265
321
  const parameterPhase = dryRun
266
- ? (0, ParameterConditionPlacementOptimizer_1.planParameterConditionOptimization)(sssqlPhase.sql, { dryRun })
267
- : (0, ParameterConditionPlacementOptimizer_1.optimizeParameterConditionPlacement)(sssqlPhase.sql, { dryRun });
322
+ ? parameterOptimizer.plan(parameterInput, parameterOptions)
323
+ : parameterOptimizer.optimize(parameterInput, parameterOptions);
268
324
  const parameterWarnings = mapParameterWarnings(parameterPhase.warnings);
269
325
  const parameterErrors = mapParameterErrors(parameterPhase.errors);
270
326
  const parameterApplied = mapParameterApplied(parameterPhase.applied);
271
327
  const parameterSkipped = mapParameterSkipped(parameterPhase.skipped);
272
- const warnings = [...sssqlPhase.warnings, ...parameterWarnings];
273
- const errors = [...sssqlPhase.errors, ...parameterErrors];
328
+ const staticOptimizer = new StaticPredicatePlacementOptimizer_1.StaticPredicatePlacementOptimizer();
329
+ const staticInput = reuseOwnedModel
330
+ ? (_c = parameterPhase.query) !== null && _c !== void 0 ? _c : parameterPhase.sql
331
+ : parameterPhase.sql;
332
+ const staticOptions = {
333
+ ...options,
334
+ dryRun,
335
+ cloneInput: reuseOwnedModel && parameterPhase.query ? false : options.cloneInput
336
+ };
337
+ const staticPhase = dryRun
338
+ ? staticOptimizer.plan(staticInput, staticOptions)
339
+ : staticOptimizer.optimize(staticInput, staticOptions);
340
+ const staticWarnings = mapStaticWarnings(staticPhase.warnings);
341
+ const staticErrors = mapStaticErrors(staticPhase.errors);
342
+ const staticApplied = mapStaticApplied(staticPhase.applied);
343
+ const staticSkipped = mapStaticSkipped(staticPhase.skipped);
344
+ const warnings = [...sssqlPhase.warnings, ...parameterWarnings, ...staticWarnings];
345
+ const errors = [...sssqlPhase.errors, ...parameterErrors, ...staticErrors];
274
346
  return {
275
347
  ok: errors.length === 0,
276
- sql: parameterPhase.sql,
348
+ sql: staticPhase.sql,
349
+ query: staticPhase.query,
277
350
  phases: [
278
351
  makePhaseSummary("sssql_optional_condition", {
279
352
  appliedCount: sssqlPhase.applied.length,
@@ -286,17 +359,25 @@ const runConditionOptimization = (input, options, defaultDryRun) => {
286
359
  skippedCount: parameterSkipped.length,
287
360
  warningCount: parameterWarnings.length,
288
361
  errorCount: parameterErrors.length
362
+ }),
363
+ makePhaseSummary("static_predicate_placement", {
364
+ appliedCount: staticApplied.length,
365
+ skippedCount: staticSkipped.length,
366
+ warningCount: staticWarnings.length,
367
+ errorCount: staticErrors.length
289
368
  })
290
369
  ],
291
- applied: [...sssqlPhase.applied, ...parameterApplied],
292
- skipped: [...sssqlPhase.skipped, ...parameterSkipped],
370
+ applied: [...sssqlPhase.applied, ...parameterApplied, ...staticApplied],
371
+ skipped: [...sssqlPhase.skipped, ...parameterSkipped, ...staticSkipped],
293
372
  warnings,
294
373
  errors,
295
374
  safety: {
296
375
  mode: "safe_only",
297
376
  unsafeRewriteApplied: false,
298
377
  dryRun,
299
- formatterGeneratedSource: sssqlPhase.formatterGeneratedSource || parameterPhase.safety.formatterGeneratedSource
378
+ formatterGeneratedSource: sssqlPhase.formatterGeneratedSource
379
+ || parameterPhase.safety.formatterGeneratedSource
380
+ || staticPhase.safety.formatterGeneratedSource
300
381
  }
301
382
  };
302
383
  };