UNPKG

rawsql-ts

Version:

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

189 lines (188 loc) 6.38 kB
import { SimpleSelectQuery } from "../models/SimpleSelectQuery"; /** * Options for JoinAggregationDecomposer */ export interface JoinDecomposerOptions { /** Name for the detail CTE (default: "detail_data") */ detailCTEName?: string; } /** * Result of decomposition analysis (safe, no exceptions) */ export interface DecompositionAnalysisResult { /** Whether the query can be decomposed */ success: boolean; /** The decomposed query if successful */ decomposedQuery?: SimpleSelectQuery; /** Error message if failed */ error?: string; /** Known limitations that may affect the result */ limitations?: string[]; /** Metadata about the decomposition process */ metadata: { /** Number of JOINs found */ joinCount: number; /** Number of aggregation functions found */ aggregationCount: number; /** Columns included in detail CTE */ detailColumns: string[]; /** Whether HAVING clause exists */ hasHaving: boolean; /** Whether ORDER BY clause exists */ hasOrderBy: boolean; /** Whether window functions are present */ hasWindowFunctions: boolean; }; } /** * Error thrown when query decomposition fails */ export declare class DecompositionError extends Error { readonly originalQuery: SimpleSelectQuery; readonly cause?: Error | undefined; constructor(message: string, originalQuery: SimpleSelectQuery, cause?: Error | undefined); } /** * Decomposes queries that combine table joins with aggregations into separate detail and aggregation queries using CTEs * * This transformer separates JOIN operations from aggregation operations to make queries easier to debug: * - Detail query: Contains JOINs and column selection * - Aggregation query: Contains GROUP BY and aggregation functions, referencing the CTE * * Provides two patterns following existing codebase conventions: * - analyze(): Safe analysis (Result pattern like SelectQueryParser.analyze) * - decompose(): Direct decomposition with exceptions (Exception pattern like SelectQueryParser.parse) * * @example * ```typescript * const decomposer = new JoinAggregationDecomposer(); * * // Safe analysis (Result pattern) * const analysis = decomposer.analyze(query); * if (analysis.success) { * console.log('Can decompose with', analysis.metadata.joinCount, 'joins'); * if (analysis.limitations) { * console.log('Known limitations:', analysis.limitations); * } * } else { * console.log('Cannot decompose:', analysis.error); * } * * // Direct decomposition (Exception pattern) * try { * const decomposed = decomposer.decompose(query); * // Success: decomposed query ready to use * } catch (error) { * if (error instanceof DecompositionError) { * console.log('Decomposition failed:', error.message); * } * } * ``` */ export declare class JoinAggregationDecomposer { private readonly options; private readonly formatter; constructor(options?: JoinDecomposerOptions); /** * Analyzes a query for decomposition without throwing errors (safe analysis) * Follows the same pattern as SelectQueryParser.analyze() * * @param query The query to analyze * @returns Analysis result with success status, error information, and metadata */ analyze(query: SimpleSelectQuery): DecompositionAnalysisResult; /** * Decomposes a JOIN + aggregation query into separate detail and aggregation queries * Follows the same pattern as SelectQueryParser.parse() - throws on error * * @param query The query to decompose * @returns The decomposed query with CTE structure * @throws DecompositionError if the query cannot be decomposed or formatted */ decompose(query: SimpleSelectQuery): SimpleSelectQuery; /** * Gets validation error message without throwing (for analyze method) */ private getValidationError; /** * Performs the actual decomposition */ private performDecomposition; /** * Extracts metadata about the query */ private extractMetadata; /** * Detects known limitations based on metadata */ private detectLimitations; /** * Counts the number of JOINs in the query */ private countJoins; /** * Counts aggregation functions in the query */ private countAggregationFunctions; /** * Checks if query contains window functions */ private hasWindowFunctions; /** * Checks if an expression contains aggregation functions */ private containsAggregationFunction; /** * Checks if an expression contains window functions */ private containsWindowFunction; /** * Gets function name from FunctionCall */ private getFunctionName; /** * Extracts detail column names for metadata */ private extractDetailColumnNames; /** * Extracts columns needed for the detail CTE */ private extractDetailColumns; /** * Extracts column references from an expression */ private extractColumnsFromExpression; /** * Gets a unique key for a column reference */ private getColumnKey; /** * Builds the detail query (CTE content) */ private buildDetailQuery; /** * Builds the aggregation query that references the CTE */ private buildAggregationQuery; /** * Transforms an expression to reference CTE columns instead of original table columns */ private transformExpressionForCTE; } /** * Utility function to analyze a JOIN + aggregation query from SQL string (safe, no exceptions) * * @param sql The SQL string to parse and analyze * @param options Decomposer options * @returns Analysis result with success status, error information, and metadata */ export declare function analyzeJoinAggregation(sql: string, options?: JoinDecomposerOptions): DecompositionAnalysisResult; /** * Utility function to decompose a JOIN + aggregation query from SQL string * * @param sql The SQL string to parse and decompose * @param options Decomposer options * @returns The decomposed query * @throws DecompositionError if parsing or decomposition fails */ export declare function decomposeJoinAggregation(sql: string, options?: JoinDecomposerOptions): SimpleSelectQuery;