UNPKG

rawsql-ts

Version:

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

255 lines (254 loc) 9.46 kB
/** * Information about a CTE (Common Table Expression) region in SQL text. * Provides boundaries and content for SQL editor integration. * * @example * ```typescript * const region: CTERegion = { * name: 'monthly_sales', * startPosition: 5, * endPosition: 150, * sqlContent: 'SELECT id, name FROM users WHERE active = true' * }; * ``` */ export interface CTERegion { /** The name of the CTE (e.g., 'monthly_sales') */ name: string; /** Starting character position in the original SQL text (0-based) */ startPosition: number; /** Ending character position in the original SQL text (0-based) */ endPosition: number; /** The executable SQL content of the CTE (SELECT statement without CTE wrapper) */ sqlContent: string; } /** * Result of cursor position analysis for SQL editor integration. * Contains information about what SQL should be executed based on cursor position. * * @example * ```typescript * const info: CursorPositionInfo = { * isInCTE: true, * cteRegion: { name: 'users_cte', startPosition: 10, endPosition: 100, sqlContent: '...' }, * executableSQL: 'SELECT id, name FROM users WHERE active = true' * }; * ``` */ export interface CursorPositionInfo { /** Whether the cursor is currently positioned inside a CTE region */ isInCTE: boolean; /** The CTE region containing the cursor (null if cursor is not in a CTE) */ cteRegion: CTERegion | null; /** The SQL that should be executed based on cursor position (CTE content or main query) */ executableSQL: string | null; } /** * Utility class for detecting CTE (Common Table Expression) regions and extracting executable SQL. * * Designed for SQL editor features where users want to execute specific CTE parts based on cursor position. * This enables editors to provide "run current section" functionality that intelligently executes * either the CTE the cursor is in, or the main query. * * @example Basic usage - Analyze cursor position * ```typescript * const sql = ` * WITH users_cte AS ( * SELECT id, name FROM users WHERE active = true * ) * SELECT * FROM users_cte ORDER BY name * `; * * const cursorPosition = 50; // Inside the CTE * const analysis = CTERegionDetector.analyzeCursorPosition(sql, cursorPosition); * * if (analysis.isInCTE) { * console.log(`Execute CTE: ${analysis.cteRegion.name}`); * executeSQL(analysis.executableSQL); // Runs just the CTE SELECT * } * ``` * * @example Get all executable sections * ```typescript * const positions = CTERegionDetector.getCTEPositions(sql); * // Returns: [ * // { name: 'users_cte', startPosition: 17, type: 'CTE' }, * // { name: 'MAIN_QUERY', startPosition: 120, type: 'MAIN_QUERY' } * // ] * ``` */ export declare class CTERegionDetector { /** * Analyze cursor position and return information about the current context. * * This is the main method for SQL editor integration. It determines whether the cursor * is inside a CTE or the main query, and provides the appropriate executable SQL. * * @param sql - The complete SQL string to analyze * @param cursorPosition - The cursor position (0-based character offset) * @returns Analysis result containing context information and executable SQL * * @example * ```typescript * const sql = `WITH users AS (SELECT * FROM table) SELECT * FROM users`; * const analysis = CTERegionDetector.analyzeCursorPosition(sql, 25); * * if (analysis.isInCTE) { * console.log(`Cursor is in CTE: ${analysis.cteRegion.name}`); * executeSQL(analysis.executableSQL); // Execute just the CTE * } else { * console.log('Cursor is in main query'); * executeSQL(analysis.executableSQL); // Execute the full query * } * ``` */ static analyzeCursorPosition(sql: string, cursorPosition: number): CursorPositionInfo; /** * Get the CTE name at the specified cursor position (simplified interface). * * This method provides a simple interface for retrieving just the CTE name * without additional context information. * * @param sql - The SQL string to analyze * @param cursorPosition - The cursor position (0-based character offset) * @returns The CTE name if cursor is in a CTE, null otherwise * * @example * ```typescript * const sql = `WITH users AS (SELECT * FROM table) SELECT * FROM users`; * const cteName = CTERegionDetector.getCursorCte(sql, 25); * console.log(cteName); // "users" * ``` */ static getCursorCte(sql: string, cursorPosition: number): string | null; /** * Get the CTE name at the specified 2D coordinates (line, column). * * This method provides a convenient interface for editor integrations * that work with line/column coordinates instead of character positions. * * @param sql - The SQL string to analyze * @param line - The line number (1-based) * @param column - The column number (1-based) * @returns The CTE name if cursor is in a CTE, null otherwise * * @example * ```typescript * const sql = `WITH users AS (\n SELECT * FROM table\n) SELECT * FROM users`; * const cteName = CTERegionDetector.getCursorCteAt(sql, 2, 5); * console.log(cteName); // "users" * ``` */ static getCursorCteAt(sql: string, line: number, column: number): string | null; /** * Convert line/column coordinates to character position. * * @param text - The text to analyze * @param line - The line number (1-based) * @param column - The column number (1-based) * @returns The character position (0-based), or -1 if invalid coordinates */ private static lineColumnToPosition; /** * Convert character position to line/column coordinates. * * @param text - The text to analyze * @param position - The character position (0-based) * @returns Object with line and column (1-based), or null if invalid position */ static positionToLineColumn(text: string, position: number): { line: number; column: number; } | null; /** * Extract all CTE regions from SQL text with their boundaries and executable content. * * Parses the SQL to identify all Common Table Expressions and their locations, * providing the information needed for syntax highlighting, code folding, and selective execution. * * @param sql - The SQL string to analyze * @returns Array of CTE regions with their boundaries and content * * @example * ```typescript * const sql = ` * WITH * users AS (SELECT * FROM people), * orders AS (SELECT * FROM purchases) * SELECT * FROM users JOIN orders * `; * * const regions = CTERegionDetector.extractCTERegions(sql); * // Returns: [ * // { name: 'users', startPosition: 23, endPosition: 45, sqlContent: 'SELECT * FROM people' }, * // { name: 'orders', startPosition: 55, endPosition: 80, sqlContent: 'SELECT * FROM purchases' } * // ] * ``` */ static extractCTERegions(sql: string): CTERegion[]; /** * Find matching closing parenthesis for CTE definition */ private static findMatchingParen; /** * Extract the SQL content of a CTE (the SELECT statement inside parentheses) */ private static extractCTESQL; /** * Check if a SELECT lexeme is the main query SELECT (not inside a CTE) */ private static isMainQuerySelect; /** * Calculate extended CTE boundaries for better cursor position detection. * Extended boundaries include the space between CTEs and before the main query. */ private static calculateExtendedCTEBoundaries; /** * Find the start position of the main query after the last CTE */ private static findMainQueryStart; /** * Extract the main query part (non-CTE SQL) */ private static extractMainQuery; /** * Get a list of all executable sections (CTEs and main query) with their start positions. * * This method is particularly useful for building editor UI features such as: * - Dropdown menus for section selection * - Sidebar navigation for large queries * - Quick jump functionality * - "Run section" buttons * * @param sql - The SQL string to analyze * @returns Array of executable sections with their names, positions, and types * * @example * ```typescript * const sql = ` * WITH monthly_sales AS (SELECT ...), * yearly_summary AS (SELECT ...) * SELECT * FROM yearly_summary * `; * * const positions = CTERegionDetector.getCTEPositions(sql); * // Returns: [ * // { name: 'monthly_sales', startPosition: 17, type: 'CTE' }, * // { name: 'yearly_summary', startPosition: 55, type: 'CTE' }, * // { name: 'MAIN_QUERY', startPosition: 120, type: 'MAIN_QUERY' } * // ] * * // Use for editor UI * positions.forEach(section => { * addMenuItem(`${section.type}: ${section.name}`, () => { * jumpToPosition(section.startPosition); * }); * }); * ``` */ static getCTEPositions(sql: string): Array<{ name: string; startPosition: number; type: 'CTE' | 'MAIN_QUERY'; }>; }