UNPKG

rawsql-ts

Version:

[beta]High-performance SQL parser and AST analyzer written in TypeScript. Provides fast parsing and advanced transformation capabilities.

781 lines 31.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ParameterRemover = void 0; const Clause_1 = require("../models/Clause"); const SelectQuery_1 = require("../models/SelectQuery"); const ValueComponent_1 = require("../models/ValueComponent"); const OperatorPrecedence_1 = require("./OperatorPrecedence"); /** * Helper visitor to detect if a component tree contains any ParameterExpression */ class ParameterDetector { constructor() { this.handlers = new Map(); // ParameterExpression always returns true this.handlers.set(ValueComponent_1.ParameterExpression.kind, () => true); // Binary expressions check both sides this.handlers.set(ValueComponent_1.BinaryExpression.kind, (expr) => this.visit(expr.left) || this.visit(expr.right)); // Parenthesized expressions check inner expression this.handlers.set(ValueComponent_1.ParenExpression.kind, (expr) => this.visit(expr.expression)); // Unary expressions check inner expression this.handlers.set(ValueComponent_1.UnaryExpression.kind, (expr) => this.visit(expr.expression)); // Function calls check argument if present this.handlers.set(ValueComponent_1.FunctionCall.kind, (expr) => expr.argument ? this.visit(expr.argument) : false); // Case expressions check condition and switch cases this.handlers.set(ValueComponent_1.CaseExpression.kind, (expr) => { const conditionHasParam = expr.condition ? this.visit(expr.condition) : false; const switchCaseHasParam = this.visit(expr.switchCase); return conditionHasParam || switchCaseHasParam; }); // Between expressions check all three parts this.handlers.set(ValueComponent_1.BetweenExpression.kind, (expr) => this.visit(expr.expression) || this.visit(expr.lower) || this.visit(expr.upper)); // Default case: no parameters for simple types // (ColumnReference, LiteralValue, IdentifierString, etc.) } visit(component) { const handler = this.handlers.get(component.getKind()); if (handler) { return handler(component); } return false; // Default: no parameters } static detect(component) { const detector = new ParameterDetector(); return detector.visit(component); } } /** * Helper to analyze SQL expression structure safely */ class ExpressionAnalyzer { /** * Check if a component is a binary expression with logical operator (AND/OR) */ static isLogicalBinaryExpression(component) { if (component.getKind() !== ValueComponent_1.BinaryExpression.kind) { return false; } const expr = component; return OperatorPrecedence_1.OperatorPrecedence.isLogicalOperator(expr.operator.value); } /** * Check if a component is a comparison operator */ static isComparisonBinaryExpression(component) { if (component.getKind() !== ValueComponent_1.BinaryExpression.kind) { return false; } const expr = component; return OperatorPrecedence_1.OperatorPrecedence.isComparisonOperator(expr.operator.value); } } /** * Utility class to traverse and remove ParameterExpression nodes from the SQL AST. * This removes any binary expression containing a ParameterExpression as a whole. * For compound logical expressions (AND/OR), only the parameterized parts are removed. * If all conditions are removed from a logical expression, the parent node is removed as well. */ class ParameterRemover { constructor() { this.visitedNodes = new Set(); this.isRootVisit = true; this.handlers = new Map(); // Setup handlers for all component types // SelectQuery types this.handlers.set(SelectQuery_1.SimpleSelectQuery.kind, (expr) => this.visitSimpleSelectQuery(expr)); this.handlers.set(SelectQuery_1.BinarySelectQuery.kind, (expr) => this.visitBinarySelectQuery(expr)); this.handlers.set(SelectQuery_1.ValuesQuery.kind, (expr) => this.visitValuesQuery(expr)); // WithClause and CommonTable this.handlers.set(Clause_1.WithClause.kind, (expr) => this.visitWithClause(expr)); this.handlers.set(Clause_1.CommonTable.kind, (expr) => this.visitCommonTable(expr)); // SelectClause and SelectItem this.handlers.set(Clause_1.SelectClause.kind, (expr) => this.visitSelectClause(expr)); this.handlers.set(Clause_1.SelectItem.kind, (expr) => this.visitSelectItem(expr)); this.handlers.set(Clause_1.Distinct.kind, (expr) => this.visitDistinctComponent(expr)); this.handlers.set(Clause_1.DistinctOn.kind, (expr) => this.visitDistinctComponent(expr)); // Identifiers and raw strings this.handlers.set(ValueComponent_1.IdentifierString.kind, (expr) => this.visitIdentifierString(expr)); this.handlers.set(ValueComponent_1.RawString.kind, (expr) => this.visitRawString(expr)); this.handlers.set(ValueComponent_1.ColumnReference.kind, (expr) => this.visitColumnReference(expr)); this.handlers.set(ValueComponent_1.ParameterExpression.kind, (expr) => this.visitParameterExpression(expr)); this.handlers.set(ValueComponent_1.LiteralValue.kind, (expr) => this.visitLiteralValue(expr)); // Source components this.handlers.set(Clause_1.SourceExpression.kind, (expr) => this.visitSourceExpression(expr)); this.handlers.set(Clause_1.TableSource.kind, (expr) => this.visitTableSource(expr)); this.handlers.set(Clause_1.ParenSource.kind, (expr) => this.visitParenSource(expr)); this.handlers.set(Clause_1.SourceAliasExpression.kind, (expr) => this.visitSourceAliasExpression(expr)); // Subqueries and inline queries this.handlers.set(Clause_1.SubQuerySource.kind, (expr) => this.visitSubQuerySource(expr)); this.handlers.set(ValueComponent_1.InlineQuery.kind, (expr) => this.visitInlineQuery(expr)); // FROM and JOIN clauses this.handlers.set(Clause_1.FromClause.kind, (expr) => this.visitFromClause(expr)); this.handlers.set(Clause_1.JoinClause.kind, (expr) => this.visitJoinClause(expr)); this.handlers.set(Clause_1.JoinOnClause.kind, (expr) => this.visitJoinOnClause(expr)); this.handlers.set(Clause_1.JoinUsingClause.kind, (expr) => this.visitJoinUsingClause(expr)); // WHERE clause this.handlers.set(Clause_1.WhereClause.kind, (expr) => this.visitWhereClause(expr)); // Value components that might contain subqueries or parameters this.handlers.set(ValueComponent_1.ParenExpression.kind, (expr) => this.visitParenExpression(expr)); this.handlers.set(ValueComponent_1.BinaryExpression.kind, (expr) => this.visitBinaryExpression(expr)); this.handlers.set(ValueComponent_1.UnaryExpression.kind, (expr) => this.visitUnaryExpression(expr)); this.handlers.set(ValueComponent_1.CaseExpression.kind, (expr) => this.visitCaseExpression(expr)); this.handlers.set(ValueComponent_1.CaseKeyValuePair.kind, (expr) => this.visitCaseKeyValuePair(expr)); this.handlers.set(ValueComponent_1.SwitchCaseArgument.kind, (expr) => this.visitSwitchCaseArgument(expr)); this.handlers.set(ValueComponent_1.BetweenExpression.kind, (expr) => this.visitBetweenExpression(expr)); this.handlers.set(ValueComponent_1.FunctionCall.kind, (expr) => this.visitFunctionCall(expr)); this.handlers.set(ValueComponent_1.ArrayExpression.kind, (expr) => this.visitArrayExpression(expr)); this.handlers.set(ValueComponent_1.TupleExpression.kind, (expr) => this.visitTupleExpression(expr)); this.handlers.set(ValueComponent_1.CastExpression.kind, (expr) => this.visitCastExpression(expr)); this.handlers.set(ValueComponent_1.WindowFrameExpression.kind, (expr) => this.visitWindowFrameExpression(expr)); this.handlers.set(ValueComponent_1.WindowFrameSpec.kind, (expr) => this.visitWindowFrameSpec(expr)); this.handlers.set(ValueComponent_1.TypeValue.kind, (expr) => this.visitTypeValue(expr)); // Other clauses this.handlers.set(Clause_1.GroupByClause.kind, (expr) => this.visitGroupByClause(expr)); this.handlers.set(Clause_1.HavingClause.kind, (expr) => this.visitHavingClause(expr)); this.handlers.set(Clause_1.OrderByClause.kind, (expr) => this.visitOrderByClause(expr)); this.handlers.set(Clause_1.OrderByItem.kind, (expr) => this.visitOrderByItem(expr)); this.handlers.set(Clause_1.WindowFrameClause.kind, (expr) => this.visitWindowFrameClause(expr)); this.handlers.set(Clause_1.WindowsClause.kind, (expr) => this.visitWindowsClause(expr)); this.handlers.set(Clause_1.LimitClause.kind, (expr) => this.visitLimitClause(expr)); this.handlers.set(Clause_1.ForClause.kind, (expr) => this.visitForClause(expr)); this.handlers.set(Clause_1.OffsetClause.kind, (expr) => this.visitOffsetClause(expr)); this.handlers.set(Clause_1.FetchClause.kind, (expr) => this.visitFetchClause(expr)); this.handlers.set(Clause_1.FetchExpression.kind, (expr) => this.visitFetchExpression(expr)); } /** * Reset the visited nodes tracking */ reset() { this.visitedNodes.clear(); } /** * Main entry point for the visitor pattern. * @param arg The SQL component to visit * @returns The component with parameter expressions removed, or null if the entire component should be removed */ visit(arg) { // If not a root visit, just visit the node and return if (!this.isRootVisit) { return this.visitNode(arg); } // If this is a root visit, we need to reset the state this.reset(); this.isRootVisit = false; try { return this.visitNode(arg); } finally { // Regardless of success or failure, reset the root visit flag this.isRootVisit = true; } } /** * Internal visit method used for all nodes. * This separates the visit flag management from the actual node visitation logic. */ visitNode(arg) { var _a, _b; // Check for circular references - if node already visited, return as is if (this.visitedNodes.has(arg)) { return arg; } // Mark as visited node this.visitedNodes.add(arg); // Handle null values if (!arg) { return null; } const handler = this.handlers.get(arg.getKind()); if (handler) { return handler(arg); } // Provide more detailed error message const kindSymbol = ((_a = arg.getKind()) === null || _a === void 0 ? void 0 : _a.toString()) || 'unknown'; const constructor = ((_b = arg.constructor) === null || _b === void 0 ? void 0 : _b.name) || 'unknown'; throw new Error(`[ParameterRemover] No handler for ${constructor} with kind ${kindSymbol}.`); } /** * Visit SimpleSelectQuery node */ visitSimpleSelectQuery(query) { const withClause = query.withClause ? this.visit(query.withClause) : null; // SelectClause is required if (!query.selectClause) { throw new Error("[ParameterRemover] SimpleSelectQuery missing required selectClause"); } const selectClause = this.visit(query.selectClause); const fromClause = query.fromClause ? this.visit(query.fromClause) : null; const whereClause = query.whereClause ? this.visit(query.whereClause) : null; const groupByClause = query.groupByClause ? this.visit(query.groupByClause) : null; const havingClause = query.havingClause ? this.visit(query.havingClause) : null; const orderByClause = query.orderByClause ? this.visit(query.orderByClause) : null; const windowClause = query.windowClause ? this.visit(query.windowClause) : null; const limitClause = query.limitClause ? this.visit(query.limitClause) : null; const offsetClause = query.offsetClause ? this.visit(query.offsetClause) : null; const fetchClause = query.fetchClause ? this.visit(query.fetchClause) : null; const forClause = query.forClause ? this.visit(query.forClause) : null; return new SelectQuery_1.SimpleSelectQuery({ withClause, selectClause, fromClause, whereClause, groupByClause, havingClause, orderByClause, windowClause, limitClause, offsetClause, fetchClause, forClause }); } /** * Visit BinarySelectQuery node */ visitBinarySelectQuery(query) { if (!query.left || !query.right) { return null; } const left = this.visit(query.left); if (!left) { return null; } const right = this.visit(query.right); if (!right) { return null; } const operation = query.operator; return new SelectQuery_1.BinarySelectQuery(left, operation.value, right); } /** * Visit ValuesQuery node */ visitValuesQuery(query) { // Since ValuesQuery doesn't typically contain parameters in WHERE conditions, // we'll just return it as is for now return query; } /** * Visit WithClause node */ visitWithClause(clause) { if (!clause.tables) { return null; } const tables = clause.tables .map(table => this.visit(table)) .filter(table => table !== null); if (tables.length === 0) { return null; } return new Clause_1.WithClause(clause.recursive, tables); } /** * Visit CommonTable node */ visitCommonTable(table) { if (!table.aliasExpression || !table.query) { return null; } const aliasExpression = this.visit(table.aliasExpression); if (!aliasExpression) { return null; } const selectQuery = this.visit(table.query); if (!selectQuery) { return null; } return new Clause_1.CommonTable(selectQuery, aliasExpression, table.materialized); } /** * Visit SelectClause node */ visitSelectClause(clause) { if (!clause.items) { throw new Error("[ParameterRemover] SelectClause missing required items"); } const items = clause.items .map(item => this.visit(item)) .filter(item => item !== null); const distinct = clause.distinct ? this.visit(clause.distinct) : null; if (items.length === 0) { throw new Error("[ParameterRemover] SelectClause must have at least one item"); } return new Clause_1.SelectClause(items, distinct); } /** * Visit SelectItem node */ visitSelectItem(item) { var _a; if (!item.value) { return null; } const value = this.visit(item.value); if (!value) { return null; } return new Clause_1.SelectItem(value, ((_a = item.identifier) === null || _a === void 0 ? void 0 : _a.name) || null); } // Simple visitor methods that return the node unchanged visitIdentifierString(identifier) { return identifier; } visitRawString(str) { return str; } visitColumnReference(ref) { return ref; } visitParameterExpression(param) { return null; } visitLiteralValue(literal) { return literal; } visitTableSource(source) { return source; } visitForClause(clause) { return clause; } visitDistinctComponent(component) { return component; } /** * Visit SourceExpression node */ visitSourceExpression(source) { if (!source.datasource) { return source; // Return as is instead of null } const sourceComponent = this.visit(source.datasource); if (!sourceComponent) { return source; // Return as is instead of null } return new Clause_1.SourceExpression(sourceComponent, source.aliasExpression); } /** * Visit ParenSource node */ visitParenSource(source) { return new Clause_1.ParenSource(this.visit(source.source)); } /** * Visit SourceAliasExpression node */ visitSourceAliasExpression(expr) { const table = expr.table; const columns = expr.columns; const columnNames = columns ? columns.map(col => col.name) : null; return new Clause_1.SourceAliasExpression(table.name, columnNames); } /** * Visit SubQuerySource node */ visitSubQuerySource(source) { if (!source.query) { return null; } const query = this.visit(source.query); if (!query) { return null; } return new Clause_1.SubQuerySource(query); } /** * Visit InlineQuery node */ visitInlineQuery(query) { if (!query.selectQuery) { return null; } const selectQuery = this.visit(query.selectQuery); if (!selectQuery) { return null; } return new ValueComponent_1.InlineQuery(selectQuery); } /** * Visit FromClause node */ visitFromClause(clause) { if (!clause.source) { return clause; // Return as is instead of null } // Always keep the source, even if something inside might change const source = this.visit(clause.source); let joins = null; if (clause.joins) { const processedJoins = clause.joins .map(join => this.visit(join)) .filter(join => join !== null); if (processedJoins.length > 0) { joins = processedJoins; } } return new Clause_1.FromClause(source || clause.source, joins); } /** * Visit JoinClause node */ visitJoinClause(clause) { if (!clause.source) { return null; } const source = this.visit(clause.source); if (!source) { return null; } const condition = clause.condition ? this.visit(clause.condition) : null; return new Clause_1.JoinClause(clause.joinType.value, source, condition, clause.lateral); } /** * Visit JoinOnClause node */ visitJoinOnClause(clause) { const condition = this.visit(clause.condition); // If condition has been removed (contains only parameters), return null if (!condition) { return null; } return new Clause_1.JoinOnClause(condition); } /** * Visit JoinUsingClause node */ visitJoinUsingClause(clause) { return clause; } /** * Visit WhereClause node - key method for parameter removal */ visitWhereClause(clause) { const condition = this.visit(clause.condition); // If the entire condition has been removed (contains only parameters), return null if (!condition) { return null; } return new Clause_1.WhereClause(condition); } /** * Visit ParenExpression node */ visitParenExpression(expr) { const innerExpression = this.visit(expr.expression); // If the inner expression has been removed (contains only parameters), return null if (!innerExpression) { return null; } return new ValueComponent_1.ParenExpression(innerExpression); } /** * Visit BinaryExpression node - improved logic for right-associative parser structure */ visitBinaryExpression(expr) { const operator = expr.operator.value.toLowerCase(); if (OperatorPrecedence_1.OperatorPrecedence.isLogicalOperator(operator)) { // Handle logical operators normally const left = this.visit(expr.left); const right = this.visit(expr.right); if (!left && !right) { return null; } if (!left && right) { return right; } if (left && !right) { return left; } return new ValueComponent_1.BinaryExpression(left, expr.operator.value, right); } else { // For comparison operators, handle right-associative parser structure return this.handleComparisonExpression(expr); } } /** * Handle comparison expressions, accounting for right-associative parser structure */ handleComparisonExpression(expr) { const left = this.visit(expr.left); // Check if the right side is a logical expression (AND/OR) using type-safe analysis if (ExpressionAnalyzer.isLogicalBinaryExpression(expr.right)) { // This is the problematic case: comparison = (logical expression) // We need to restructure this as: (comparison) logical (other parts) return this.restructureComparisonWithLogical(expr, left); } // Normal comparison processing const right = this.visit(expr.right); if (!left || !right) { return null; } return new ValueComponent_1.BinaryExpression(left, expr.operator.value, right); } /** * Restructure expressions like "id = (1 AND ...)" to "(id = 1) AND ..." */ restructureComparisonWithLogical(expr, processedLeft) { if (!processedLeft) { return null; } const rightBinary = expr.right; const logicalOperator = rightBinary.operator.value; // Process the logical expression's left side as the right side of our comparison const comparisonRight = this.visit(rightBinary.left); if (!comparisonRight) { // If the comparison right side contains only parameters, // try to process the logical expression's right side return this.visit(rightBinary.right); } // Create the restructured comparison: "id = 1" const restructuredComparison = new ValueComponent_1.BinaryExpression(processedLeft, expr.operator.value, comparisonRight); // Process the remaining logical expression's right side const logicalRight = this.visit(rightBinary.right); if (!logicalRight) { // Only the left comparison is valid return restructuredComparison; } // Combine: "(id = 1) AND (remaining expression)" return new ValueComponent_1.BinaryExpression(restructuredComparison, logicalOperator, logicalRight); } /** * Check if an operator is a logical operator */ /** * Check if the resulting expression would be nonsensical * This is a heuristic to detect cases like "name = age > 18" */ wouldCreateNonsensicalExpression(left, operator, right) { // Only apply this check for simple cases where we have a direct comparison operator // followed by another comparison operator in the right side if (OperatorPrecedence_1.OperatorPrecedence.isComparisonOperator(operator) && ExpressionAnalyzer.isComparisonBinaryExpression(right)) { const rightBinary = right; if (rightBinary.operator && OperatorPrecedence_1.OperatorPrecedence.isComparisonOperator(rightBinary.operator.value)) { // Additional check: make sure this isn't a legitimate nested case // If the left side is a simple column and the right side is a comparison, // this is likely nonsensical (like "name = age > 18") if (left.getKind().toString().includes('ColumnReference')) { return true; } } } return false; } /** * Check if a ValueComponent contains a ParameterExpression anywhere in its tree */ containsParameter(component) { return ParameterDetector.detect(component); } /** * Visit UnaryExpression node */ visitUnaryExpression(expr) { const expression = this.visit(expr.expression); // If the expression has been removed (contains only parameters), return null if (!expression) { return null; } return new ValueComponent_1.UnaryExpression(expr.operator.value, expression); } /** * Visit CaseExpression node */ visitCaseExpression(expr) { const condition = expr.condition ? this.visit(expr.condition) : null; const switchCase = this.visit(expr.switchCase); // If switchCase has been removed (contains only parameters), return null if (!switchCase) { return null; } return new ValueComponent_1.CaseExpression(condition, switchCase); } /** * Visit CaseKeyValuePair node */ visitCaseKeyValuePair(pair) { // If either key or value contains parameters, remove the entire pair if (this.containsParameter(pair.key) || this.containsParameter(pair.value)) { return null; } const key = this.visit(pair.key); const value = this.visit(pair.value); return new ValueComponent_1.CaseKeyValuePair(key, value); } /** * Visit SwitchCaseArgument node */ visitSwitchCaseArgument(arg) { // Process all case pairs, filter out null results const cases = arg.cases .map(caseItem => this.visit(caseItem)) .filter(caseItem => caseItem !== null); // Process the else value if it exists const elseValue = arg.elseValue ? this.visit(arg.elseValue) : null; // If no cases remain and no else value, remove the entire switch case if (cases.length === 0 && !elseValue) { return null; } return new ValueComponent_1.SwitchCaseArgument(cases, elseValue); } /** * Visit BetweenExpression node */ visitBetweenExpression(expr) { // If any part of the expression contains a parameter, remove the entire expression if (this.containsParameter(expr.expression) || this.containsParameter(expr.lower) || this.containsParameter(expr.upper)) { return null; } const expression = this.visit(expr.expression); const lower = this.visit(expr.lower); const upper = this.visit(expr.upper); return new ValueComponent_1.BetweenExpression(expression, lower, upper, expr.negated); } /** * Visit FunctionCall node */ visitFunctionCall(call) { const argument = call.argument ? this.visit(call.argument) : null; const over = call.over ? this.visit(call.over) : null; return new ValueComponent_1.FunctionCall(call.qualifiedName.namespaces, call.qualifiedName.name, argument, over); } /** * Visit ArrayExpression node */ visitArrayExpression(expr) { const expression = this.visit(expr.expression); // If the expression has been removed (contains only parameters), return null if (!expression) { return null; } return new ValueComponent_1.ArrayExpression(expression); } /** * Visit TupleExpression node */ visitTupleExpression(expr) { const values = expr.values .map(value => this.visit(value)) .filter(value => value !== null); return new ValueComponent_1.TupleExpression(values); } /** * Visit CastExpression node */ visitCastExpression(expr) { // If the input contains a parameter, remove the entire expression if (this.containsParameter(expr.input)) { return null; } const input = this.visit(expr.input); const castType = this.visit(expr.castType); // If the input has been removed, return null if (!input) { return null; } return new ValueComponent_1.CastExpression(input, castType); } /** * Visit WindowFrameExpression node */ visitWindowFrameExpression(expr) { const partition = expr.partition ? this.visit(expr.partition) : null; const order = expr.order ? this.visit(expr.order) : null; const frameSpec = expr.frameSpec ? this.visit(expr.frameSpec) : null; return new ValueComponent_1.WindowFrameExpression(partition, order, frameSpec); } /** * Visit WindowFrameSpec node */ visitWindowFrameSpec(spec) { return spec; } /** * Visit TypeValue node */ visitTypeValue(type) { const argument = type.argument ? this.visit(type.argument) : null; return new ValueComponent_1.TypeValue(type.qualifiedName.namespaces, type.qualifiedName.name, argument); } /** * Visit GroupByClause node */ visitGroupByClause(clause) { if (!clause.grouping || clause.grouping.length === 0) { return null; } const grouping = clause.grouping .map(expr => this.visit(expr)) .filter(expr => expr !== null); if (grouping.length === 0) { return null; } return new Clause_1.GroupByClause(grouping); } /** * Visit HavingClause node */ visitHavingClause(clause) { const condition = this.visit(clause.condition); // If the condition has been removed (contains only parameters), return null if (!condition) { return null; } return new Clause_1.HavingClause(condition); } /** * Visit OrderByClause node */ visitOrderByClause(clause) { const items = clause.order .map((item) => this.visit(item)) .filter((item) => item !== null); return new Clause_1.OrderByClause(items); } /** * Visit OrderByItem node */ visitOrderByItem(item) { const value = this.visit(item.value); return new Clause_1.OrderByItem(value, item.sortDirection, item.nullsPosition); } /** * Visit WindowFrameClause node */ visitWindowFrameClause(clause) { const expression = this.visit(clause.expression); return new Clause_1.WindowFrameClause(clause.name.name, expression); } /** * Visit WindowsClause node */ visitWindowsClause(clause) { const windows = clause.windows.map(window => this.visit(window)); return new Clause_1.WindowsClause(windows); } /** * Visit LimitClause node */ visitLimitClause(clause) { const value = this.visit(clause.value); return new Clause_1.LimitClause(value); } /** * Visit OffsetClause node */ visitOffsetClause(clause) { const value = this.visit(clause.value); return new Clause_1.OffsetClause(value); } /** * Visit FetchClause node */ visitFetchClause(clause) { const expression = this.visit(clause.expression); return new Clause_1.FetchClause(expression); } /** * Visit FetchExpression node */ visitFetchExpression(expression) { const count = this.visit(expression.count); return new Clause_1.FetchExpression(expression.type, count, expression.unit); } /** * Static method to apply parameter removal transformation on an SQL AST * @param node The SQL AST node to transform * @returns The transformed SQL AST with parameter expressions removed */ static remove(node) { const remover = new ParameterRemover(); return remover.visit(node); } } exports.ParameterRemover = ParameterRemover; //# sourceMappingURL=ParameterRemover.js.map