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
TypeScript
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;
}