UNPKG

rawsql-ts

Version:

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

177 lines (176 loc) 8.48 kB
import { CommonTable } from '../models/Clause'; import { JsonMapping } from './PostgresJsonQueryBuilder'; import { ProcessableEntity } from './PostgresObjectEntityCteBuilder'; /** * PostgreSQL-specific builder for creating CTEs for array entities (array relationships). * This class handles the creation of CTEs that build JSON/JSONB arrays for child entities, * processing them from the deepest level up to ensure proper dependency ordering. * * Features: * - Depth-based CTE naming (cte_array_depth_N) * - Row compression using GROUP BY operations * - JSONB/JSON array aggregation * - Hierarchical processing of nested arrays * - Column exclusion to avoid duplication * * Why depth calculation is critical: * 1. Array entities can be nested at multiple levels. We must process the deepest * (most distant) arrays first to ensure their JSON representations are available * when building their parent arrays. * 2. Array entity processing is essentially a row compression operation using GROUP BY. * Unlike parent entities which use column compression, arrays require grouping * to aggregate multiple rows into JSON arrays. * * Example hierarchy: * Order (root, depth 0) * └─ Items (array, depth 1) * └─ Details (array, depth 2) * * Processing order: depth 2 → depth 1 → depth 0 */ export declare class PostgresArrayEntityCteBuilder { private static readonly CTE_ARRAY_PREFIX; /** * Build CTEs for all array entities in the correct dependency order * @param ctesSoFar Array of CTEs built so far (starts with the initial CTE) * @param aliasOfCteToBuildUpon Alias of the CTE from which the current array CTE will select * @param allEntities Map of all entities in the mapping * @param mapping The JSON mapping configuration * @returns Object containing the updated list of all CTEs and the alias of the last CTE created */ buildArrayEntityCtes(ctesSoFar: CommonTable[], aliasOfCteToBuildUpon: string, allEntities: Map<string, ProcessableEntity>, mapping: JsonMapping): { updatedCtes: CommonTable[]; lastCteAlias: string; }; /** * Collect all array entities and calculate their depth from root. * * Depth calculation ensures proper processing order where deeper nested * arrays are processed first, making their aggregated data available * for parent array processing. * * @param mapping The JSON mapping configuration * @param allEntities Map of all entities in the mapping * @returns Array of array entity information with calculated depths, sorted deepest first */ private collectAndSortArrayEntities; /** * Group array entities by their depth level. * * Grouping by depth allows us to: * - Process all entities at the same level in a single CTE * - Optimize query performance by reducing the number of CTEs * - Maintain clear dependency ordering * * @param arrayInfos Array of array entity information with depths * @returns Map of depth level to entities at that depth */ private groupEntitiesByDepth; /** * Build a CTE that processes all array entities at a specific depth level. * * This method creates a single CTE that aggregates multiple array entities * at the same depth, using GROUP BY to compress rows into JSON arrays. * * @param infos Array entities at this depth level * @param currentCteAlias Alias of the CTE to build upon * @param currentCtes All CTEs built so far * @param depth Current depth level being processed * @param mapping JSON mapping configuration * @returns The new CTE and its alias */ private buildDepthCte; /** * Build JSON aggregation function for an array entity. * * This method creates a jsonb_agg or json_agg function call that aggregates * the entity's columns into a JSON array. It also handles nested relationships * by including child entity properties in the JSON object. * * @param entity The array entity being processed * @param nestedEntities All nested entities from the mapping * @param allEntities Map of all entities (not used in current implementation) * @returns Object containing the JSON aggregation function */ private buildAggregationDetailsForArrayEntity; /** * Collects array entity columns organized by depth for the GROUP BY exclusion strategy. * * This method creates a mapping from depth levels to sets of column names that belong to * array entities at each depth. This is used to determine which columns should be excluded * from GROUP BY clauses when performing array aggregation at specific depths. * * @param mapping The JSON mapping configuration containing all entities * @param currentDepth The current aggregation depth being processed * @returns A map where keys are depth levels and values are sets of column names */ private collectArrayEntityColumnsByDepth; /** * Calculates the depth of an entity in the hierarchy by traversing up to the root. * * @param entity The entity to calculate depth for * @param mapping The JSON mapping containing all entities * @returns The depth level (0 for root level, 1 for first level, etc.) */ private calculateEntityDepth; /** * Adds all columns from an entity to the specified depth set. * * @param entity The entity whose columns should be added * @param depth The depth level to add columns to * @param arrayEntitiesByDepth The map to update */ private addEntityColumnsToDepthSet; /** * Recursively collects columns from all descendant entities under a parent entity. * * This method ensures that all nested entities (at any depth) under an array entity * have their columns properly categorized by the array entity's depth level. * * @param parentEntityId The ID of the parent entity * @param targetDepth The depth level to assign collected columns to * @param mapping The JSON mapping containing all entities * @param arrayEntitiesByDepth The map to update with collected columns */ private collectDescendantColumns; /** * Processes SELECT variables to determine which should be included in GROUP BY clauses. * * This method implements the core logic for deciding which columns from previous CTEs * should be included in the GROUP BY clause when performing array aggregation. It handles * special cases for JSON columns and applies depth-based filtering to prevent over-grouping. * * @param prevSelects SELECT variables from the previous CTE * @param arrayColumns Columns that are being aggregated (should be excluded from GROUP BY) * @param arrayEntitiesByDepth Map of depth levels to their column sets * @param currentDepth The current aggregation depth being processed * @param selectItems Output array for SELECT items * @param groupByItems Output array for GROUP BY items */ private processSelectVariablesForGroupBy; /** * Determines whether a column should be included in the GROUP BY clause. * * This method applies depth-based filtering and special handling for JSON columns * to prevent over-grouping during array aggregation. It implements heuristics for * excluding columns that belong to nested entities within array contexts. * * @param columnName The name of the column to evaluate * @param arrayEntitiesByDepth Map of depth levels to their column sets * @param currentDepth The current aggregation depth * @returns True if the column should be included in GROUP BY, false otherwise */ private shouldIncludeColumnInGroupBy; /** * Applies heuristics to determine if an entity JSON column should be included in GROUP BY. * * This method uses entity numbering patterns to identify deeply nested entities * that should be excluded from GROUP BY when processing array aggregations. * This is a simplified heuristic approach that works for current use cases. * * @param columnName The JSON column name (expected format: entity_N_json) * @param currentDepth The current aggregation depth * @returns True if the JSON column should be included, false otherwise */ private shouldIncludeJsonColumn; }