UNPKG

rawsql-ts

Version:

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

141 lines (140 loc) 5.83 kB
import { CommonTable } from '../models/Clause'; import { JsonMapping } from './PostgreJsonQueryBuilder'; /** * Entity with processing metadata */ export interface ProcessableEntity { id: string; name: string; columns: { [jsonKey: string]: string; }; isRoot: boolean; propertyName: string; parentId?: string; relationshipType?: "object" | "array"; } /** * PostgreSQL-specific builder for creating CTEs for object entities (object relationships). * This class handles the creation of CTEs that build JSON/JSONB objects for object entities, * processing them from the deepest level up to ensure proper dependency ordering. * * Features: * - Depth-based CTE naming (cte_object_depth_N) * - NULL handling for entity columns * - JSONB/JSON object construction * - Hierarchical processing of nested objects * * Why depth calculation is critical: * 1. Object entities can be nested at multiple levels. We must process the deepest * (most distant) objects first to ensure their JSON representations are available * when building their parent entities. * 2. Object entity processing is essentially a column compression operation. Entities * at the same depth level can be processed simultaneously since they don't depend * on each other. * * Example hierarchy: * Order (root, depth 0) * └─ Customer (depth 1) * └─ Address (depth 2) * └─ Shipping (depth 1) * └─ Carrier (depth 2) * * Processing order: depth 2 → depth 1 → depth 0 */ export declare class PostgresObjectEntityCteBuilder { private static readonly JSON_COLUMN_SUFFIX; private static readonly CTE_OBJECT_PREFIX; private static readonly WILDCARD_COLUMN; /** * Build CTEs for all object entities in the correct dependency order * @param initialCte The starting CTE containing all raw data * @param allEntities Map of all entities in the mapping * @param mapping The JSON mapping configuration * @returns Array of CTEs and the alias of the last CTE created */ buildObjectEntityCtes(initialCte: CommonTable, allEntities: Map<string, ProcessableEntity>, mapping: JsonMapping): { ctes: CommonTable[]; lastCteAlias: string; }; /** * Collect all object entities and calculate their depth from root. * * Depth calculation is crucial because: * - It determines the processing order (deepest first) * - It ensures dependencies are resolved before an entity is processed * - It allows parallel processing of entities at the same depth level * * @param mapping The JSON mapping configuration * @param allEntities Map of all entities in the mapping * @returns Array of object entity information with calculated depths */ private collectAndSortObjectEntities; /** * Group 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 parentInfos Array of parent entity information with depths * @returns Map of depth level to entities at that depth */ private groupEntitiesByDepth; /** * Build a CTE that processes all entities at a specific depth level */ private buildDepthCte; /** * Build JSON column for a single entity with NULL handling */ private buildEntityJsonColumn; /** * Prepare entity columns and NULL checks. * * This method extracts column data and creates NULL checks for each column. * The NULL checking is essential for handling outer joins correctly. * * In outer join scenarios, when there's no matching row in the joined table, * all columns from that table will be NULL. Instead of creating an empty object * with all NULL properties (e.g., {id: null, name: null, email: null}), * we want to represent the absence of the entity as NULL itself. * * This ensures cleaner JSON output where missing relationships are represented * as NULL rather than objects with all NULL fields. * * @param entity The entity whose columns are being processed * @returns Object containing arrays of JSON object arguments and NULL check conditions */ private prepareEntityColumns; /** * Add child object relationships to JSON object arguments. * * This method processes nested object-type entities that are direct children of the current entity. * For each child entity, it adds the property name and corresponding JSON column reference * to the arguments array that will be used to build the parent's JSON object. * * The child JSON columns are expected to already exist in the data source (created by deeper * level CTEs), as we process from the deepest level up to the root. * * Note: In this context, "child" refers to entities that have an object relationship (0..1) * with their parent. From a data perspective, these are typically entities referenced via * foreign keys, representing "parent" entities in traditional database terminology. * * @param entity The current entity being processed * @param jsonObjectArgs Array to which JSON object arguments will be added * @param mapping The JSON mapping configuration * @param allEntities Map of all entities in the mapping */ private addChildObjectRelationships; /** * Create JSON object function call */ private createJsonObject; /** * Build NULL condition from NULL checks */ private buildNullCondition; /** * Create CASE expression with NULL handling */ private createCaseExpression; }