rawsql-ts 0.10.1-beta → 0.10.3-beta

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 (79) hide show
  1. package/dist/esm/index.min.js +16 -0
  2. package/dist/esm/index.min.js.map +7 -0
  3. package/dist/esm/models/ValueComponent.js +7 -0
  4. package/dist/esm/models/ValueComponent.js.map +1 -1
  5. package/dist/esm/parsers/CommandExpressionParser.js +1 -16
  6. package/dist/esm/parsers/CommandExpressionParser.js.map +1 -1
  7. package/dist/esm/parsers/FunctionExpressionParser.js +51 -6
  8. package/dist/esm/parsers/FunctionExpressionParser.js.map +1 -1
  9. package/dist/esm/parsers/SqlPrintTokenParser.js +11 -1
  10. package/dist/esm/parsers/SqlPrintTokenParser.js.map +1 -1
  11. package/dist/esm/parsers/ValueParser.js +56 -11
  12. package/dist/esm/parsers/ValueParser.js.map +1 -1
  13. package/dist/esm/tokenReaders/CommandTokenReader.js +0 -1
  14. package/dist/esm/tokenReaders/CommandTokenReader.js.map +1 -1
  15. package/dist/esm/tokenReaders/FunctionTokenReader.js +2 -0
  16. package/dist/esm/tokenReaders/FunctionTokenReader.js.map +1 -1
  17. package/dist/esm/transformers/CTECollector.js +18 -2
  18. package/dist/esm/transformers/CTECollector.js.map +1 -1
  19. package/dist/esm/transformers/CTEDisabler.js +6 -1
  20. package/dist/esm/transformers/CTEDisabler.js.map +1 -1
  21. package/dist/esm/transformers/SelectableColumnCollector.js +5 -1
  22. package/dist/esm/transformers/SelectableColumnCollector.js.map +1 -1
  23. package/dist/esm/transformers/TableSourceCollector.js +37 -2
  24. package/dist/esm/transformers/TableSourceCollector.js.map +1 -1
  25. package/dist/esm/types/models/ValueComponent.d.ts +6 -1
  26. package/dist/esm/types/parsers/CommandExpressionParser.d.ts +0 -1
  27. package/dist/esm/types/parsers/FunctionExpressionParser.d.ts +13 -1
  28. package/dist/esm/types/parsers/SqlPrintTokenParser.d.ts +1 -0
  29. package/dist/esm/types/parsers/ValueParser.d.ts +9 -1
  30. package/dist/esm/types/transformers/CTECollector.d.ts +3 -0
  31. package/dist/esm/types/transformers/CTEDisabler.d.ts +2 -1
  32. package/dist/esm/types/transformers/SelectableColumnCollector.d.ts +1 -0
  33. package/dist/esm/types/transformers/TableSourceCollector.d.ts +9 -0
  34. package/dist/esm/types/utils/OperatorPrecedence.d.ts +29 -0
  35. package/dist/esm/types/utils/ParameterRemover.d.ts +225 -0
  36. package/dist/esm/utils/OperatorPrecedence.js +79 -0
  37. package/dist/esm/utils/OperatorPrecedence.js.map +1 -0
  38. package/dist/esm/utils/ParameterRemover.js +777 -0
  39. package/dist/esm/utils/ParameterRemover.js.map +1 -0
  40. package/dist/index.min.js +16 -0
  41. package/dist/index.min.js.map +7 -0
  42. package/dist/models/ValueComponent.d.ts +6 -1
  43. package/dist/models/ValueComponent.js +9 -1
  44. package/dist/models/ValueComponent.js.map +1 -1
  45. package/dist/parsers/CommandExpressionParser.d.ts +0 -1
  46. package/dist/parsers/CommandExpressionParser.js +0 -15
  47. package/dist/parsers/CommandExpressionParser.js.map +1 -1
  48. package/dist/parsers/FunctionExpressionParser.d.ts +13 -1
  49. package/dist/parsers/FunctionExpressionParser.js +50 -5
  50. package/dist/parsers/FunctionExpressionParser.js.map +1 -1
  51. package/dist/parsers/SqlPrintTokenParser.d.ts +1 -0
  52. package/dist/parsers/SqlPrintTokenParser.js +10 -0
  53. package/dist/parsers/SqlPrintTokenParser.js.map +1 -1
  54. package/dist/parsers/ValueParser.d.ts +9 -1
  55. package/dist/parsers/ValueParser.js +55 -10
  56. package/dist/parsers/ValueParser.js.map +1 -1
  57. package/dist/tokenReaders/CommandTokenReader.js +0 -1
  58. package/dist/tokenReaders/CommandTokenReader.js.map +1 -1
  59. package/dist/tokenReaders/FunctionTokenReader.js +2 -0
  60. package/dist/tokenReaders/FunctionTokenReader.js.map +1 -1
  61. package/dist/transformers/CTECollector.d.ts +3 -0
  62. package/dist/transformers/CTECollector.js +16 -0
  63. package/dist/transformers/CTECollector.js.map +1 -1
  64. package/dist/transformers/CTEDisabler.d.ts +2 -1
  65. package/dist/transformers/CTEDisabler.js +5 -0
  66. package/dist/transformers/CTEDisabler.js.map +1 -1
  67. package/dist/transformers/SelectableColumnCollector.d.ts +1 -0
  68. package/dist/transformers/SelectableColumnCollector.js +4 -0
  69. package/dist/transformers/SelectableColumnCollector.js.map +1 -1
  70. package/dist/transformers/TableSourceCollector.d.ts +9 -0
  71. package/dist/transformers/TableSourceCollector.js +35 -0
  72. package/dist/transformers/TableSourceCollector.js.map +1 -1
  73. package/dist/utils/OperatorPrecedence.d.ts +29 -0
  74. package/dist/utils/OperatorPrecedence.js +83 -0
  75. package/dist/utils/OperatorPrecedence.js.map +1 -0
  76. package/dist/utils/ParameterRemover.d.ts +225 -0
  77. package/dist/utils/ParameterRemover.js +781 -0
  78. package/dist/utils/ParameterRemover.js.map +1 -0
  79. package/package.json +4 -2
@@ -0,0 +1,781 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ParameterRemover = void 0;
4
+ const Clause_1 = require("../models/Clause");
5
+ const SelectQuery_1 = require("../models/SelectQuery");
6
+ const ValueComponent_1 = require("../models/ValueComponent");
7
+ const OperatorPrecedence_1 = require("./OperatorPrecedence");
8
+ /**
9
+ * Helper visitor to detect if a component tree contains any ParameterExpression
10
+ */
11
+ class ParameterDetector {
12
+ constructor() {
13
+ this.handlers = new Map();
14
+ // ParameterExpression always returns true
15
+ this.handlers.set(ValueComponent_1.ParameterExpression.kind, () => true);
16
+ // Binary expressions check both sides
17
+ this.handlers.set(ValueComponent_1.BinaryExpression.kind, (expr) => this.visit(expr.left) || this.visit(expr.right));
18
+ // Parenthesized expressions check inner expression
19
+ this.handlers.set(ValueComponent_1.ParenExpression.kind, (expr) => this.visit(expr.expression));
20
+ // Unary expressions check inner expression
21
+ this.handlers.set(ValueComponent_1.UnaryExpression.kind, (expr) => this.visit(expr.expression));
22
+ // Function calls check argument if present
23
+ this.handlers.set(ValueComponent_1.FunctionCall.kind, (expr) => expr.argument ? this.visit(expr.argument) : false);
24
+ // Case expressions check condition and switch cases
25
+ this.handlers.set(ValueComponent_1.CaseExpression.kind, (expr) => {
26
+ const conditionHasParam = expr.condition ? this.visit(expr.condition) : false;
27
+ const switchCaseHasParam = this.visit(expr.switchCase);
28
+ return conditionHasParam || switchCaseHasParam;
29
+ });
30
+ // Between expressions check all three parts
31
+ this.handlers.set(ValueComponent_1.BetweenExpression.kind, (expr) => this.visit(expr.expression) || this.visit(expr.lower) || this.visit(expr.upper));
32
+ // Default case: no parameters for simple types
33
+ // (ColumnReference, LiteralValue, IdentifierString, etc.)
34
+ }
35
+ visit(component) {
36
+ const handler = this.handlers.get(component.getKind());
37
+ if (handler) {
38
+ return handler(component);
39
+ }
40
+ return false; // Default: no parameters
41
+ }
42
+ static detect(component) {
43
+ const detector = new ParameterDetector();
44
+ return detector.visit(component);
45
+ }
46
+ }
47
+ /**
48
+ * Helper to analyze SQL expression structure safely
49
+ */
50
+ class ExpressionAnalyzer {
51
+ /**
52
+ * Check if a component is a binary expression with logical operator (AND/OR)
53
+ */
54
+ static isLogicalBinaryExpression(component) {
55
+ if (component.getKind() !== ValueComponent_1.BinaryExpression.kind) {
56
+ return false;
57
+ }
58
+ const expr = component;
59
+ return OperatorPrecedence_1.OperatorPrecedence.isLogicalOperator(expr.operator.value);
60
+ }
61
+ /**
62
+ * Check if a component is a comparison operator
63
+ */
64
+ static isComparisonBinaryExpression(component) {
65
+ if (component.getKind() !== ValueComponent_1.BinaryExpression.kind) {
66
+ return false;
67
+ }
68
+ const expr = component;
69
+ return OperatorPrecedence_1.OperatorPrecedence.isComparisonOperator(expr.operator.value);
70
+ }
71
+ }
72
+ /**
73
+ * Utility class to traverse and remove ParameterExpression nodes from the SQL AST.
74
+ * This removes any binary expression containing a ParameterExpression as a whole.
75
+ * For compound logical expressions (AND/OR), only the parameterized parts are removed.
76
+ * If all conditions are removed from a logical expression, the parent node is removed as well.
77
+ */
78
+ class ParameterRemover {
79
+ constructor() {
80
+ this.visitedNodes = new Set();
81
+ this.isRootVisit = true;
82
+ this.handlers = new Map();
83
+ // Setup handlers for all component types
84
+ // SelectQuery types
85
+ this.handlers.set(SelectQuery_1.SimpleSelectQuery.kind, (expr) => this.visitSimpleSelectQuery(expr));
86
+ this.handlers.set(SelectQuery_1.BinarySelectQuery.kind, (expr) => this.visitBinarySelectQuery(expr));
87
+ this.handlers.set(SelectQuery_1.ValuesQuery.kind, (expr) => this.visitValuesQuery(expr));
88
+ // WithClause and CommonTable
89
+ this.handlers.set(Clause_1.WithClause.kind, (expr) => this.visitWithClause(expr));
90
+ this.handlers.set(Clause_1.CommonTable.kind, (expr) => this.visitCommonTable(expr));
91
+ // SelectClause and SelectItem
92
+ this.handlers.set(Clause_1.SelectClause.kind, (expr) => this.visitSelectClause(expr));
93
+ this.handlers.set(Clause_1.SelectItem.kind, (expr) => this.visitSelectItem(expr));
94
+ this.handlers.set(Clause_1.Distinct.kind, (expr) => this.visitDistinctComponent(expr));
95
+ this.handlers.set(Clause_1.DistinctOn.kind, (expr) => this.visitDistinctComponent(expr));
96
+ // Identifiers and raw strings
97
+ this.handlers.set(ValueComponent_1.IdentifierString.kind, (expr) => this.visitIdentifierString(expr));
98
+ this.handlers.set(ValueComponent_1.RawString.kind, (expr) => this.visitRawString(expr));
99
+ this.handlers.set(ValueComponent_1.ColumnReference.kind, (expr) => this.visitColumnReference(expr));
100
+ this.handlers.set(ValueComponent_1.ParameterExpression.kind, (expr) => this.visitParameterExpression(expr));
101
+ this.handlers.set(ValueComponent_1.LiteralValue.kind, (expr) => this.visitLiteralValue(expr));
102
+ // Source components
103
+ this.handlers.set(Clause_1.SourceExpression.kind, (expr) => this.visitSourceExpression(expr));
104
+ this.handlers.set(Clause_1.TableSource.kind, (expr) => this.visitTableSource(expr));
105
+ this.handlers.set(Clause_1.ParenSource.kind, (expr) => this.visitParenSource(expr));
106
+ this.handlers.set(Clause_1.SourceAliasExpression.kind, (expr) => this.visitSourceAliasExpression(expr));
107
+ // Subqueries and inline queries
108
+ this.handlers.set(Clause_1.SubQuerySource.kind, (expr) => this.visitSubQuerySource(expr));
109
+ this.handlers.set(ValueComponent_1.InlineQuery.kind, (expr) => this.visitInlineQuery(expr));
110
+ // FROM and JOIN clauses
111
+ this.handlers.set(Clause_1.FromClause.kind, (expr) => this.visitFromClause(expr));
112
+ this.handlers.set(Clause_1.JoinClause.kind, (expr) => this.visitJoinClause(expr));
113
+ this.handlers.set(Clause_1.JoinOnClause.kind, (expr) => this.visitJoinOnClause(expr));
114
+ this.handlers.set(Clause_1.JoinUsingClause.kind, (expr) => this.visitJoinUsingClause(expr));
115
+ // WHERE clause
116
+ this.handlers.set(Clause_1.WhereClause.kind, (expr) => this.visitWhereClause(expr));
117
+ // Value components that might contain subqueries or parameters
118
+ this.handlers.set(ValueComponent_1.ParenExpression.kind, (expr) => this.visitParenExpression(expr));
119
+ this.handlers.set(ValueComponent_1.BinaryExpression.kind, (expr) => this.visitBinaryExpression(expr));
120
+ this.handlers.set(ValueComponent_1.UnaryExpression.kind, (expr) => this.visitUnaryExpression(expr));
121
+ this.handlers.set(ValueComponent_1.CaseExpression.kind, (expr) => this.visitCaseExpression(expr));
122
+ this.handlers.set(ValueComponent_1.CaseKeyValuePair.kind, (expr) => this.visitCaseKeyValuePair(expr));
123
+ this.handlers.set(ValueComponent_1.SwitchCaseArgument.kind, (expr) => this.visitSwitchCaseArgument(expr));
124
+ this.handlers.set(ValueComponent_1.BetweenExpression.kind, (expr) => this.visitBetweenExpression(expr));
125
+ this.handlers.set(ValueComponent_1.FunctionCall.kind, (expr) => this.visitFunctionCall(expr));
126
+ this.handlers.set(ValueComponent_1.ArrayExpression.kind, (expr) => this.visitArrayExpression(expr));
127
+ this.handlers.set(ValueComponent_1.TupleExpression.kind, (expr) => this.visitTupleExpression(expr));
128
+ this.handlers.set(ValueComponent_1.CastExpression.kind, (expr) => this.visitCastExpression(expr));
129
+ this.handlers.set(ValueComponent_1.WindowFrameExpression.kind, (expr) => this.visitWindowFrameExpression(expr));
130
+ this.handlers.set(ValueComponent_1.WindowFrameSpec.kind, (expr) => this.visitWindowFrameSpec(expr));
131
+ this.handlers.set(ValueComponent_1.TypeValue.kind, (expr) => this.visitTypeValue(expr));
132
+ // Other clauses
133
+ this.handlers.set(Clause_1.GroupByClause.kind, (expr) => this.visitGroupByClause(expr));
134
+ this.handlers.set(Clause_1.HavingClause.kind, (expr) => this.visitHavingClause(expr));
135
+ this.handlers.set(Clause_1.OrderByClause.kind, (expr) => this.visitOrderByClause(expr));
136
+ this.handlers.set(Clause_1.OrderByItem.kind, (expr) => this.visitOrderByItem(expr));
137
+ this.handlers.set(Clause_1.WindowFrameClause.kind, (expr) => this.visitWindowFrameClause(expr));
138
+ this.handlers.set(Clause_1.WindowsClause.kind, (expr) => this.visitWindowsClause(expr));
139
+ this.handlers.set(Clause_1.LimitClause.kind, (expr) => this.visitLimitClause(expr));
140
+ this.handlers.set(Clause_1.ForClause.kind, (expr) => this.visitForClause(expr));
141
+ this.handlers.set(Clause_1.OffsetClause.kind, (expr) => this.visitOffsetClause(expr));
142
+ this.handlers.set(Clause_1.FetchClause.kind, (expr) => this.visitFetchClause(expr));
143
+ this.handlers.set(Clause_1.FetchExpression.kind, (expr) => this.visitFetchExpression(expr));
144
+ }
145
+ /**
146
+ * Reset the visited nodes tracking
147
+ */
148
+ reset() {
149
+ this.visitedNodes.clear();
150
+ }
151
+ /**
152
+ * Main entry point for the visitor pattern.
153
+ * @param arg The SQL component to visit
154
+ * @returns The component with parameter expressions removed, or null if the entire component should be removed
155
+ */
156
+ visit(arg) {
157
+ // If not a root visit, just visit the node and return
158
+ if (!this.isRootVisit) {
159
+ return this.visitNode(arg);
160
+ }
161
+ // If this is a root visit, we need to reset the state
162
+ this.reset();
163
+ this.isRootVisit = false;
164
+ try {
165
+ return this.visitNode(arg);
166
+ }
167
+ finally {
168
+ // Regardless of success or failure, reset the root visit flag
169
+ this.isRootVisit = true;
170
+ }
171
+ }
172
+ /**
173
+ * Internal visit method used for all nodes.
174
+ * This separates the visit flag management from the actual node visitation logic.
175
+ */
176
+ visitNode(arg) {
177
+ var _a, _b;
178
+ // Check for circular references - if node already visited, return as is
179
+ if (this.visitedNodes.has(arg)) {
180
+ return arg;
181
+ }
182
+ // Mark as visited node
183
+ this.visitedNodes.add(arg);
184
+ // Handle null values
185
+ if (!arg) {
186
+ return null;
187
+ }
188
+ const handler = this.handlers.get(arg.getKind());
189
+ if (handler) {
190
+ return handler(arg);
191
+ }
192
+ // Provide more detailed error message
193
+ const kindSymbol = ((_a = arg.getKind()) === null || _a === void 0 ? void 0 : _a.toString()) || 'unknown';
194
+ const constructor = ((_b = arg.constructor) === null || _b === void 0 ? void 0 : _b.name) || 'unknown';
195
+ throw new Error(`[ParameterRemover] No handler for ${constructor} with kind ${kindSymbol}.`);
196
+ }
197
+ /**
198
+ * Visit SimpleSelectQuery node
199
+ */
200
+ visitSimpleSelectQuery(query) {
201
+ const withClause = query.withClause ? this.visit(query.withClause) : null;
202
+ // SelectClause is required
203
+ if (!query.selectClause) {
204
+ throw new Error("[ParameterRemover] SimpleSelectQuery missing required selectClause");
205
+ }
206
+ const selectClause = this.visit(query.selectClause);
207
+ const fromClause = query.fromClause ? this.visit(query.fromClause) : null;
208
+ const whereClause = query.whereClause ? this.visit(query.whereClause) : null;
209
+ const groupByClause = query.groupByClause ? this.visit(query.groupByClause) : null;
210
+ const havingClause = query.havingClause ? this.visit(query.havingClause) : null;
211
+ const orderByClause = query.orderByClause ? this.visit(query.orderByClause) : null;
212
+ const windowClause = query.windowClause ? this.visit(query.windowClause) : null;
213
+ const limitClause = query.limitClause ? this.visit(query.limitClause) : null;
214
+ const offsetClause = query.offsetClause ? this.visit(query.offsetClause) : null;
215
+ const fetchClause = query.fetchClause ? this.visit(query.fetchClause) : null;
216
+ const forClause = query.forClause ? this.visit(query.forClause) : null;
217
+ return new SelectQuery_1.SimpleSelectQuery({
218
+ withClause,
219
+ selectClause,
220
+ fromClause,
221
+ whereClause,
222
+ groupByClause,
223
+ havingClause,
224
+ orderByClause,
225
+ windowClause,
226
+ limitClause,
227
+ offsetClause,
228
+ fetchClause,
229
+ forClause
230
+ });
231
+ }
232
+ /**
233
+ * Visit BinarySelectQuery node
234
+ */
235
+ visitBinarySelectQuery(query) {
236
+ if (!query.left || !query.right) {
237
+ return null;
238
+ }
239
+ const left = this.visit(query.left);
240
+ if (!left) {
241
+ return null;
242
+ }
243
+ const right = this.visit(query.right);
244
+ if (!right) {
245
+ return null;
246
+ }
247
+ const operation = query.operator;
248
+ return new SelectQuery_1.BinarySelectQuery(left, operation.value, right);
249
+ }
250
+ /**
251
+ * Visit ValuesQuery node
252
+ */
253
+ visitValuesQuery(query) {
254
+ // Since ValuesQuery doesn't typically contain parameters in WHERE conditions,
255
+ // we'll just return it as is for now
256
+ return query;
257
+ }
258
+ /**
259
+ * Visit WithClause node
260
+ */
261
+ visitWithClause(clause) {
262
+ if (!clause.tables) {
263
+ return null;
264
+ }
265
+ const tables = clause.tables
266
+ .map(table => this.visit(table))
267
+ .filter(table => table !== null);
268
+ if (tables.length === 0) {
269
+ return null;
270
+ }
271
+ return new Clause_1.WithClause(clause.recursive, tables);
272
+ }
273
+ /**
274
+ * Visit CommonTable node
275
+ */
276
+ visitCommonTable(table) {
277
+ if (!table.aliasExpression || !table.query) {
278
+ return null;
279
+ }
280
+ const aliasExpression = this.visit(table.aliasExpression);
281
+ if (!aliasExpression) {
282
+ return null;
283
+ }
284
+ const selectQuery = this.visit(table.query);
285
+ if (!selectQuery) {
286
+ return null;
287
+ }
288
+ return new Clause_1.CommonTable(selectQuery, aliasExpression, table.materialized);
289
+ }
290
+ /**
291
+ * Visit SelectClause node
292
+ */
293
+ visitSelectClause(clause) {
294
+ if (!clause.items) {
295
+ throw new Error("[ParameterRemover] SelectClause missing required items");
296
+ }
297
+ const items = clause.items
298
+ .map(item => this.visit(item))
299
+ .filter(item => item !== null);
300
+ const distinct = clause.distinct ? this.visit(clause.distinct) : null;
301
+ if (items.length === 0) {
302
+ throw new Error("[ParameterRemover] SelectClause must have at least one item");
303
+ }
304
+ return new Clause_1.SelectClause(items, distinct);
305
+ }
306
+ /**
307
+ * Visit SelectItem node
308
+ */
309
+ visitSelectItem(item) {
310
+ var _a;
311
+ if (!item.value) {
312
+ return null;
313
+ }
314
+ const value = this.visit(item.value);
315
+ if (!value) {
316
+ return null;
317
+ }
318
+ return new Clause_1.SelectItem(value, ((_a = item.identifier) === null || _a === void 0 ? void 0 : _a.name) || null);
319
+ }
320
+ // Simple visitor methods that return the node unchanged
321
+ visitIdentifierString(identifier) { return identifier; }
322
+ visitRawString(str) { return str; }
323
+ visitColumnReference(ref) { return ref; }
324
+ visitParameterExpression(param) { return null; }
325
+ visitLiteralValue(literal) { return literal; }
326
+ visitTableSource(source) { return source; }
327
+ visitForClause(clause) { return clause; }
328
+ visitDistinctComponent(component) { return component; }
329
+ /**
330
+ * Visit SourceExpression node
331
+ */
332
+ visitSourceExpression(source) {
333
+ if (!source.datasource) {
334
+ return source; // Return as is instead of null
335
+ }
336
+ const sourceComponent = this.visit(source.datasource);
337
+ if (!sourceComponent) {
338
+ return source; // Return as is instead of null
339
+ }
340
+ return new Clause_1.SourceExpression(sourceComponent, source.aliasExpression);
341
+ }
342
+ /**
343
+ * Visit ParenSource node
344
+ */
345
+ visitParenSource(source) {
346
+ return new Clause_1.ParenSource(this.visit(source.source));
347
+ }
348
+ /**
349
+ * Visit SourceAliasExpression node
350
+ */
351
+ visitSourceAliasExpression(expr) {
352
+ const table = expr.table;
353
+ const columns = expr.columns;
354
+ const columnNames = columns ? columns.map(col => col.name) : null;
355
+ return new Clause_1.SourceAliasExpression(table.name, columnNames);
356
+ }
357
+ /**
358
+ * Visit SubQuerySource node
359
+ */
360
+ visitSubQuerySource(source) {
361
+ if (!source.query) {
362
+ return null;
363
+ }
364
+ const query = this.visit(source.query);
365
+ if (!query) {
366
+ return null;
367
+ }
368
+ return new Clause_1.SubQuerySource(query);
369
+ }
370
+ /**
371
+ * Visit InlineQuery node
372
+ */
373
+ visitInlineQuery(query) {
374
+ if (!query.selectQuery) {
375
+ return null;
376
+ }
377
+ const selectQuery = this.visit(query.selectQuery);
378
+ if (!selectQuery) {
379
+ return null;
380
+ }
381
+ return new ValueComponent_1.InlineQuery(selectQuery);
382
+ }
383
+ /**
384
+ * Visit FromClause node
385
+ */
386
+ visitFromClause(clause) {
387
+ if (!clause.source) {
388
+ return clause; // Return as is instead of null
389
+ }
390
+ // Always keep the source, even if something inside might change
391
+ const source = this.visit(clause.source);
392
+ let joins = null;
393
+ if (clause.joins) {
394
+ const processedJoins = clause.joins
395
+ .map(join => this.visit(join))
396
+ .filter(join => join !== null);
397
+ if (processedJoins.length > 0) {
398
+ joins = processedJoins;
399
+ }
400
+ }
401
+ return new Clause_1.FromClause(source || clause.source, joins);
402
+ }
403
+ /**
404
+ * Visit JoinClause node
405
+ */
406
+ visitJoinClause(clause) {
407
+ if (!clause.source) {
408
+ return null;
409
+ }
410
+ const source = this.visit(clause.source);
411
+ if (!source) {
412
+ return null;
413
+ }
414
+ const condition = clause.condition ? this.visit(clause.condition) : null;
415
+ return new Clause_1.JoinClause(clause.joinType.value, source, condition, clause.lateral);
416
+ }
417
+ /**
418
+ * Visit JoinOnClause node
419
+ */
420
+ visitJoinOnClause(clause) {
421
+ const condition = this.visit(clause.condition);
422
+ // If condition has been removed (contains only parameters), return null
423
+ if (!condition) {
424
+ return null;
425
+ }
426
+ return new Clause_1.JoinOnClause(condition);
427
+ }
428
+ /**
429
+ * Visit JoinUsingClause node
430
+ */
431
+ visitJoinUsingClause(clause) {
432
+ return clause;
433
+ }
434
+ /**
435
+ * Visit WhereClause node - key method for parameter removal
436
+ */
437
+ visitWhereClause(clause) {
438
+ const condition = this.visit(clause.condition);
439
+ // If the entire condition has been removed (contains only parameters), return null
440
+ if (!condition) {
441
+ return null;
442
+ }
443
+ return new Clause_1.WhereClause(condition);
444
+ }
445
+ /**
446
+ * Visit ParenExpression node
447
+ */
448
+ visitParenExpression(expr) {
449
+ const innerExpression = this.visit(expr.expression);
450
+ // If the inner expression has been removed (contains only parameters), return null
451
+ if (!innerExpression) {
452
+ return null;
453
+ }
454
+ return new ValueComponent_1.ParenExpression(innerExpression);
455
+ }
456
+ /**
457
+ * Visit BinaryExpression node - improved logic for right-associative parser structure
458
+ */
459
+ visitBinaryExpression(expr) {
460
+ const operator = expr.operator.value.toLowerCase();
461
+ if (OperatorPrecedence_1.OperatorPrecedence.isLogicalOperator(operator)) {
462
+ // Handle logical operators normally
463
+ const left = this.visit(expr.left);
464
+ const right = this.visit(expr.right);
465
+ if (!left && !right) {
466
+ return null;
467
+ }
468
+ if (!left && right) {
469
+ return right;
470
+ }
471
+ if (left && !right) {
472
+ return left;
473
+ }
474
+ return new ValueComponent_1.BinaryExpression(left, expr.operator.value, right);
475
+ }
476
+ else {
477
+ // For comparison operators, handle right-associative parser structure
478
+ return this.handleComparisonExpression(expr);
479
+ }
480
+ }
481
+ /**
482
+ * Handle comparison expressions, accounting for right-associative parser structure
483
+ */
484
+ handleComparisonExpression(expr) {
485
+ const left = this.visit(expr.left);
486
+ // Check if the right side is a logical expression (AND/OR) using type-safe analysis
487
+ if (ExpressionAnalyzer.isLogicalBinaryExpression(expr.right)) {
488
+ // This is the problematic case: comparison = (logical expression)
489
+ // We need to restructure this as: (comparison) logical (other parts)
490
+ return this.restructureComparisonWithLogical(expr, left);
491
+ }
492
+ // Normal comparison processing
493
+ const right = this.visit(expr.right);
494
+ if (!left || !right) {
495
+ return null;
496
+ }
497
+ return new ValueComponent_1.BinaryExpression(left, expr.operator.value, right);
498
+ }
499
+ /**
500
+ * Restructure expressions like "id = (1 AND ...)" to "(id = 1) AND ..."
501
+ */
502
+ restructureComparisonWithLogical(expr, processedLeft) {
503
+ if (!processedLeft) {
504
+ return null;
505
+ }
506
+ const rightBinary = expr.right;
507
+ const logicalOperator = rightBinary.operator.value;
508
+ // Process the logical expression's left side as the right side of our comparison
509
+ const comparisonRight = this.visit(rightBinary.left);
510
+ if (!comparisonRight) {
511
+ // If the comparison right side contains only parameters,
512
+ // try to process the logical expression's right side
513
+ return this.visit(rightBinary.right);
514
+ }
515
+ // Create the restructured comparison: "id = 1"
516
+ const restructuredComparison = new ValueComponent_1.BinaryExpression(processedLeft, expr.operator.value, comparisonRight);
517
+ // Process the remaining logical expression's right side
518
+ const logicalRight = this.visit(rightBinary.right);
519
+ if (!logicalRight) {
520
+ // Only the left comparison is valid
521
+ return restructuredComparison;
522
+ }
523
+ // Combine: "(id = 1) AND (remaining expression)"
524
+ return new ValueComponent_1.BinaryExpression(restructuredComparison, logicalOperator, logicalRight);
525
+ }
526
+ /**
527
+ * Check if an operator is a logical operator */
528
+ /**
529
+ * Check if the resulting expression would be nonsensical
530
+ * This is a heuristic to detect cases like "name = age > 18"
531
+ */
532
+ wouldCreateNonsensicalExpression(left, operator, right) {
533
+ // Only apply this check for simple cases where we have a direct comparison operator
534
+ // followed by another comparison operator in the right side
535
+ if (OperatorPrecedence_1.OperatorPrecedence.isComparisonOperator(operator) && ExpressionAnalyzer.isComparisonBinaryExpression(right)) {
536
+ const rightBinary = right;
537
+ if (rightBinary.operator && OperatorPrecedence_1.OperatorPrecedence.isComparisonOperator(rightBinary.operator.value)) {
538
+ // Additional check: make sure this isn't a legitimate nested case
539
+ // If the left side is a simple column and the right side is a comparison,
540
+ // this is likely nonsensical (like "name = age > 18")
541
+ if (left.getKind().toString().includes('ColumnReference')) {
542
+ return true;
543
+ }
544
+ }
545
+ }
546
+ return false;
547
+ }
548
+ /**
549
+ * Check if a ValueComponent contains a ParameterExpression anywhere in its tree
550
+ */
551
+ containsParameter(component) {
552
+ return ParameterDetector.detect(component);
553
+ }
554
+ /**
555
+ * Visit UnaryExpression node
556
+ */
557
+ visitUnaryExpression(expr) {
558
+ const expression = this.visit(expr.expression);
559
+ // If the expression has been removed (contains only parameters), return null
560
+ if (!expression) {
561
+ return null;
562
+ }
563
+ return new ValueComponent_1.UnaryExpression(expr.operator.value, expression);
564
+ }
565
+ /**
566
+ * Visit CaseExpression node
567
+ */
568
+ visitCaseExpression(expr) {
569
+ const condition = expr.condition ? this.visit(expr.condition) : null;
570
+ const switchCase = this.visit(expr.switchCase);
571
+ // If switchCase has been removed (contains only parameters), return null
572
+ if (!switchCase) {
573
+ return null;
574
+ }
575
+ return new ValueComponent_1.CaseExpression(condition, switchCase);
576
+ }
577
+ /**
578
+ * Visit CaseKeyValuePair node
579
+ */
580
+ visitCaseKeyValuePair(pair) {
581
+ // If either key or value contains parameters, remove the entire pair
582
+ if (this.containsParameter(pair.key) || this.containsParameter(pair.value)) {
583
+ return null;
584
+ }
585
+ const key = this.visit(pair.key);
586
+ const value = this.visit(pair.value);
587
+ return new ValueComponent_1.CaseKeyValuePair(key, value);
588
+ }
589
+ /**
590
+ * Visit SwitchCaseArgument node
591
+ */
592
+ visitSwitchCaseArgument(arg) {
593
+ // Process all case pairs, filter out null results
594
+ const cases = arg.cases
595
+ .map(caseItem => this.visit(caseItem))
596
+ .filter(caseItem => caseItem !== null);
597
+ // Process the else value if it exists
598
+ const elseValue = arg.elseValue ? this.visit(arg.elseValue) : null;
599
+ // If no cases remain and no else value, remove the entire switch case
600
+ if (cases.length === 0 && !elseValue) {
601
+ return null;
602
+ }
603
+ return new ValueComponent_1.SwitchCaseArgument(cases, elseValue);
604
+ }
605
+ /**
606
+ * Visit BetweenExpression node
607
+ */
608
+ visitBetweenExpression(expr) {
609
+ // If any part of the expression contains a parameter, remove the entire expression
610
+ if (this.containsParameter(expr.expression) ||
611
+ this.containsParameter(expr.lower) ||
612
+ this.containsParameter(expr.upper)) {
613
+ return null;
614
+ }
615
+ const expression = this.visit(expr.expression);
616
+ const lower = this.visit(expr.lower);
617
+ const upper = this.visit(expr.upper);
618
+ return new ValueComponent_1.BetweenExpression(expression, lower, upper, expr.negated);
619
+ }
620
+ /**
621
+ * Visit FunctionCall node
622
+ */
623
+ visitFunctionCall(call) {
624
+ const argument = call.argument ? this.visit(call.argument) : null;
625
+ const over = call.over ? this.visit(call.over) : null;
626
+ return new ValueComponent_1.FunctionCall(call.qualifiedName.namespaces, call.qualifiedName.name, argument, over);
627
+ }
628
+ /**
629
+ * Visit ArrayExpression node
630
+ */
631
+ visitArrayExpression(expr) {
632
+ const expression = this.visit(expr.expression);
633
+ // If the expression has been removed (contains only parameters), return null
634
+ if (!expression) {
635
+ return null;
636
+ }
637
+ return new ValueComponent_1.ArrayExpression(expression);
638
+ }
639
+ /**
640
+ * Visit TupleExpression node
641
+ */
642
+ visitTupleExpression(expr) {
643
+ const values = expr.values
644
+ .map(value => this.visit(value))
645
+ .filter(value => value !== null);
646
+ return new ValueComponent_1.TupleExpression(values);
647
+ }
648
+ /**
649
+ * Visit CastExpression node
650
+ */
651
+ visitCastExpression(expr) {
652
+ // If the input contains a parameter, remove the entire expression
653
+ if (this.containsParameter(expr.input)) {
654
+ return null;
655
+ }
656
+ const input = this.visit(expr.input);
657
+ const castType = this.visit(expr.castType);
658
+ // If the input has been removed, return null
659
+ if (!input) {
660
+ return null;
661
+ }
662
+ return new ValueComponent_1.CastExpression(input, castType);
663
+ }
664
+ /**
665
+ * Visit WindowFrameExpression node
666
+ */
667
+ visitWindowFrameExpression(expr) {
668
+ const partition = expr.partition ? this.visit(expr.partition) : null;
669
+ const order = expr.order ? this.visit(expr.order) : null;
670
+ const frameSpec = expr.frameSpec ? this.visit(expr.frameSpec) : null;
671
+ return new ValueComponent_1.WindowFrameExpression(partition, order, frameSpec);
672
+ }
673
+ /**
674
+ * Visit WindowFrameSpec node
675
+ */
676
+ visitWindowFrameSpec(spec) {
677
+ return spec;
678
+ }
679
+ /**
680
+ * Visit TypeValue node
681
+ */
682
+ visitTypeValue(type) {
683
+ const argument = type.argument ? this.visit(type.argument) : null;
684
+ return new ValueComponent_1.TypeValue(type.qualifiedName.namespaces, type.qualifiedName.name, argument);
685
+ }
686
+ /**
687
+ * Visit GroupByClause node
688
+ */
689
+ visitGroupByClause(clause) {
690
+ if (!clause.grouping || clause.grouping.length === 0) {
691
+ return null;
692
+ }
693
+ const grouping = clause.grouping
694
+ .map(expr => this.visit(expr))
695
+ .filter(expr => expr !== null);
696
+ if (grouping.length === 0) {
697
+ return null;
698
+ }
699
+ return new Clause_1.GroupByClause(grouping);
700
+ }
701
+ /**
702
+ * Visit HavingClause node
703
+ */
704
+ visitHavingClause(clause) {
705
+ const condition = this.visit(clause.condition);
706
+ // If the condition has been removed (contains only parameters), return null
707
+ if (!condition) {
708
+ return null;
709
+ }
710
+ return new Clause_1.HavingClause(condition);
711
+ }
712
+ /**
713
+ * Visit OrderByClause node
714
+ */
715
+ visitOrderByClause(clause) {
716
+ const items = clause.order
717
+ .map((item) => this.visit(item))
718
+ .filter((item) => item !== null);
719
+ return new Clause_1.OrderByClause(items);
720
+ }
721
+ /**
722
+ * Visit OrderByItem node
723
+ */
724
+ visitOrderByItem(item) {
725
+ const value = this.visit(item.value);
726
+ return new Clause_1.OrderByItem(value, item.sortDirection, item.nullsPosition);
727
+ }
728
+ /**
729
+ * Visit WindowFrameClause node
730
+ */
731
+ visitWindowFrameClause(clause) {
732
+ const expression = this.visit(clause.expression);
733
+ return new Clause_1.WindowFrameClause(clause.name.name, expression);
734
+ }
735
+ /**
736
+ * Visit WindowsClause node
737
+ */
738
+ visitWindowsClause(clause) {
739
+ const windows = clause.windows.map(window => this.visit(window));
740
+ return new Clause_1.WindowsClause(windows);
741
+ }
742
+ /**
743
+ * Visit LimitClause node
744
+ */
745
+ visitLimitClause(clause) {
746
+ const value = this.visit(clause.value);
747
+ return new Clause_1.LimitClause(value);
748
+ }
749
+ /**
750
+ * Visit OffsetClause node
751
+ */
752
+ visitOffsetClause(clause) {
753
+ const value = this.visit(clause.value);
754
+ return new Clause_1.OffsetClause(value);
755
+ }
756
+ /**
757
+ * Visit FetchClause node
758
+ */
759
+ visitFetchClause(clause) {
760
+ const expression = this.visit(clause.expression);
761
+ return new Clause_1.FetchClause(expression);
762
+ }
763
+ /**
764
+ * Visit FetchExpression node
765
+ */
766
+ visitFetchExpression(expression) {
767
+ const count = this.visit(expression.count);
768
+ return new Clause_1.FetchExpression(expression.type, count, expression.unit);
769
+ }
770
+ /**
771
+ * Static method to apply parameter removal transformation on an SQL AST
772
+ * @param node The SQL AST node to transform
773
+ * @returns The transformed SQL AST with parameter expressions removed
774
+ */
775
+ static remove(node) {
776
+ const remover = new ParameterRemover();
777
+ return remover.visit(node);
778
+ }
779
+ }
780
+ exports.ParameterRemover = ParameterRemover;
781
+ //# sourceMappingURL=ParameterRemover.js.map