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