import type { DatabaseClient } from '../database/database-client.interface'; import { QueryExecutor } from '../entity/db-context'; import type { OrderDirection } from '../entity/db-context'; import { Condition, UnwrapSelection } from './conditions'; import { DbCte } from './cte-builder'; /** * Join types supported when a CTE is the FROM root. * * Unlike the entity-anchored {@link JoinQueryBuilder} (which only models * `INNER`/`LEFT`), a CTE-rooted query can express the full set of SQL join * flavours — including `FULL OUTER` and `CROSS` — because both sides are * already materialized, independent relations (the CTE bodies). This is what * makes a `spend FULL OUTER JOIN current_tier ON TRUE` shape expressible. */ export type CteJoinType = 'INNER' | 'LEFT' | 'RIGHT' | 'FULL OUTER' | 'CROSS'; /** * A constant `TRUE` join predicate, for cross-product joins written as * `… JOIN … ON TRUE`. Equivalent to a `CROSS JOIN` but keeps the `ON` * keyword, which Postgres requires for `FULL OUTER JOIN` (a bare * `FULL OUTER JOIN` with no `ON`/`USING` is a syntax error). * * @example * cteBuilder * .selectFromCte(spendCte) * .fullOuterJoin(currentTierCte, onTrue(), (s, t) => ({ ... })) */ export declare function onTrue(): Condition; /** * A single joined CTE step (the right-hand relation + how it is attached). */ interface CteJoinStep { type: CteJoinType; cte: DbCte; /** ON predicate. Always undefined for `CROSS` joins. */ condition?: Condition; } /** * A query whose FROM root is a {@link DbCte} (rather than an entity table), * joined to one or more further CTEs with any SQL join flavour. * * This complements the entity-anchored `db..with(...).leftJoin(cte, …)` * path: there the FROM root must be a real table and joins are `INNER`/`LEFT` * only. Here the FROM root is itself a CTE and `FULL OUTER` / `RIGHT` / `CROSS` * joins (and `ON TRUE` predicates) are available — exactly what a * `WITH a AS (…), b AS (…) SELECT … FROM a FULL OUTER JOIN b ON TRUE` shape * needs. * * Parameter ordering: every CTE body's parameters are emitted first, in `WITH` * declaration order (root CTE, then each joined CTE), followed by any `ON` * predicate parameters — so the whole statement keeps a single, sequential * `$1..$n` numbering, matching how the entity-rooted CTE path orders params. * * @typeParam TRootColumns - the column shape of the root CTE * @typeParam TSelection - the projected output row shape (after `.select(...)`) */ export declare class CteRootQueryBuilder, TSelection = TRootColumns> { protected rootCte: DbCte; protected client: DatabaseClient; protected executor?: QueryExecutor | undefined; private joinSteps; private selector?; private orderByFields; private limitValue?; private offsetValue?; constructor(rootCte: DbCte, client: DatabaseClient, executor?: QueryExecutor | undefined); /** Override the per-query timeout (ms). Pass `0` to disable. */ withTimeout(timeoutMs: number): this; /** Flag this query as expected to finish within `expectedMs` (ms). */ expectedExecutionTime(expectedMs: number): this; /** * `INNER JOIN` another CTE. */ innerJoin>(cte: DbCte, condition: Condition): CteJoinedQueryBuilder; /** * `LEFT JOIN` another CTE. */ leftJoin>(cte: DbCte, condition: Condition): CteJoinedQueryBuilder; /** * `RIGHT JOIN` another CTE. */ rightJoin>(cte: DbCte, condition: Condition): CteJoinedQueryBuilder; /** * `FULL OUTER JOIN` another CTE. * * Postgres requires an `ON`/`USING` clause on a `FULL OUTER JOIN`, so pass a * predicate — use {@link onTrue} for the cross-product (`ON TRUE`) form that * keeps every row of both sides while pairing them up. */ fullOuterJoin>(cte: DbCte, condition: Condition): CteJoinedQueryBuilder; /** * `CROSS JOIN` another CTE (cartesian product, no `ON`). */ crossJoin>(cte: DbCte): CteJoinedQueryBuilder; /** * Project the root CTE's columns directly (no join). */ select(selector: (root: TRootColumns) => TNewSelection): CteRootQueryBuilder>; /** * Order the result. Selector returns one or more projected columns (by their * output alias) — `ORDER BY "alias"` — supporting the same shapes as the * other builders (`r => r.col`, `r => [a, b]`, `r => [[a, 'DESC']]`). */ orderBy(selector: (row: TSelection) => T): this; orderBy(selector: (row: TSelection) => T[]): this; orderBy(selector: (row: TSelection) => Array<[T, OrderDirection]>): this; /** Limit the result set. */ limit(count: number): this; /** Offset the result set. */ offset(count: number): this; private addJoin; /** @internal — used by the joined builder to share the build machinery. */ _getRootCte(): DbCte; /** @internal */ _setState(joinSteps: CteJoinStep[], selector: ((...sources: any[]) => any) | undefined, orderByFields: Array<{ table: string; field: string; direction: 'ASC' | 'DESC'; }>, limitValue: number | undefined, offsetValue: number | undefined): void; /** * Build the SQL + ordered parameter array for this CTE-rooted query. * @internal */ buildQuery(): { sql: string; params: any[]; }; /** Generate the SQL string (for debugging / assertions). */ toSql(): string; /** Execute and return all rows. */ toList(): Promise; /** Execute and return the first row, or null. */ first(): Promise; /** Evaluate the user selector against fresh CTE FieldRef proxies. */ protected evaluateSelection(): Record; } /** * The result of joining a CTE onto a CTE-rooted query. Carries the same build * machinery as {@link CteRootQueryBuilder} but its `.select(...)` selector * receives a FieldRef proxy per source (root first, then each joined CTE in * order), and further joins can still be chained. */ export declare class CteJoinedQueryBuilder, TRight extends Record, TSelection = TRootColumns & TRight> extends CteRootQueryBuilder { private _joinSteps; /** @internal */ _inheritJoins(steps: CteJoinStep[]): void; /** * Project columns from the root CTE plus every joined CTE. The selector is * called with `(root, ...joined)` FieldRef proxies in FROM declaration order. * * The common single-join case is fully typed: `(root, right)` where `right` * is the joined CTE ({@link TRight}). For 3+ way joins, the additional joined * sources arrive (in FROM order) as loosely-typed rest arguments. */ select(selector: (root: TRootColumns, right: TRight) => TNewSelection): CteRootQueryBuilder>; select(selector: (root: TRootColumns, ...joined: any[]) => TNewSelection): CteRootQueryBuilder>; /** * Typed `fullOuterJoin` that exposes both already-joined sources (root + * first right) to the predicate. (Re-declared so the chained right side keeps * a useful element type rather than collapsing to the base signature.) */ fullOuterJoin>(cte: DbCte, condition: Condition): CteJoinedQueryBuilder; } export {}; //# sourceMappingURL=cte-root-query.d.ts.map