@rawsql-ts/ztd-cli 0.19.0 → 0.20.2

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 (184) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +4 -4
  3. package/dist/commands/agents.d.ts +2 -0
  4. package/dist/commands/agents.js +68 -0
  5. package/dist/commands/agents.js.map +1 -0
  6. package/dist/commands/checkContract.d.ts +46 -0
  7. package/dist/commands/checkContract.js +359 -0
  8. package/dist/commands/checkContract.js.map +1 -0
  9. package/dist/commands/connectionOptions.d.ts +12 -0
  10. package/dist/commands/connectionOptions.js +22 -0
  11. package/dist/commands/connectionOptions.js.map +1 -0
  12. package/dist/commands/ddl.d.ts +7 -0
  13. package/dist/commands/ddl.js +145 -0
  14. package/dist/commands/ddl.js.map +1 -0
  15. package/dist/commands/describe.d.ts +23 -0
  16. package/dist/commands/describe.js +399 -0
  17. package/dist/commands/describe.js.map +1 -0
  18. package/dist/commands/diff.d.ts +24 -0
  19. package/dist/commands/diff.js +73 -0
  20. package/dist/commands/diff.js.map +1 -0
  21. package/dist/commands/genEntities.d.ts +14 -0
  22. package/dist/commands/genEntities.js +58 -0
  23. package/dist/commands/genEntities.js.map +1 -0
  24. package/dist/commands/init.d.ts +104 -0
  25. package/dist/commands/init.js +1480 -0
  26. package/dist/commands/init.js.map +1 -0
  27. package/dist/commands/lint.d.ts +89 -0
  28. package/dist/commands/lint.js +501 -0
  29. package/dist/commands/lint.js.map +1 -0
  30. package/dist/commands/modelGen.d.ts +60 -0
  31. package/dist/commands/modelGen.js +572 -0
  32. package/dist/commands/modelGen.js.map +1 -0
  33. package/dist/commands/options.d.ts +9 -0
  34. package/dist/commands/options.js +48 -0
  35. package/dist/commands/options.js.map +1 -0
  36. package/dist/commands/perf.d.ts +9 -0
  37. package/dist/commands/perf.js +374 -0
  38. package/dist/commands/perf.js.map +1 -0
  39. package/dist/commands/pull.d.ts +21 -0
  40. package/dist/commands/pull.js +115 -0
  41. package/dist/commands/pull.js.map +1 -0
  42. package/dist/commands/query.d.ts +9 -0
  43. package/dist/commands/query.js +377 -0
  44. package/dist/commands/query.js.map +1 -0
  45. package/dist/commands/testEvidence.d.ts +237 -0
  46. package/dist/commands/testEvidence.js +1220 -0
  47. package/dist/commands/testEvidence.js.map +1 -0
  48. package/dist/commands/ztdConfig.d.ts +30 -0
  49. package/dist/commands/ztdConfig.js +224 -0
  50. package/dist/commands/ztdConfig.js.map +1 -0
  51. package/dist/commands/ztdConfigCommand.d.ts +18 -0
  52. package/dist/commands/ztdConfigCommand.js +268 -0
  53. package/dist/commands/ztdConfigCommand.js.map +1 -0
  54. package/dist/index.d.ts +4 -0
  55. package/dist/index.js +127 -0
  56. package/dist/index.js.map +1 -0
  57. package/dist/perf/benchmark.d.ts +277 -0
  58. package/dist/perf/benchmark.js +2186 -0
  59. package/dist/perf/benchmark.js.map +1 -0
  60. package/dist/perf/sandbox.d.ts +73 -0
  61. package/dist/perf/sandbox.js +492 -0
  62. package/dist/perf/sandbox.js.map +1 -0
  63. package/dist/query/analysis.d.ts +20 -0
  64. package/dist/query/analysis.js +192 -0
  65. package/dist/query/analysis.js.map +1 -0
  66. package/dist/query/analyzeColumnUsage.d.ts +10 -0
  67. package/dist/query/analyzeColumnUsage.js +451 -0
  68. package/dist/query/analyzeColumnUsage.js.map +1 -0
  69. package/dist/query/analyzeTableUsage.d.ts +10 -0
  70. package/dist/query/analyzeTableUsage.js +318 -0
  71. package/dist/query/analyzeTableUsage.js.map +1 -0
  72. package/dist/query/execute.d.ts +40 -0
  73. package/dist/query/execute.js +784 -0
  74. package/dist/query/execute.js.map +1 -0
  75. package/dist/query/format.d.ts +1 -0
  76. package/dist/query/format.js +9 -0
  77. package/dist/query/format.js.map +1 -0
  78. package/dist/query/lint.d.ts +29 -0
  79. package/dist/query/lint.js +340 -0
  80. package/dist/query/lint.js.map +1 -0
  81. package/dist/query/location.d.ts +18 -0
  82. package/dist/query/location.js +204 -0
  83. package/dist/query/location.js.map +1 -0
  84. package/dist/query/patch.d.ts +21 -0
  85. package/dist/query/patch.js +151 -0
  86. package/dist/query/patch.js.map +1 -0
  87. package/dist/query/planner.d.ts +31 -0
  88. package/dist/query/planner.js +134 -0
  89. package/dist/query/planner.js.map +1 -0
  90. package/dist/query/report.d.ts +7 -0
  91. package/dist/query/report.js +19 -0
  92. package/dist/query/report.js.map +1 -0
  93. package/dist/query/scalarFilterAnalysis.d.ts +6 -0
  94. package/dist/query/scalarFilterAnalysis.js +212 -0
  95. package/dist/query/scalarFilterAnalysis.js.map +1 -0
  96. package/dist/query/slice.d.ts +17 -0
  97. package/dist/query/slice.js +204 -0
  98. package/dist/query/slice.js.map +1 -0
  99. package/dist/query/structure.d.ts +24 -0
  100. package/dist/query/structure.js +135 -0
  101. package/dist/query/structure.js.map +1 -0
  102. package/dist/query/targets.d.ts +2 -0
  103. package/dist/query/targets.js +6 -0
  104. package/dist/query/targets.js.map +1 -0
  105. package/dist/query/types.d.ts +97 -0
  106. package/dist/query/types.js +3 -0
  107. package/dist/query/types.js.map +1 -0
  108. package/dist/specs/sql/activeOrders.catalog.d.ts +12 -0
  109. package/dist/specs/sql/activeOrders.catalog.js +36 -0
  110. package/dist/specs/sql/activeOrders.catalog.js.map +1 -0
  111. package/dist/specs/sql/usersList.catalog.d.ts +8 -0
  112. package/dist/specs/sql/usersList.catalog.js +14 -0
  113. package/dist/specs/sql/usersList.catalog.js.map +1 -0
  114. package/dist/specs/sqlCatalogDefinition.d.ts +20 -0
  115. package/dist/specs/sqlCatalogDefinition.js +10 -0
  116. package/dist/specs/sqlCatalogDefinition.js.map +1 -0
  117. package/dist/utils/agentCli.d.ts +23 -0
  118. package/dist/utils/agentCli.js +84 -0
  119. package/dist/utils/agentCli.js.map +1 -0
  120. package/dist/utils/agentSafety.d.ts +4 -0
  121. package/dist/utils/agentSafety.js +50 -0
  122. package/dist/utils/agentSafety.js.map +1 -0
  123. package/dist/utils/agents.d.ts +31 -0
  124. package/dist/utils/agents.js +362 -0
  125. package/dist/utils/agents.js.map +1 -0
  126. package/dist/utils/collectSqlFiles.d.ts +9 -0
  127. package/dist/utils/collectSqlFiles.js +58 -0
  128. package/dist/utils/collectSqlFiles.js.map +1 -0
  129. package/dist/utils/connectionSummary.d.ts +3 -0
  130. package/dist/utils/connectionSummary.js +29 -0
  131. package/dist/utils/connectionSummary.js.map +1 -0
  132. package/dist/utils/dbConnection.d.ts +31 -0
  133. package/dist/utils/dbConnection.js +151 -0
  134. package/dist/utils/dbConnection.js.map +1 -0
  135. package/dist/utils/fs.d.ts +1 -0
  136. package/dist/utils/fs.js +12 -0
  137. package/dist/utils/fs.js.map +1 -0
  138. package/dist/utils/modelGenBinder.d.ts +8 -0
  139. package/dist/utils/modelGenBinder.js +31 -0
  140. package/dist/utils/modelGenBinder.js.map +1 -0
  141. package/dist/utils/modelGenRender.d.ts +29 -0
  142. package/dist/utils/modelGenRender.js +158 -0
  143. package/dist/utils/modelGenRender.js.map +1 -0
  144. package/dist/utils/modelGenScanner.d.ts +24 -0
  145. package/dist/utils/modelGenScanner.js +196 -0
  146. package/dist/utils/modelGenScanner.js.map +1 -0
  147. package/dist/utils/modelProbe.d.ts +14 -0
  148. package/dist/utils/modelProbe.js +121 -0
  149. package/dist/utils/modelProbe.js.map +1 -0
  150. package/dist/utils/normalizePulledSchema.d.ts +12 -0
  151. package/dist/utils/normalizePulledSchema.js +213 -0
  152. package/dist/utils/normalizePulledSchema.js.map +1 -0
  153. package/dist/utils/optionalDependencies.d.ts +43 -0
  154. package/dist/utils/optionalDependencies.js +134 -0
  155. package/dist/utils/optionalDependencies.js.map +1 -0
  156. package/dist/utils/pgDump.d.ts +12 -0
  157. package/dist/utils/pgDump.js +58 -0
  158. package/dist/utils/pgDump.js.map +1 -0
  159. package/dist/utils/queryFingerprint.d.ts +14 -0
  160. package/dist/utils/queryFingerprint.js +34 -0
  161. package/dist/utils/queryFingerprint.js.map +1 -0
  162. package/dist/utils/sqlCatalogDiscovery.d.ts +44 -0
  163. package/dist/utils/sqlCatalogDiscovery.js +166 -0
  164. package/dist/utils/sqlCatalogDiscovery.js.map +1 -0
  165. package/dist/utils/sqlCatalogStatements.d.ts +20 -0
  166. package/dist/utils/sqlCatalogStatements.js +23 -0
  167. package/dist/utils/sqlCatalogStatements.js.map +1 -0
  168. package/dist/utils/sqlLintHelpers.d.ts +18 -0
  169. package/dist/utils/sqlLintHelpers.js +270 -0
  170. package/dist/utils/sqlLintHelpers.js.map +1 -0
  171. package/dist/utils/telemetry.d.ts +71 -0
  172. package/dist/utils/telemetry.js +597 -0
  173. package/dist/utils/telemetry.js.map +1 -0
  174. package/dist/utils/typeMapper.d.ts +4 -0
  175. package/dist/utils/typeMapper.js +79 -0
  176. package/dist/utils/typeMapper.js.map +1 -0
  177. package/dist/utils/ztdProjectConfig.d.ts +41 -0
  178. package/dist/utils/ztdProjectConfig.js +182 -0
  179. package/dist/utils/ztdProjectConfig.js.map +1 -0
  180. package/package.json +19 -20
  181. package/templates/README.md +1 -1
  182. package/templates/README.webapi.md +1 -1
  183. package/templates/src/catalog/runtime/_coercions.local-source.ts +0 -30
  184. package/templates/src/local/sql-contract.ts +0 -1
@@ -0,0 +1,784 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.executeQueryPipeline = executeQueryPipeline;
7
+ const node_fs_1 = require("node:fs");
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const rawsql_ts_1 = require("rawsql-ts");
10
+ const analysis_1 = require("./analysis");
11
+ const planner_1 = require("./planner");
12
+ const SUPPORTED_COMPARISON_OPERATORS = new Set(['=', '!=', '<>', '>', '>=', '<', '<=']);
13
+ /**
14
+ * Execute a decomposed query pipeline inside one DB session and reuse prior stage outputs.
15
+ */
16
+ async function executeQueryPipeline(sessionFactory, options) {
17
+ const source = preparePipelineSource(options.sqlFile);
18
+ const plan = (0, planner_1.buildQueryPipelinePlan)(options.sqlFile, options.metadata);
19
+ const session = await sessionFactory.openSession();
20
+ const materializedCtes = [];
21
+ const createdTempTables = [];
22
+ const steps = [];
23
+ let executionError;
24
+ try {
25
+ for (const step of plan.steps) {
26
+ if (step.kind === 'materialize') {
27
+ const stage = await buildPipelineStageQuery(source, session, {
28
+ cte: step.target,
29
+ runtimeParams: options.params,
30
+ materializedCtes,
31
+ scalarFilterColumns: plan.metadata.scalarFilterColumns
32
+ });
33
+ steps.push(...stage.scalarSteps);
34
+ const sql = `create temp table ${quoteIdentifier(step.target)} as ${stage.sql.trim()}`;
35
+ const stageParams = normalizeParamsForSql(sql, stage.params, options.params);
36
+ const result = normalizePipelineQueryResult(await session.query(sql, stageParams));
37
+ materializedCtes.push(step.target);
38
+ createdTempTables.push(step.target);
39
+ steps.push({
40
+ kind: step.kind,
41
+ target: step.target,
42
+ sql,
43
+ params: stageParams,
44
+ rowCount: result.rowCount
45
+ });
46
+ continue;
47
+ }
48
+ const finalStage = await buildPipelineStageQuery(source, session, {
49
+ final: true,
50
+ runtimeParams: options.params,
51
+ materializedCtes,
52
+ scalarFilterColumns: plan.metadata.scalarFilterColumns
53
+ });
54
+ steps.push(...finalStage.scalarSteps);
55
+ const finalParams = normalizeParamsForSql(finalStage.sql, finalStage.params, options.params);
56
+ const result = normalizePipelineQueryResult(await session.query(finalStage.sql, finalParams));
57
+ steps.push({
58
+ kind: step.kind,
59
+ target: step.target,
60
+ sql: finalStage.sql,
61
+ params: finalParams,
62
+ rowCount: result.rowCount
63
+ });
64
+ return {
65
+ plan,
66
+ final: {
67
+ rows: result.rows,
68
+ rowCount: result.rowCount,
69
+ sql: finalStage.sql,
70
+ params: finalParams
71
+ },
72
+ steps
73
+ };
74
+ }
75
+ throw new Error('Query pipeline plan did not include a final-query step.');
76
+ }
77
+ catch (error) {
78
+ executionError = error;
79
+ throw error;
80
+ }
81
+ finally {
82
+ await cleanupPipelineSession(session, createdTempTables, executionError);
83
+ }
84
+ }
85
+ async function buildPipelineStageQuery(source, session, options) {
86
+ validateStageOptions(options);
87
+ return options.cte
88
+ ? buildTargetStageQuery(source, session, options)
89
+ : buildFinalStageQuery(source, session, options);
90
+ }
91
+ async function buildTargetStageQuery(source, session, options) {
92
+ var _a, _b, _c, _d;
93
+ const parsed = (0, analysis_1.assertSupportedStatement)(rawsql_ts_1.SqlParser.parse(source.sql), 'executeQueryPipeline');
94
+ const analysis = (0, analysis_1.analyzeStatement)(parsed);
95
+ const targetName = options.cte;
96
+ const materializedStopSet = new Set(options.materializedCtes.filter((name) => name !== targetName));
97
+ const includedNames = (0, analysis_1.collectDependencyClosure)(targetName, analysis.dependencyMap, materializedStopSet);
98
+ if (!includedNames.includes(targetName)) {
99
+ throw new Error(`CTE not found in query: ${targetName}`);
100
+ }
101
+ const includedCtes = buildStageCtes(analysis.ctes, includedNames, targetName, options.materializedCtes);
102
+ const targetCte = includedCtes.find((cte) => cte.aliasExpression.table.name === targetName);
103
+ if (!targetCte) {
104
+ throw new Error(`CTE not found in query: ${targetName}`);
105
+ }
106
+ const dependencyCtes = includedCtes.filter((cte) => cte.aliasExpression.table.name !== targetName);
107
+ const bindingContext = createScalarBindingContext(options, includedNames, source.sql, (_b = (_a = getWithClause(parsed)) === null || _a === void 0 ? void 0 : _a.recursive) !== null && _b !== void 0 ? _b : false);
108
+ const scalarSteps = await bindScalarFilterPredicatesInCtes(includedCtes, bindingContext, session);
109
+ const formatter = createPipelineFormatter(options.runtimeParams);
110
+ const targetQuery = assertSelectQuery(targetCte.query);
111
+ const withComponent = dependencyCtes.length > 0 ? new rawsql_ts_1.WithClause((_d = (_c = getWithClause(parsed)) === null || _c === void 0 ? void 0 : _c.recursive) !== null && _d !== void 0 ? _d : false, dependencyCtes) : null;
112
+ const withResult = withComponent
113
+ ? formatter.format(withComponent)
114
+ : { formattedSql: '', params: emptyFormatterParams(options.runtimeParams) };
115
+ let mainResult;
116
+ if (options.limit !== undefined) {
117
+ if (targetQuery instanceof rawsql_ts_1.SimpleSelectQuery) {
118
+ targetQuery.limitClause = new rawsql_ts_1.LimitClause(new rawsql_ts_1.LiteralValue(options.limit));
119
+ mainResult = formatter.format(targetQuery);
120
+ }
121
+ else {
122
+ mainResult = formatter.format(buildWrappedLimitQuery(targetQuery, options.limit));
123
+ }
124
+ }
125
+ else {
126
+ mainResult = formatter.format(targetQuery);
127
+ }
128
+ const mergedParams = mergeFormatterParams([withResult.params, mainResult.params], options.runtimeParams);
129
+ const sql = withResult.formattedSql ? `${withResult.formattedSql} ${mainResult.formattedSql}` : mainResult.formattedSql;
130
+ return {
131
+ sql: `${sql}\n`,
132
+ params: normalizeParamsForSql(sql, mergedParams, options.runtimeParams),
133
+ scalarSteps
134
+ };
135
+ }
136
+ async function buildFinalStageQuery(source, session, options) {
137
+ var _a, _b, _c, _d;
138
+ const parsed = (0, analysis_1.assertSupportedStatement)(rawsql_ts_1.SqlParser.parse(source.sql), 'executeQueryPipeline');
139
+ const analysis = (0, analysis_1.analyzeStatement)(parsed);
140
+ const stopSet = new Set(options.materializedCtes);
141
+ const includedNames = [...(0, analysis_1.collectReachableCtes)(analysis.rootDependencies, analysis.dependencyMap, stopSet)];
142
+ const includedCtes = buildStageCtes(analysis.ctes, includedNames, null, options.materializedCtes);
143
+ const bindingContext = createScalarBindingContext(options, includedNames, source.sql, (_b = (_a = getWithClause(parsed)) === null || _a === void 0 ? void 0 : _a.recursive) !== null && _b !== void 0 ? _b : false);
144
+ applyMinimalWithClause(parsed, includedCtes, (_d = (_c = getWithClause(parsed)) === null || _c === void 0 ? void 0 : _c.recursive) !== null && _d !== void 0 ? _d : false);
145
+ const scalarSteps = [
146
+ ...(await bindScalarFilterPredicatesInCtes(includedCtes, bindingContext, session)),
147
+ ...(await bindScalarFilterPredicates(parsed, bindingContext, session))
148
+ ];
149
+ const formatter = createPipelineFormatter(options.runtimeParams);
150
+ if (options.limit !== undefined) {
151
+ if (parsed instanceof rawsql_ts_1.SimpleSelectQuery) {
152
+ parsed.limitClause = new rawsql_ts_1.LimitClause(new rawsql_ts_1.LiteralValue(options.limit));
153
+ }
154
+ else if (parsed instanceof rawsql_ts_1.ValuesQuery || parsed instanceof rawsql_ts_1.BinarySelectQuery) {
155
+ const wrapped = buildWrappedLimitQuery(parsed, options.limit);
156
+ const { formattedSql, params } = formatter.format(wrapped);
157
+ return {
158
+ sql: `${formattedSql}\n`,
159
+ params: normalizeParamsForSql(formattedSql, mergeFormatterParams(params, options.runtimeParams), options.runtimeParams),
160
+ scalarSteps
161
+ };
162
+ }
163
+ else {
164
+ throw new Error('--limit is only supported for SELECT final slices or --cte slices.');
165
+ }
166
+ }
167
+ const { formattedSql, params } = formatter.format(parsed);
168
+ return {
169
+ sql: `${formattedSql}\n`,
170
+ params: normalizeParamsForSql(formattedSql, mergeFormatterParams(params, options.runtimeParams), options.runtimeParams),
171
+ scalarSteps
172
+ };
173
+ }
174
+ function createScalarBindingContext(options, includedNames, sourceSql, recursive) {
175
+ return {
176
+ runtimeParams: options.runtimeParams,
177
+ scalarFilterColumns: new Set(options.scalarFilterColumns),
178
+ materializedCtes: new Set(options.materializedCtes),
179
+ sourceSql,
180
+ recursive,
181
+ nextOrdinal: 1
182
+ };
183
+ }
184
+ function buildStageCtes(ctes, includedNames, currentTarget, materializedCtes) {
185
+ const includedSet = new Set(includedNames);
186
+ const materializedSet = new Set(materializedCtes);
187
+ return ctes.filter((cte) => {
188
+ const name = cte.aliasExpression.table.name;
189
+ if (!includedSet.has(name)) {
190
+ return false;
191
+ }
192
+ return name === currentTarget || !materializedSet.has(name);
193
+ });
194
+ }
195
+ async function bindScalarFilterPredicatesInCtes(ctes, context, session) {
196
+ const steps = [];
197
+ for (const cte of ctes) {
198
+ steps.push(...await bindScalarFilterPredicates(assertSelectQuery(cte.query), context, session));
199
+ }
200
+ return steps;
201
+ }
202
+ async function bindScalarFilterPredicates(statement, context, session) {
203
+ if (context.scalarFilterColumns.size === 0) {
204
+ return [];
205
+ }
206
+ if (statement instanceof rawsql_ts_1.SimpleSelectQuery) {
207
+ return bindScalarFilterPredicatesInSelect(statement, context, session);
208
+ }
209
+ if (statement instanceof rawsql_ts_1.BinarySelectQuery) {
210
+ const steps = [];
211
+ steps.push(...await bindScalarFilterPredicatesInSelectBranch(assertSelectQuery(statement.left), context, session));
212
+ steps.push(...await bindScalarFilterPredicatesInSelectBranch(assertSelectQuery(statement.right), context, session));
213
+ return steps;
214
+ }
215
+ if (statement instanceof rawsql_ts_1.ValuesQuery) {
216
+ return [];
217
+ }
218
+ if (statement instanceof rawsql_ts_1.InsertQuery) {
219
+ return statement.selectQuery
220
+ ? bindScalarFilterPredicatesInSelectBranch(assertSelectQuery(statement.selectQuery), context, session)
221
+ : [];
222
+ }
223
+ if (statement instanceof rawsql_ts_1.UpdateQuery || statement instanceof rawsql_ts_1.DeleteQuery) {
224
+ return [];
225
+ }
226
+ return [];
227
+ }
228
+ async function bindScalarFilterPredicatesInSelectBranch(statement, context, session) {
229
+ if (statement instanceof rawsql_ts_1.SimpleSelectQuery) {
230
+ return bindScalarFilterPredicatesInSelect(statement, context, session);
231
+ }
232
+ if (statement instanceof rawsql_ts_1.BinarySelectQuery) {
233
+ const steps = [];
234
+ steps.push(...await bindScalarFilterPredicatesInSelectBranch(assertSelectQuery(statement.left), context, session));
235
+ steps.push(...await bindScalarFilterPredicatesInSelectBranch(assertSelectQuery(statement.right), context, session));
236
+ return steps;
237
+ }
238
+ return [];
239
+ }
240
+ async function bindScalarFilterPredicatesInSelect(selectQuery, context, session) {
241
+ if (!selectQuery.whereClause) {
242
+ return [];
243
+ }
244
+ return rewritePredicateExpression(selectQuery.whereClause.condition, context, session);
245
+ }
246
+ async function rewritePredicateExpression(expression, context, session) {
247
+ if (!(expression instanceof rawsql_ts_1.BinaryExpression)) {
248
+ return [];
249
+ }
250
+ const binaryExpression = expression;
251
+ const candidate = findScalarBindingCandidate(binaryExpression, context.scalarFilterColumns);
252
+ if (candidate) {
253
+ const execution = await executeScalarFilterBinding(candidate, context, session);
254
+ if (execution) {
255
+ candidate.replace(new rawsql_ts_1.ParameterExpression(execution.paramName, execution.value));
256
+ return [execution.step];
257
+ }
258
+ }
259
+ const steps = [];
260
+ steps.push(...await rewritePredicateExpression(binaryExpression.left, context, session));
261
+ steps.push(...await rewritePredicateExpression(binaryExpression.right, context, session));
262
+ return steps;
263
+ }
264
+ function findScalarBindingCandidate(expression, scalarFilterColumns) {
265
+ const operator = extractOperator(expression.operator);
266
+ if (!SUPPORTED_COMPARISON_OPERATORS.has(operator)) {
267
+ return null;
268
+ }
269
+ const leftMatches = containsTargetColumn(expression.left, scalarFilterColumns);
270
+ const rightMatches = containsTargetColumn(expression.right, scalarFilterColumns);
271
+ const leftInline = unwrapInlineQuery(expression.left);
272
+ const rightInline = unwrapInlineQuery(expression.right);
273
+ if (leftMatches && rightInline) {
274
+ return {
275
+ columnName: leftMatches,
276
+ inlineQuery: rightInline,
277
+ replace: (parameter) => {
278
+ expression.right = parameter;
279
+ }
280
+ };
281
+ }
282
+ if (rightMatches && leftInline) {
283
+ return {
284
+ columnName: rightMatches,
285
+ inlineQuery: leftInline,
286
+ replace: (parameter) => {
287
+ expression.left = parameter;
288
+ }
289
+ };
290
+ }
291
+ return null;
292
+ }
293
+ async function executeScalarFilterBinding(candidate, context, session) {
294
+ const selectQuery = candidate.inlineQuery.selectQuery;
295
+ if (!(selectQuery instanceof rawsql_ts_1.SimpleSelectQuery)) {
296
+ throw new Error(`Scalar filter binding for column "${candidate.columnName}" requires a simple SELECT subquery.`);
297
+ }
298
+ if (isCorrelatedScalarSubquery(selectQuery)) {
299
+ return null;
300
+ }
301
+ assertSingleColumnScalarSelect(selectQuery, candidate.columnName);
302
+ const paramName = `__scalar_filter_${candidate.columnName}_${context.nextOrdinal}`;
303
+ const { sql, params: queryParams } = buildScalarBindingQuery(selectQuery, context);
304
+ const scalarParams = normalizeParamsForSql(sql, queryParams, context.runtimeParams);
305
+ const result = normalizePipelineQueryResult(await session.query(sql, scalarParams));
306
+ const value = extractScalarFilterValue(result.rows, candidate.columnName);
307
+ const step = {
308
+ kind: 'scalar-filter-bind',
309
+ target: candidate.columnName,
310
+ sql,
311
+ params: scalarParams,
312
+ rowCount: result.rowCount
313
+ };
314
+ context.nextOrdinal += 1;
315
+ return { paramName, value, step };
316
+ }
317
+ function buildScalarBindingQuery(selectQuery, context) {
318
+ const sourceStatement = (0, analysis_1.assertSupportedStatement)(rawsql_ts_1.SqlParser.parse(context.sourceSql), 'executeQueryPipeline');
319
+ const sourceAnalysis = (0, analysis_1.analyzeStatement)(sourceStatement);
320
+ const scalarRoots = collectScalarQueryCteRoots(selectQuery, sourceAnalysis.ctes, context.materializedCtes);
321
+ const dependencyNames = scalarRoots.length > 0
322
+ ? [...(0, analysis_1.collectReachableCtes)(scalarRoots, sourceAnalysis.dependencyMap, context.materializedCtes)]
323
+ : [];
324
+ const scalarCtes = buildStageCtes(sourceAnalysis.ctes, dependencyNames, null, [...context.materializedCtes]);
325
+ const formatter = createPipelineFormatter(context.runtimeParams);
326
+ const withComponent = scalarCtes.length > 0 ? new rawsql_ts_1.WithClause(context.recursive, scalarCtes) : null;
327
+ const withResult = withComponent
328
+ ? formatter.format(withComponent)
329
+ : { formattedSql: '', params: emptyFormatterParams(context.runtimeParams) };
330
+ const mainResult = formatter.format(selectQuery);
331
+ const mergedParams = mergeFormatterParams([withResult.params, mainResult.params], context.runtimeParams);
332
+ const sql = withResult.formattedSql ? `${withResult.formattedSql} ${mainResult.formattedSql}` : mainResult.formattedSql;
333
+ return {
334
+ sql: `${sql}
335
+ `,
336
+ params: normalizeParamsForSql(sql, mergedParams, context.runtimeParams)
337
+ };
338
+ }
339
+ function collectScalarQueryCteRoots(selectQuery, ctes, materializedCtes) {
340
+ const cteNames = new Set(ctes.map((cte) => cte.aliasExpression.table.name));
341
+ const roots = new Set();
342
+ walkAst(selectQuery, (current) => {
343
+ if (!(current instanceof rawsql_ts_1.TableSource)) {
344
+ return;
345
+ }
346
+ const sourceName = extractQualifiedNameLeaf(current.qualifiedName.name);
347
+ if (cteNames.has(sourceName) && !materializedCtes.has(sourceName)) {
348
+ roots.add(sourceName);
349
+ }
350
+ });
351
+ return [...roots];
352
+ }
353
+ function assertSingleColumnScalarSelect(selectQuery, columnName) {
354
+ if (selectQuery.selectClause.items.length !== 1) {
355
+ throw new Error(`Scalar filter binding for column "${columnName}" requires a subquery that statically exposes exactly one column.`);
356
+ }
357
+ const [item] = selectQuery.selectClause.items;
358
+ if ((item === null || item === void 0 ? void 0 : item.value) instanceof rawsql_ts_1.RawString && item.value.value.trim() === '*') {
359
+ throw new Error(`Scalar filter binding for column "${columnName}" requires a subquery that statically exposes exactly one column.`);
360
+ }
361
+ }
362
+ function extractScalarFilterValue(rows, columnName) {
363
+ var _a;
364
+ if (rows.length !== 1) {
365
+ throw new Error(`Scalar filter binding for column "${columnName}" must return exactly one row.`);
366
+ }
367
+ const row = (_a = rows[0]) !== null && _a !== void 0 ? _a : {};
368
+ const columns = Object.keys(row);
369
+ if (columns.length !== 1) {
370
+ throw new Error(`Scalar filter binding for column "${columnName}" must return exactly one column.`);
371
+ }
372
+ return row[columns[0]];
373
+ }
374
+ function isCorrelatedScalarSubquery(selectQuery) {
375
+ const localNames = collectLocalRelationNames(selectQuery);
376
+ const columnReferences = collectColumnReferences(selectQuery);
377
+ return columnReferences.some((reference) => {
378
+ var _a, _b;
379
+ const qualifierParts = (_b = (_a = reference.qualifiedName.namespaces) === null || _a === void 0 ? void 0 : _a.map((namespace) => namespace.name)) !== null && _b !== void 0 ? _b : [];
380
+ if (qualifierParts.length === 0) {
381
+ return false;
382
+ }
383
+ const qualifier = qualifierParts[qualifierParts.length - 1];
384
+ return !localNames.has(qualifier);
385
+ });
386
+ }
387
+ function collectLocalRelationNames(selectQuery) {
388
+ var _a, _b, _c, _d;
389
+ const localNames = new Set();
390
+ const sources = (_b = (_a = selectQuery.fromClause) === null || _a === void 0 ? void 0 : _a.getSources()) !== null && _b !== void 0 ? _b : [];
391
+ for (const source of sources) {
392
+ const aliasName = (_d = (_c = source.aliasExpression) === null || _c === void 0 ? void 0 : _c.table) === null || _d === void 0 ? void 0 : _d.name;
393
+ if (aliasName) {
394
+ localNames.add(aliasName);
395
+ }
396
+ if (source.datasource instanceof rawsql_ts_1.TableSource) {
397
+ localNames.add(extractQualifiedNameLeaf(source.datasource.qualifiedName.name));
398
+ }
399
+ }
400
+ return localNames;
401
+ }
402
+ function collectColumnReferences(node) {
403
+ const matches = [];
404
+ walkAst(node, (current) => {
405
+ if (current instanceof rawsql_ts_1.ColumnReference) {
406
+ matches.push(current);
407
+ }
408
+ });
409
+ return matches;
410
+ }
411
+ function containsTargetColumn(node, scalarFilterColumns) {
412
+ let matched = null;
413
+ walkAst(node, (current) => {
414
+ if (matched || !(current instanceof rawsql_ts_1.ColumnReference)) {
415
+ return;
416
+ }
417
+ const columnName = extractQualifiedNameLeaf(current.qualifiedName.name);
418
+ if (scalarFilterColumns.has(columnName)) {
419
+ matched = columnName;
420
+ }
421
+ });
422
+ return matched;
423
+ }
424
+ function walkAst(node, visit) {
425
+ if (!node || typeof node !== 'object') {
426
+ return;
427
+ }
428
+ visit(node);
429
+ for (const value of Object.values(node)) {
430
+ if (!value) {
431
+ continue;
432
+ }
433
+ if (Array.isArray(value)) {
434
+ for (const item of value) {
435
+ walkAst(item, visit);
436
+ }
437
+ continue;
438
+ }
439
+ if (typeof value === 'object') {
440
+ walkAst(value, visit);
441
+ }
442
+ }
443
+ }
444
+ function unwrapInlineQuery(expression) {
445
+ if (expression instanceof rawsql_ts_1.InlineQuery) {
446
+ return expression;
447
+ }
448
+ if (expression instanceof rawsql_ts_1.ParenExpression) {
449
+ return unwrapInlineQuery(expression.expression);
450
+ }
451
+ return null;
452
+ }
453
+ function extractOperator(operator) {
454
+ if (operator instanceof rawsql_ts_1.RawString) {
455
+ return operator.value.trim();
456
+ }
457
+ return '';
458
+ }
459
+ function extractQualifiedNameLeaf(name) {
460
+ return name instanceof rawsql_ts_1.RawString ? name.value : name.name;
461
+ }
462
+ function preparePipelineSource(sqlFile) {
463
+ const sql = (0, node_fs_1.readFileSync)(node_path_1.default.resolve(sqlFile), 'utf8');
464
+ return {
465
+ sql
466
+ };
467
+ }
468
+ function createPipelineFormatter(runtimeParams) {
469
+ if (runtimeParams && !Array.isArray(runtimeParams)) {
470
+ return new rawsql_ts_1.SqlFormatter({
471
+ identifierEscape: { start: '"', end: '"' },
472
+ parameterStyle: 'named',
473
+ parameterSymbol: ':'
474
+ });
475
+ }
476
+ return new rawsql_ts_1.SqlFormatter({ preset: 'postgres' });
477
+ }
478
+ function emptyFormatterParams(runtimeParams) {
479
+ return Array.isArray(runtimeParams) ? [] : {};
480
+ }
481
+ function mergeFormatterParams(formatterParams, runtimeParams) {
482
+ const parts = Array.isArray(formatterParams) && formatterParams.some((part) => Array.isArray(part) || isPlainObject(part))
483
+ ? formatterParams
484
+ : [formatterParams];
485
+ if ((runtimeParams && !Array.isArray(runtimeParams)) || parts.some((part) => isPlainObject(part))) {
486
+ const merged = isPlainObject(runtimeParams) ? { ...runtimeParams } : {};
487
+ // Preserve original runtime params while layering formatter-generated named values on top.
488
+ for (const part of parts) {
489
+ if (!isPlainObject(part)) {
490
+ continue;
491
+ }
492
+ for (const [key, value] of Object.entries(part)) {
493
+ if (value === undefined || (value === null && key in merged)) {
494
+ continue;
495
+ }
496
+ merged[key] = value;
497
+ }
498
+ }
499
+ return Object.keys(merged).length > 0 ? merged : undefined;
500
+ }
501
+ const merged = Array.isArray(runtimeParams) ? [...runtimeParams] : [];
502
+ for (const part of parts) {
503
+ if (!Array.isArray(part)) {
504
+ continue;
505
+ }
506
+ // Formatter arrays reuse positional indexes, so keep runtime slots in place and only fill missing/generated entries.
507
+ part.forEach((value, index) => {
508
+ if ((value === undefined || value === null) && index < merged.length) {
509
+ return;
510
+ }
511
+ merged[index] = value;
512
+ });
513
+ }
514
+ return merged.length > 0 ? merged : undefined;
515
+ }
516
+ function isPlainObject(value) {
517
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
518
+ }
519
+ function normalizeParamsForSql(sql, params, runtimeParams) {
520
+ if (!Array.isArray(params)) {
521
+ return params;
522
+ }
523
+ const maxSlot = findHighestPositionalPlaceholder(sql);
524
+ if (maxSlot === 0) {
525
+ return undefined;
526
+ }
527
+ const finalized = params.slice(0, maxSlot).map((value, index) => {
528
+ if ((value === undefined || value === null) && Array.isArray(runtimeParams) && index < runtimeParams.length) {
529
+ return runtimeParams[index];
530
+ }
531
+ return value;
532
+ });
533
+ return finalized;
534
+ }
535
+ function findHighestPositionalPlaceholder(sql) {
536
+ let highest = 0;
537
+ let index = 0;
538
+ let dollarQuoteTag = null;
539
+ while (index < sql.length) {
540
+ const current = sql[index];
541
+ const next = sql[index + 1];
542
+ if (dollarQuoteTag) {
543
+ if (sql.startsWith(dollarQuoteTag, index)) {
544
+ index += dollarQuoteTag.length;
545
+ dollarQuoteTag = null;
546
+ continue;
547
+ }
548
+ index += 1;
549
+ continue;
550
+ }
551
+ if (current === "'") {
552
+ index = skipQuotedString(sql, index, "'");
553
+ continue;
554
+ }
555
+ if (current === '"') {
556
+ index = skipQuotedString(sql, index, '"');
557
+ continue;
558
+ }
559
+ if (current === '-' && next === '-') {
560
+ index = skipLineComment(sql, index + 2);
561
+ continue;
562
+ }
563
+ if (current === '/' && next === '*') {
564
+ index = skipBlockComment(sql, index + 2);
565
+ continue;
566
+ }
567
+ const dollarTag = readDollarQuoteTag(sql, index);
568
+ if (dollarTag) {
569
+ dollarQuoteTag = dollarTag;
570
+ index += dollarTag.length;
571
+ continue;
572
+ }
573
+ if (current === '$' && isAsciiDigit(next)) {
574
+ let end = index + 1;
575
+ while (end < sql.length && isAsciiDigit(sql[end])) {
576
+ end += 1;
577
+ }
578
+ highest = Math.max(highest, Number(sql.slice(index + 1, end)));
579
+ index = end;
580
+ continue;
581
+ }
582
+ index += 1;
583
+ }
584
+ return highest;
585
+ }
586
+ function skipQuotedString(sql, start, quote) {
587
+ let index = start + 1;
588
+ while (index < sql.length) {
589
+ if (sql[index] === quote) {
590
+ if (sql[index + 1] === quote) {
591
+ index += 2;
592
+ continue;
593
+ }
594
+ return index + 1;
595
+ }
596
+ index += 1;
597
+ }
598
+ return index;
599
+ }
600
+ function skipLineComment(sql, start) {
601
+ let index = start;
602
+ while (index < sql.length && sql[index] !== '\n') {
603
+ index += 1;
604
+ }
605
+ return index;
606
+ }
607
+ function skipBlockComment(sql, start) {
608
+ let index = start;
609
+ while (index < sql.length - 1) {
610
+ if (sql[index] === '*' && sql[index + 1] === '/') {
611
+ return index + 2;
612
+ }
613
+ index += 1;
614
+ }
615
+ return sql.length;
616
+ }
617
+ function readDollarQuoteTag(sql, start) {
618
+ if (sql[start] !== '$') {
619
+ return null;
620
+ }
621
+ let index = start + 1;
622
+ while (index < sql.length && sql[index] !== '$') {
623
+ const current = sql[index];
624
+ if (!isDollarQuoteTagChar(current)) {
625
+ return null;
626
+ }
627
+ index += 1;
628
+ }
629
+ if (sql[index] !== '$') {
630
+ return null;
631
+ }
632
+ return sql.slice(start, index + 1);
633
+ }
634
+ function isDollarQuoteTagChar(char) {
635
+ return char !== undefined && /[A-Za-z0-9_]/.test(char);
636
+ }
637
+ function isAsciiDigit(value) {
638
+ return value !== undefined && value >= '0' && value <= '9';
639
+ }
640
+ function normalizePipelineQueryResult(result) {
641
+ if (Array.isArray(result)) {
642
+ return { rows: result };
643
+ }
644
+ return {
645
+ rows: result.rows,
646
+ rowCount: result.rowCount
647
+ };
648
+ }
649
+ async function cleanupPipelineSession(session, createdTempTables, executionError) {
650
+ let cleanupError;
651
+ // Keep dropping later tables even if one cleanup statement fails.
652
+ for (const tableName of [...createdTempTables].reverse()) {
653
+ try {
654
+ await session.query(`drop table if exists ${quoteIdentifier(tableName)}`);
655
+ }
656
+ catch (error) {
657
+ if (!cleanupError) {
658
+ cleanupError = error;
659
+ }
660
+ }
661
+ }
662
+ try {
663
+ await closePipelineSession(session);
664
+ }
665
+ catch (error) {
666
+ if (!executionError && !cleanupError) {
667
+ throw error;
668
+ }
669
+ }
670
+ if (!executionError && cleanupError) {
671
+ throw cleanupError;
672
+ }
673
+ }
674
+ async function closePipelineSession(session) {
675
+ if (typeof session.release === 'function') {
676
+ await session.release();
677
+ return;
678
+ }
679
+ if (typeof session.end === 'function') {
680
+ await session.end();
681
+ }
682
+ }
683
+ function quoteIdentifier(name) {
684
+ return `"${name.replace(/"/g, '""')}"`;
685
+ }
686
+ function validateStageOptions(options) {
687
+ const hasTarget = typeof options.cte === 'string' && options.cte.trim() !== '';
688
+ const hasFinal = options.final === true;
689
+ if (hasTarget === hasFinal) {
690
+ throw new Error('Specify exactly one stage target or final query mode.');
691
+ }
692
+ }
693
+ function buildSelectFromTargetQuery(targetName, limit) {
694
+ return new rawsql_ts_1.SimpleSelectQuery({
695
+ selectClause: new rawsql_ts_1.SelectClause([new rawsql_ts_1.SelectItem(new rawsql_ts_1.RawString('*'))]),
696
+ fromClause: new rawsql_ts_1.FromClause(new rawsql_ts_1.SourceExpression(new rawsql_ts_1.TableSource(null, targetName), null), null),
697
+ limitClause: limit === undefined ? null : new rawsql_ts_1.LimitClause(new rawsql_ts_1.LiteralValue(limit))
698
+ });
699
+ }
700
+ function buildWrappedLimitQuery(statement, limit) {
701
+ return new rawsql_ts_1.SimpleSelectQuery({
702
+ selectClause: new rawsql_ts_1.SelectClause([new rawsql_ts_1.SelectItem(new rawsql_ts_1.RawString('*'))]),
703
+ fromClause: new rawsql_ts_1.FromClause(new rawsql_ts_1.SourceExpression(new rawsql_ts_1.SubQuerySource(statement), new rawsql_ts_1.SourceAliasExpression('final_slice', null)), null),
704
+ limitClause: new rawsql_ts_1.LimitClause(new rawsql_ts_1.LiteralValue(limit))
705
+ });
706
+ }
707
+ function applyMinimalWithClause(statement, ctes, recursive) {
708
+ const nextWithClause = ctes.length > 0 ? new rawsql_ts_1.WithClause(recursive, ctes) : null;
709
+ if (statement instanceof rawsql_ts_1.SimpleSelectQuery ||
710
+ statement instanceof rawsql_ts_1.ValuesQuery ||
711
+ statement instanceof rawsql_ts_1.UpdateQuery ||
712
+ statement instanceof rawsql_ts_1.DeleteQuery) {
713
+ statement.withClause = nextWithClause;
714
+ return;
715
+ }
716
+ if (statement instanceof rawsql_ts_1.InsertQuery) {
717
+ if (!statement.selectQuery) {
718
+ return;
719
+ }
720
+ // INSERT ... SELECT stores the CTEs on the nested selectQuery, not on InsertQuery itself.
721
+ applyMinimalWithClauseToSelect(assertSelectQuery(statement.selectQuery), nextWithClause);
722
+ return;
723
+ }
724
+ applyMinimalWithClauseToSelect(statement, nextWithClause);
725
+ }
726
+ function applyMinimalWithClauseToSelect(statement, withClause) {
727
+ if (statement instanceof rawsql_ts_1.SimpleSelectQuery || statement instanceof rawsql_ts_1.ValuesQuery) {
728
+ statement.withClause = withClause;
729
+ return;
730
+ }
731
+ let current = statement;
732
+ while (current instanceof rawsql_ts_1.BinarySelectQuery) {
733
+ if (current.left instanceof rawsql_ts_1.BinarySelectQuery) {
734
+ current = current.left;
735
+ continue;
736
+ }
737
+ if (current.left instanceof rawsql_ts_1.SimpleSelectQuery || current.left instanceof rawsql_ts_1.ValuesQuery) {
738
+ current.left.withClause = withClause;
739
+ return;
740
+ }
741
+ break;
742
+ }
743
+ throw new Error('Unable to apply rewritten WITH clause to the final query.');
744
+ }
745
+ function getWithClause(statement) {
746
+ var _a;
747
+ if (statement instanceof rawsql_ts_1.SimpleSelectQuery ||
748
+ statement instanceof rawsql_ts_1.ValuesQuery ||
749
+ statement instanceof rawsql_ts_1.UpdateQuery ||
750
+ statement instanceof rawsql_ts_1.DeleteQuery) {
751
+ return (_a = statement.withClause) !== null && _a !== void 0 ? _a : null;
752
+ }
753
+ if (statement instanceof rawsql_ts_1.InsertQuery) {
754
+ return statement.selectQuery ? getSelectWithClause(assertSelectQuery(statement.selectQuery)) : null;
755
+ }
756
+ return getSelectWithClause(statement);
757
+ }
758
+ function assertSelectQuery(statement) {
759
+ if (statement instanceof rawsql_ts_1.SimpleSelectQuery ||
760
+ statement instanceof rawsql_ts_1.BinarySelectQuery ||
761
+ statement instanceof rawsql_ts_1.ValuesQuery) {
762
+ return statement;
763
+ }
764
+ throw new Error('Expected a SELECT-compatible statement for query execution.');
765
+ }
766
+ function getSelectWithClause(statement) {
767
+ var _a, _b;
768
+ if (statement instanceof rawsql_ts_1.SimpleSelectQuery || statement instanceof rawsql_ts_1.ValuesQuery) {
769
+ return (_a = statement.withClause) !== null && _a !== void 0 ? _a : null;
770
+ }
771
+ let current = statement;
772
+ while (current instanceof rawsql_ts_1.BinarySelectQuery) {
773
+ if (current.left instanceof rawsql_ts_1.BinarySelectQuery) {
774
+ current = current.left;
775
+ continue;
776
+ }
777
+ if (current.left instanceof rawsql_ts_1.SimpleSelectQuery || current.left instanceof rawsql_ts_1.ValuesQuery) {
778
+ return (_b = current.left.withClause) !== null && _b !== void 0 ? _b : null;
779
+ }
780
+ break;
781
+ }
782
+ return null;
783
+ }
784
+ //# sourceMappingURL=execute.js.map