import { ICollectionStrategy, CollectionStrategyType, CollectionAggregationConfig, CollectionAggregationResult } from '../collection-strategy.interface'; import { QueryContext } from '../query-builder'; /** * LATERAL JOIN-based collection strategy * * This strategy uses PostgreSQL LATERAL joins to efficiently fetch related records * for each parent row. LATERAL allows the subquery to reference columns from * preceding FROM items, enabling per-row subqueries. * * Benefits: * - Single query execution (like CTE) * - Can be more efficient for queries with LIMIT/OFFSET per parent * - Better query plan for certain data distributions * - Natural support for correlated subqueries * * Trade-offs: * - May be slower than CTE for large result sets without LIMIT * - Query plan depends heavily on indexes * * SQL Pattern: * ```sql * SELECT * "users"."id", "users"."username", * COALESCE("lateral_0".data, '[]'::jsonb) as "posts" * FROM "users" * LEFT JOIN LATERAL ( * SELECT json_agg( * json_build_object('id', "id", 'title', "title") * ORDER BY "views" DESC * ) as data * FROM ( * SELECT "id", "title", "views" * FROM "posts" * WHERE "posts"."user_id" = "users"."id" * AND "views" > $1 * ORDER BY "views" DESC * LIMIT 10 * ) sub * ) "lateral_0" ON true * ``` */ export declare class LateralCollectionStrategy implements ICollectionStrategy { getType(): CollectionStrategyType; requiresParentIds(): boolean; /** * Build the parent-correlation WHERE predicate for a collection LATERAL/correlated * subquery. Supports composite keys and constant FK predicates (literal markers * like `__LIT:true`). Falls back to the legacy single-column form when the * navigation metadata doesn't carry the array form. * * This is the load-bearing helper for the QA_GO-429 Bug D fix: navigation * properties may declare additional literal predicates beyond the column * equality (e.g. `withForeignKey: [col, isCurrent], withPrincipalKey: [id, true]`) * that must fire on every projection. Without this helper, the strategy * emitted a single hard-coded `fk = sourceTable.id` clause and silently * dropped the literal predicate, leaking SCD2-closed rows. */ private buildParentCorrelation; buildAggregation(config: CollectionAggregationConfig, context: QueryContext): CollectionAggregationResult; /** * Check if we can use a correlated subquery instead of LATERAL * This is more efficient for simple cases without LIMIT/OFFSET/ORDER BY */ private canUseCorrelatedSubquery; /** * Build a correlated subquery in SELECT instead of LATERAL JOIN * This pattern: (SELECT COALESCE(agg(...), default) FROM ...) * is often more efficient than: LEFT JOIN LATERAL (...) ON true */ private buildCorrelatedSubqueryAggregation; /** * Helper to collect nested CTE/LATERAL joins from selected fields * These are joins to CTEs or LATERAL subqueries created for nested collections */ private collectNestedCteJoins; /** * Build navigation JOINs SQL for multi-level navigation in collection queries */ private buildNavigationJoins; /** * Build navigation JOINs SQL with inner table alias mapping * Similar to buildNavigationJoins but uses innerTableAlias for the collection's own table * @param navigationJoins - The navigation joins to build * @param innerTableAlias - The alias used for the collection's target table (e.g., "lateral_0_posts") * @param targetTable - Optional: the original target table name (e.g., "posts") to map to innerTableAlias * @param context - Optional: QueryContext containing lateralTableAliasMap for nested lateral references */ private buildNavigationJoinsWithAlias; /** * Build JSONB aggregation using LATERAL */ private buildJsonbAggregation; /** * Build single JSON object aggregation using LATERAL (for firstOrDefault) * Returns a single JSON object or null, not an array. */ private buildSingleJsonAggregation; /** * Build array aggregation using LATERAL (for toNumberList/toStringList) */ private buildArrayAggregation; /** * Build scalar aggregation using LATERAL (COUNT, MIN, MAX, SUM) */ private buildScalarAggregation; } //# sourceMappingURL=lateral-collection-strategy.d.ts.map