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