UNPKG

rawsql-ts

Version:

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

200 lines (199 loc) 6.87 kB
import { SelectQuery } from "../models/SelectQuery"; import { LineColumn } from "../utils/LexemeCursor"; /** * A utility class for renaming Common Table Expressions (CTEs) in SQL queries. * * This class provides functionality to safely rename CTEs while automatically updating * all column references and table references throughout the query, including within * nested CTE definitions and subqueries. * * @example * ```typescript * import { CTERenamer, SelectQueryParser } from 'rawsql-ts'; * * const sql = ` * WITH user_data AS ( * SELECT id, name FROM users * ), * order_summary AS ( * SELECT user_data.id, COUNT(*) as order_count * FROM user_data * JOIN orders ON user_data.id = orders.user_id * GROUP BY user_data.id * ) * SELECT * FROM order_summary * `; * * const query = SelectQueryParser.parse(sql); * const renamer = new CTERenamer(); * * // Rename 'user_data' to 'customer_data' * renamer.renameCTE(query, 'user_data', 'customer_data'); * * // All references are automatically updated: * // - CTE definition: WITH customer_data AS (...) * // - Column references: customer_data.id * // - Table references: FROM customer_data * ``` * * @example * ```typescript * // Error handling * try { * renamer.renameCTE(query, 'nonexistent_cte', 'new_name'); * } catch (error) { * console.error(error.message); // "CTE 'nonexistent_cte' does not exist" * } * * try { * renamer.renameCTE(query, 'existing_cte', 'already_exists'); * } catch (error) { * console.error(error.message); // "CTE 'already_exists' already exists" * } * ``` * * Related tests: packages/core/tests/transformers/CTERenamer.test.ts * @since 0.11.16 */ export declare class CTERenamer { private dependencyAnalyzer; private columnReferenceCollector; private tableSourceCollector; private keywordParser; /** * Creates a new instance of CTERenamer. * * The constructor initializes internal collectors and analyzers needed for * comprehensive CTE renaming operations. */ constructor(); /** * Renames a Common Table Expression (CTE) and updates all references to it. * * This method performs a comprehensive rename operation that includes: * - Updating the CTE definition name in the WITH clause * - Updating all column references (e.g., `old_name.column` -> `new_name.column`) * - Updating all table references in FROM and JOIN clauses * - Processing references within nested CTEs and subqueries * * @param query - The SQL query containing the CTE to rename. Can be either SimpleSelectQuery or BinarySelectQuery (UNION/INTERSECT/EXCEPT). * @param oldName - The current name of the CTE to rename. * @param newName - The new name for the CTE. * * @throws {Error} When the specified CTE does not exist in the query. * @throws {Error} When a CTE with the new name already exists. * @throws {Error} When the query type is not supported (not a SelectQuery). * * @example * ```typescript * const renamer = new CTERenamer(); * * // Basic usage * renamer.renameCTE(query, 'old_cte_name', 'new_cte_name'); * * // With error handling * try { * renamer.renameCTE(query, 'user_data', 'customer_data'); * } catch (error) { * if (error.message.includes('does not exist')) { * console.log('CTE not found'); * } else if (error.message.includes('already exists')) { * console.log('Name conflict'); * } * } * ``` * * Related tests: packages/core/tests/transformers/CTERenamer.test.ts * @since 0.11.16 */ renameCTE(query: SelectQuery, oldName: string, newName: string): void; /** * Validates input parameters for CTE renaming. */ private validateInputs; /** * Handles CTE renaming for SimpleSelectQuery. */ private renameInSimpleQuery; /** * Handles CTE renaming for BinarySelectQuery. */ private renameInBinaryQuery; /** * Recursively handles CTE renaming for any SelectQuery type. */ private renameInSelectQuery; /** * Renames the CTE definition in the WITH clause. */ private renameCTEDefinition; /** * Updates all references to the old CTE name (column references and table sources). */ private updateAllReferences; /** * Updates table sources within CTE definitions that reference the old CTE name. * This method manually traverses CTE internals to avoid infinite recursion * that occurs when using TableSourceCollector with selectableOnly=false. */ private updateTableSourcesInCTEs; /** * Updates table sources in a specific query (used for CTE internals). */ private updateTableSourcesInQuery; /** * Updates a specific table source if it matches the old CTE name. */ private updateTableSource; /** * GUI-integrated CTE renaming with line/column position support. * * Designed for editor integration where users can right-click on CTE names * and rename them. Automatically detects the CTE name at the cursor position * and performs the rename operation. * * @param sql - The complete SQL string containing CTE definitions * @param position - Line and column position where the user clicked (1-based) * @param newName - The new name for the CTE * @returns The updated SQL string with the CTE renamed * * @throws {Error} When no CTE name is found at the specified position * @throws {Error} When the new name conflicts with existing CTE names * * @example * ```typescript * const sql = ` * WITH user_data AS (SELECT * FROM users), * order_data AS (SELECT * FROM orders) * SELECT * FROM user_data JOIN order_data ON ... * `; * * const renamer = new CTERenamer(); * // User right-clicks on 'user_data' at line 2, column 8 * const result = renamer.renameCTEAtPosition(sql, { line: 2, column: 8 }, 'customer_data'); * console.log(result); * // Returns SQL with 'user_data' renamed to 'customer_data' everywhere * ``` */ renameCTEAtPosition(sql: string, position: LineColumn, newName: string): string; /** * Check for naming conflicts with existing CTEs and reserved keywords. * @private */ private checkNameConflicts; /** * Checks if the new name conflicts with SQL keywords using the existing KeywordTrie. * @private */ private checkKeywordConflicts; /** * Fallback method for basic reserved keyword checking. * @private */ private isBasicReservedKeyword; /** * Check if a CTE name exists in the query. * @private */ private isCTENameInQuery; }