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
TypeScript
/**
* 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';
}>;
}