linkgress-orm 0.4.36 → 0.4.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/entity/db-column.d.ts +13 -0
- package/dist/entity/db-column.d.ts.map +1 -1
- package/dist/entity/db-column.js.map +1 -1
- package/dist/entity/db-context.d.ts +47 -2
- package/dist/entity/db-context.d.ts.map +1 -1
- package/dist/entity/db-context.js +63 -0
- package/dist/entity/db-context.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/query/cte-builder.d.ts.map +1 -1
- package/dist/query/cte-builder.js +30 -6
- package/dist/query/cte-builder.js.map +1 -1
- package/dist/query/cte-root-query.d.ts +164 -0
- package/dist/query/cte-root-query.d.ts.map +1 -0
- package/dist/query/cte-root-query.js +398 -0
- package/dist/query/cte-root-query.js.map +1 -0
- package/package.json +1 -1
|
@@ -57,19 +57,43 @@ class DbCteBuilder {
|
|
|
57
57
|
paramCounter: this.paramOffset,
|
|
58
58
|
params: [],
|
|
59
59
|
};
|
|
60
|
-
|
|
61
|
-
const mockRow = query._createMockRow();
|
|
62
|
-
const selectionResult = query.selector(mockRow);
|
|
63
|
-
const sql = query.buildQuery(selectionResult, {
|
|
60
|
+
const queryContext = {
|
|
64
61
|
ctes: new Map(),
|
|
65
62
|
cteCounter: 0,
|
|
66
63
|
paramCounter: context.paramCounter,
|
|
67
64
|
allParams: context.params,
|
|
68
|
-
}
|
|
65
|
+
};
|
|
66
|
+
let sql;
|
|
67
|
+
let selectionResult;
|
|
68
|
+
// Grouped query builders (`.groupBy(...).select(...)`, possibly with a
|
|
69
|
+
// trailing `.leftJoin(...)`) render their body — including SUM/COUNT/MIN/MAX
|
|
70
|
+
// aggregates and the GROUP BY — through `buildCteQuery`. They do NOT expose
|
|
71
|
+
// `_createMockRow`/`selector`, so detect and handle them first. Column
|
|
72
|
+
// definitions / mappers come from `getSelectionMetadata`. This lets an
|
|
73
|
+
// aggregate query be used as a *plain* CTE (one row per group), distinct
|
|
74
|
+
// from `withAggregation` which folds the whole group into a json_agg array.
|
|
75
|
+
if (typeof query.buildCteQuery === 'function') {
|
|
76
|
+
const result = query.buildCteQuery(queryContext);
|
|
77
|
+
sql = result.sql;
|
|
78
|
+
selectionResult = typeof query.getSelectionMetadata === 'function'
|
|
79
|
+
? query.getSelectionMetadata()
|
|
80
|
+
: {};
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
// Standard SelectQueryBuilder — render via mock row + selector.
|
|
84
|
+
const mockRow = query._createMockRow();
|
|
85
|
+
selectionResult = query.selector(mockRow);
|
|
86
|
+
sql = query.buildQuery(selectionResult, queryContext).sql;
|
|
87
|
+
}
|
|
69
88
|
// Update parameter offset for next CTE
|
|
70
|
-
this.paramOffset =
|
|
89
|
+
this.paramOffset = queryContext.paramCounter;
|
|
71
90
|
// Create column definitions from the selection
|
|
72
91
|
const columnDefs = {};
|
|
92
|
+
if (selectionResult) {
|
|
93
|
+
for (const key of Object.keys(selectionResult)) {
|
|
94
|
+
columnDefs[key] = key;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
73
97
|
const cte = new DbCte(cteName, sql, context.params, columnDefs, selectionResult);
|
|
74
98
|
this.ctes.push(cte);
|
|
75
99
|
return { cte };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cte-builder.js","sourceRoot":"","sources":["../../src/query/cte-builder.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"cte-builder.js","sourceRoot":"","sources":["../../src/query/cte-builder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import type { DatabaseClient } from '../database/database-client.interface';
|
|
2
|
+
import { QueryExecutor } from '../entity/db-context';
|
|
3
|
+
import type { OrderDirection } from '../entity/db-context';
|
|
4
|
+
import { Condition, UnwrapSelection } from './conditions';
|
|
5
|
+
import { DbCte } from './cte-builder';
|
|
6
|
+
/**
|
|
7
|
+
* Join types supported when a CTE is the FROM root.
|
|
8
|
+
*
|
|
9
|
+
* Unlike the entity-anchored {@link JoinQueryBuilder} (which only models
|
|
10
|
+
* `INNER`/`LEFT`), a CTE-rooted query can express the full set of SQL join
|
|
11
|
+
* flavours — including `FULL OUTER` and `CROSS` — because both sides are
|
|
12
|
+
* already materialized, independent relations (the CTE bodies). This is what
|
|
13
|
+
* makes a `spend FULL OUTER JOIN current_tier ON TRUE` shape expressible.
|
|
14
|
+
*/
|
|
15
|
+
export type CteJoinType = 'INNER' | 'LEFT' | 'RIGHT' | 'FULL OUTER' | 'CROSS';
|
|
16
|
+
/**
|
|
17
|
+
* A constant `TRUE` join predicate, for cross-product joins written as
|
|
18
|
+
* `… JOIN … ON TRUE`. Equivalent to a `CROSS JOIN` but keeps the `ON`
|
|
19
|
+
* keyword, which Postgres requires for `FULL OUTER JOIN` (a bare
|
|
20
|
+
* `FULL OUTER JOIN` with no `ON`/`USING` is a syntax error).
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* cteBuilder
|
|
24
|
+
* .selectFromCte(spendCte)
|
|
25
|
+
* .fullOuterJoin(currentTierCte, onTrue(), (s, t) => ({ ... }))
|
|
26
|
+
*/
|
|
27
|
+
export declare function onTrue(): Condition;
|
|
28
|
+
/**
|
|
29
|
+
* A single joined CTE step (the right-hand relation + how it is attached).
|
|
30
|
+
*/
|
|
31
|
+
interface CteJoinStep {
|
|
32
|
+
type: CteJoinType;
|
|
33
|
+
cte: DbCte<any>;
|
|
34
|
+
/** ON predicate. Always undefined for `CROSS` joins. */
|
|
35
|
+
condition?: Condition;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* A query whose FROM root is a {@link DbCte} (rather than an entity table),
|
|
39
|
+
* joined to one or more further CTEs with any SQL join flavour.
|
|
40
|
+
*
|
|
41
|
+
* This complements the entity-anchored `db.<table>.with(...).leftJoin(cte, …)`
|
|
42
|
+
* path: there the FROM root must be a real table and joins are `INNER`/`LEFT`
|
|
43
|
+
* only. Here the FROM root is itself a CTE and `FULL OUTER` / `RIGHT` / `CROSS`
|
|
44
|
+
* joins (and `ON TRUE` predicates) are available — exactly what a
|
|
45
|
+
* `WITH a AS (…), b AS (…) SELECT … FROM a FULL OUTER JOIN b ON TRUE` shape
|
|
46
|
+
* needs.
|
|
47
|
+
*
|
|
48
|
+
* Parameter ordering: every CTE body's parameters are emitted first, in `WITH`
|
|
49
|
+
* declaration order (root CTE, then each joined CTE), followed by any `ON`
|
|
50
|
+
* predicate parameters — so the whole statement keeps a single, sequential
|
|
51
|
+
* `$1..$n` numbering, matching how the entity-rooted CTE path orders params.
|
|
52
|
+
*
|
|
53
|
+
* @typeParam TRootColumns - the column shape of the root CTE
|
|
54
|
+
* @typeParam TSelection - the projected output row shape (after `.select(...)`)
|
|
55
|
+
*/
|
|
56
|
+
export declare class CteRootQueryBuilder<TRootColumns extends Record<string, any>, TSelection = TRootColumns> {
|
|
57
|
+
protected rootCte: DbCte<TRootColumns>;
|
|
58
|
+
protected client: DatabaseClient;
|
|
59
|
+
protected executor?: QueryExecutor | undefined;
|
|
60
|
+
private joinSteps;
|
|
61
|
+
private selector?;
|
|
62
|
+
private orderByFields;
|
|
63
|
+
private limitValue?;
|
|
64
|
+
private offsetValue?;
|
|
65
|
+
constructor(rootCte: DbCte<TRootColumns>, client: DatabaseClient, executor?: QueryExecutor | undefined);
|
|
66
|
+
/** Override the per-query timeout (ms). Pass `0` to disable. */
|
|
67
|
+
withTimeout(timeoutMs: number): this;
|
|
68
|
+
/** Flag this query as expected to finish within `expectedMs` (ms). */
|
|
69
|
+
expectedExecutionTime(expectedMs: number): this;
|
|
70
|
+
/**
|
|
71
|
+
* `INNER JOIN` another CTE.
|
|
72
|
+
*/
|
|
73
|
+
innerJoin<TRight extends Record<string, any>>(cte: DbCte<TRight>, condition: Condition): CteJoinedQueryBuilder<TRootColumns, TRight>;
|
|
74
|
+
/**
|
|
75
|
+
* `LEFT JOIN` another CTE.
|
|
76
|
+
*/
|
|
77
|
+
leftJoin<TRight extends Record<string, any>>(cte: DbCte<TRight>, condition: Condition): CteJoinedQueryBuilder<TRootColumns, TRight>;
|
|
78
|
+
/**
|
|
79
|
+
* `RIGHT JOIN` another CTE.
|
|
80
|
+
*/
|
|
81
|
+
rightJoin<TRight extends Record<string, any>>(cte: DbCte<TRight>, condition: Condition): CteJoinedQueryBuilder<TRootColumns, TRight>;
|
|
82
|
+
/**
|
|
83
|
+
* `FULL OUTER JOIN` another CTE.
|
|
84
|
+
*
|
|
85
|
+
* Postgres requires an `ON`/`USING` clause on a `FULL OUTER JOIN`, so pass a
|
|
86
|
+
* predicate — use {@link onTrue} for the cross-product (`ON TRUE`) form that
|
|
87
|
+
* keeps every row of both sides while pairing them up.
|
|
88
|
+
*/
|
|
89
|
+
fullOuterJoin<TRight extends Record<string, any>>(cte: DbCte<TRight>, condition: Condition): CteJoinedQueryBuilder<TRootColumns, TRight>;
|
|
90
|
+
/**
|
|
91
|
+
* `CROSS JOIN` another CTE (cartesian product, no `ON`).
|
|
92
|
+
*/
|
|
93
|
+
crossJoin<TRight extends Record<string, any>>(cte: DbCte<TRight>): CteJoinedQueryBuilder<TRootColumns, TRight>;
|
|
94
|
+
/**
|
|
95
|
+
* Project the root CTE's columns directly (no join).
|
|
96
|
+
*/
|
|
97
|
+
select<TNewSelection>(selector: (root: TRootColumns) => TNewSelection): CteRootQueryBuilder<TRootColumns, UnwrapSelection<TNewSelection>>;
|
|
98
|
+
/**
|
|
99
|
+
* Order the result. Selector returns one or more projected columns (by their
|
|
100
|
+
* output alias) — `ORDER BY "alias"` — supporting the same shapes as the
|
|
101
|
+
* other builders (`r => r.col`, `r => [a, b]`, `r => [[a, 'DESC']]`).
|
|
102
|
+
*/
|
|
103
|
+
orderBy<T>(selector: (row: TSelection) => T): this;
|
|
104
|
+
orderBy<T>(selector: (row: TSelection) => T[]): this;
|
|
105
|
+
orderBy<T>(selector: (row: TSelection) => Array<[T, OrderDirection]>): this;
|
|
106
|
+
/** Limit the result set. */
|
|
107
|
+
limit(count: number): this;
|
|
108
|
+
/** Offset the result set. */
|
|
109
|
+
offset(count: number): this;
|
|
110
|
+
private addJoin;
|
|
111
|
+
/** @internal — used by the joined builder to share the build machinery. */
|
|
112
|
+
_getRootCte(): DbCte<TRootColumns>;
|
|
113
|
+
/** @internal */
|
|
114
|
+
_setState(joinSteps: CteJoinStep[], selector: ((...sources: any[]) => any) | undefined, orderByFields: Array<{
|
|
115
|
+
table: string;
|
|
116
|
+
field: string;
|
|
117
|
+
direction: 'ASC' | 'DESC';
|
|
118
|
+
}>, limitValue: number | undefined, offsetValue: number | undefined): void;
|
|
119
|
+
/**
|
|
120
|
+
* Build the SQL + ordered parameter array for this CTE-rooted query.
|
|
121
|
+
* @internal
|
|
122
|
+
*/
|
|
123
|
+
buildQuery(): {
|
|
124
|
+
sql: string;
|
|
125
|
+
params: any[];
|
|
126
|
+
};
|
|
127
|
+
/** Generate the SQL string (for debugging / assertions). */
|
|
128
|
+
toSql(): string;
|
|
129
|
+
/** Execute and return all rows. */
|
|
130
|
+
toList(): Promise<TSelection[]>;
|
|
131
|
+
/** Execute and return the first row, or null. */
|
|
132
|
+
first(): Promise<TSelection | null>;
|
|
133
|
+
/** Evaluate the user selector against fresh CTE FieldRef proxies. */
|
|
134
|
+
protected evaluateSelection(): Record<string, any>;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* The result of joining a CTE onto a CTE-rooted query. Carries the same build
|
|
138
|
+
* machinery as {@link CteRootQueryBuilder} but its `.select(...)` selector
|
|
139
|
+
* receives a FieldRef proxy per source (root first, then each joined CTE in
|
|
140
|
+
* order), and further joins can still be chained.
|
|
141
|
+
*/
|
|
142
|
+
export declare class CteJoinedQueryBuilder<TRootColumns extends Record<string, any>, TRight extends Record<string, any>, TSelection = TRootColumns & TRight> extends CteRootQueryBuilder<TRootColumns, TSelection> {
|
|
143
|
+
private _joinSteps;
|
|
144
|
+
/** @internal */
|
|
145
|
+
_inheritJoins(steps: CteJoinStep[]): void;
|
|
146
|
+
/**
|
|
147
|
+
* Project columns from the root CTE plus every joined CTE. The selector is
|
|
148
|
+
* called with `(root, ...joined)` FieldRef proxies in FROM declaration order.
|
|
149
|
+
*
|
|
150
|
+
* The common single-join case is fully typed: `(root, right)` where `right`
|
|
151
|
+
* is the joined CTE ({@link TRight}). For 3+ way joins, the additional joined
|
|
152
|
+
* sources arrive (in FROM order) as loosely-typed rest arguments.
|
|
153
|
+
*/
|
|
154
|
+
select<TNewSelection>(selector: (root: TRootColumns, right: TRight) => TNewSelection): CteRootQueryBuilder<TRootColumns, UnwrapSelection<TNewSelection>>;
|
|
155
|
+
select<TNewSelection>(selector: (root: TRootColumns, ...joined: any[]) => TNewSelection): CteRootQueryBuilder<TRootColumns, UnwrapSelection<TNewSelection>>;
|
|
156
|
+
/**
|
|
157
|
+
* Typed `fullOuterJoin` that exposes both already-joined sources (root +
|
|
158
|
+
* first right) to the predicate. (Re-declared so the chained right side keeps
|
|
159
|
+
* a useful element type rather than collapsing to the base signature.)
|
|
160
|
+
*/
|
|
161
|
+
fullOuterJoin<TThird extends Record<string, any>>(cte: DbCte<TThird>, condition: Condition): CteJoinedQueryBuilder<TRootColumns, TThird>;
|
|
162
|
+
}
|
|
163
|
+
export {};
|
|
164
|
+
//# sourceMappingURL=cte-root-query.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cte-root-query.d.ts","sourceRoot":"","sources":["../../src/query/cte-root-query.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CteJoinedQueryBuilder = exports.CteRootQueryBuilder = void 0;
|
|
4
|
+
exports.onTrue = onTrue;
|
|
5
|
+
const db_context_1 = require("../entity/db-context");
|
|
6
|
+
const conditions_1 = require("./conditions");
|
|
7
|
+
const query_utils_1 = require("./query-utils");
|
|
8
|
+
/** SQL keyword emitted for each {@link CteJoinType}. */
|
|
9
|
+
const CTE_JOIN_SQL = {
|
|
10
|
+
INNER: 'INNER JOIN',
|
|
11
|
+
LEFT: 'LEFT JOIN',
|
|
12
|
+
RIGHT: 'RIGHT JOIN',
|
|
13
|
+
'FULL OUTER': 'FULL OUTER JOIN',
|
|
14
|
+
CROSS: 'CROSS JOIN',
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* A constant `TRUE` join predicate, for cross-product joins written as
|
|
18
|
+
* `… JOIN … ON TRUE`. Equivalent to a `CROSS JOIN` but keeps the `ON`
|
|
19
|
+
* keyword, which Postgres requires for `FULL OUTER JOIN` (a bare
|
|
20
|
+
* `FULL OUTER JOIN` with no `ON`/`USING` is a syntax error).
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* cteBuilder
|
|
24
|
+
* .selectFromCte(spendCte)
|
|
25
|
+
* .fullOuterJoin(currentTierCte, onTrue(), (s, t) => ({ ... }))
|
|
26
|
+
*/
|
|
27
|
+
function onTrue() {
|
|
28
|
+
return (0, conditions_1.sql) `TRUE`;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Build a mock row that yields {@link FieldRef}s for a CTE's columns, qualified
|
|
32
|
+
* with the CTE's own name as the table alias. Mirrors
|
|
33
|
+
* `SelectQueryBuilder.createMockRowForCte` so column mappers / aggregation-array
|
|
34
|
+
* markers carried on the CTE's `selectionMetadata` survive into the projection.
|
|
35
|
+
*/
|
|
36
|
+
function createCteFieldRefProxy(cte) {
|
|
37
|
+
return new Proxy({}, {
|
|
38
|
+
get(_target, prop) {
|
|
39
|
+
if (typeof prop === 'symbol') {
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
if (cte.selectionMetadata && prop in cte.selectionMetadata) {
|
|
43
|
+
const value = cte.selectionMetadata[prop];
|
|
44
|
+
// SqlFragment / column with a fromDriver mapper — preserve it so the
|
|
45
|
+
// projection re-applies the mapper to the joined column.
|
|
46
|
+
if (typeof value === 'object' && value !== null && typeof value.getMapper === 'function') {
|
|
47
|
+
return {
|
|
48
|
+
__fieldName: prop,
|
|
49
|
+
__dbColumnName: prop,
|
|
50
|
+
__tableAlias: cte.name,
|
|
51
|
+
getMapper: () => value.getMapper(),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
// CTE aggregation-array marker (json_agg column) — preserve the inner
|
|
55
|
+
// metadata so nested items can be mapped.
|
|
56
|
+
if (typeof value === 'object' && value !== null && '__isAggregationArray' in value && value.__isAggregationArray) {
|
|
57
|
+
return {
|
|
58
|
+
__fieldName: prop,
|
|
59
|
+
__dbColumnName: prop,
|
|
60
|
+
__tableAlias: cte.name,
|
|
61
|
+
__isAggregationArray: true,
|
|
62
|
+
__innerSelectionMetadata: value.__innerSelectionMetadata,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
__fieldName: prop,
|
|
68
|
+
__dbColumnName: prop,
|
|
69
|
+
__tableAlias: cte.name,
|
|
70
|
+
};
|
|
71
|
+
},
|
|
72
|
+
has() {
|
|
73
|
+
return true;
|
|
74
|
+
},
|
|
75
|
+
ownKeys() {
|
|
76
|
+
return cte.columnDefs ? Object.keys(cte.columnDefs) : [];
|
|
77
|
+
},
|
|
78
|
+
getOwnPropertyDescriptor() {
|
|
79
|
+
return { enumerable: true, configurable: true };
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
const NUMERIC_REGEX = /^-?\d+(\.\d+)?$/;
|
|
84
|
+
/**
|
|
85
|
+
* A query whose FROM root is a {@link DbCte} (rather than an entity table),
|
|
86
|
+
* joined to one or more further CTEs with any SQL join flavour.
|
|
87
|
+
*
|
|
88
|
+
* This complements the entity-anchored `db.<table>.with(...).leftJoin(cte, …)`
|
|
89
|
+
* path: there the FROM root must be a real table and joins are `INNER`/`LEFT`
|
|
90
|
+
* only. Here the FROM root is itself a CTE and `FULL OUTER` / `RIGHT` / `CROSS`
|
|
91
|
+
* joins (and `ON TRUE` predicates) are available — exactly what a
|
|
92
|
+
* `WITH a AS (…), b AS (…) SELECT … FROM a FULL OUTER JOIN b ON TRUE` shape
|
|
93
|
+
* needs.
|
|
94
|
+
*
|
|
95
|
+
* Parameter ordering: every CTE body's parameters are emitted first, in `WITH`
|
|
96
|
+
* declaration order (root CTE, then each joined CTE), followed by any `ON`
|
|
97
|
+
* predicate parameters — so the whole statement keeps a single, sequential
|
|
98
|
+
* `$1..$n` numbering, matching how the entity-rooted CTE path orders params.
|
|
99
|
+
*
|
|
100
|
+
* @typeParam TRootColumns - the column shape of the root CTE
|
|
101
|
+
* @typeParam TSelection - the projected output row shape (after `.select(...)`)
|
|
102
|
+
*/
|
|
103
|
+
class CteRootQueryBuilder {
|
|
104
|
+
constructor(rootCte, client, executor) {
|
|
105
|
+
this.rootCte = rootCte;
|
|
106
|
+
this.client = client;
|
|
107
|
+
this.executor = executor;
|
|
108
|
+
this.joinSteps = [];
|
|
109
|
+
this.orderByFields = [];
|
|
110
|
+
}
|
|
111
|
+
/** Override the per-query timeout (ms). Pass `0` to disable. */
|
|
112
|
+
withTimeout(timeoutMs) {
|
|
113
|
+
this.executor = this.executor
|
|
114
|
+
? this.executor.withTimeout(timeoutMs)
|
|
115
|
+
: new db_context_1.QueryExecutor(this.client, undefined, timeoutMs);
|
|
116
|
+
return this;
|
|
117
|
+
}
|
|
118
|
+
/** Flag this query as expected to finish within `expectedMs` (ms). */
|
|
119
|
+
expectedExecutionTime(expectedMs) {
|
|
120
|
+
this.executor = this.executor
|
|
121
|
+
? this.executor.withExpectedExecutionTime(expectedMs)
|
|
122
|
+
: new db_context_1.QueryExecutor(this.client, undefined, undefined, expectedMs);
|
|
123
|
+
return this;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* `INNER JOIN` another CTE.
|
|
127
|
+
*/
|
|
128
|
+
innerJoin(cte, condition) {
|
|
129
|
+
return this.addJoin('INNER', cte, condition);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* `LEFT JOIN` another CTE.
|
|
133
|
+
*/
|
|
134
|
+
leftJoin(cte, condition) {
|
|
135
|
+
return this.addJoin('LEFT', cte, condition);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* `RIGHT JOIN` another CTE.
|
|
139
|
+
*/
|
|
140
|
+
rightJoin(cte, condition) {
|
|
141
|
+
return this.addJoin('RIGHT', cte, condition);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* `FULL OUTER JOIN` another CTE.
|
|
145
|
+
*
|
|
146
|
+
* Postgres requires an `ON`/`USING` clause on a `FULL OUTER JOIN`, so pass a
|
|
147
|
+
* predicate — use {@link onTrue} for the cross-product (`ON TRUE`) form that
|
|
148
|
+
* keeps every row of both sides while pairing them up.
|
|
149
|
+
*/
|
|
150
|
+
fullOuterJoin(cte, condition) {
|
|
151
|
+
return this.addJoin('FULL OUTER', cte, condition);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* `CROSS JOIN` another CTE (cartesian product, no `ON`).
|
|
155
|
+
*/
|
|
156
|
+
crossJoin(cte) {
|
|
157
|
+
return this.addJoin('CROSS', cte, undefined);
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Project the root CTE's columns directly (no join).
|
|
161
|
+
*/
|
|
162
|
+
select(selector) {
|
|
163
|
+
const next = new CteRootQueryBuilder(this.rootCte, this.client, this.executor);
|
|
164
|
+
next.joinSteps = this.joinSteps;
|
|
165
|
+
next.selector = selector;
|
|
166
|
+
next.orderByFields = this.orderByFields;
|
|
167
|
+
next.limitValue = this.limitValue;
|
|
168
|
+
next.offsetValue = this.offsetValue;
|
|
169
|
+
return next;
|
|
170
|
+
}
|
|
171
|
+
orderBy(selector) {
|
|
172
|
+
const mockRow = new Proxy({}, {
|
|
173
|
+
get: (_t, prop) => {
|
|
174
|
+
if (typeof prop === 'symbol') {
|
|
175
|
+
return undefined;
|
|
176
|
+
}
|
|
177
|
+
return { __fieldName: prop, __dbColumnName: prop };
|
|
178
|
+
},
|
|
179
|
+
has: () => true,
|
|
180
|
+
});
|
|
181
|
+
const result = selector(mockRow);
|
|
182
|
+
this.orderByFields = [];
|
|
183
|
+
(0, query_utils_1.parseOrderBy)(result, this.orderByFields, undefined, () => '');
|
|
184
|
+
return this;
|
|
185
|
+
}
|
|
186
|
+
/** Limit the result set. */
|
|
187
|
+
limit(count) {
|
|
188
|
+
this.limitValue = count;
|
|
189
|
+
return this;
|
|
190
|
+
}
|
|
191
|
+
/** Offset the result set. */
|
|
192
|
+
offset(count) {
|
|
193
|
+
this.offsetValue = count;
|
|
194
|
+
return this;
|
|
195
|
+
}
|
|
196
|
+
addJoin(type, cte, condition) {
|
|
197
|
+
const next = new CteJoinedQueryBuilder(this.rootCte, this.client, this.executor);
|
|
198
|
+
next._inheritJoins([...this.joinSteps, { type, cte, condition }]);
|
|
199
|
+
return next;
|
|
200
|
+
}
|
|
201
|
+
/** @internal — used by the joined builder to share the build machinery. */
|
|
202
|
+
_getRootCte() {
|
|
203
|
+
return this.rootCte;
|
|
204
|
+
}
|
|
205
|
+
/** @internal */
|
|
206
|
+
_setState(joinSteps, selector, orderByFields, limitValue, offsetValue) {
|
|
207
|
+
this.joinSteps = joinSteps;
|
|
208
|
+
this.selector = selector;
|
|
209
|
+
this.orderByFields = orderByFields;
|
|
210
|
+
this.limitValue = limitValue;
|
|
211
|
+
this.offsetValue = offsetValue;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Build the SQL + ordered parameter array for this CTE-rooted query.
|
|
215
|
+
* @internal
|
|
216
|
+
*/
|
|
217
|
+
buildQuery() {
|
|
218
|
+
if (!this.selector) {
|
|
219
|
+
throw new Error('A selection is required. Call .select(...) before executing a CTE-rooted query.');
|
|
220
|
+
}
|
|
221
|
+
const params = [];
|
|
222
|
+
// Parameters of every CTE body come first, in WITH declaration order
|
|
223
|
+
// (root, then each join). The bodies already carry sequential `$N`
|
|
224
|
+
// placeholders assigned by DbCteBuilder, so just concatenate their params.
|
|
225
|
+
params.push(...this.rootCte.params);
|
|
226
|
+
for (const step of this.joinSteps) {
|
|
227
|
+
params.push(...step.cte.params);
|
|
228
|
+
}
|
|
229
|
+
// The ON predicates are appended after all CTE-body params. Their next free
|
|
230
|
+
// placeholder index is therefore (paramsSoFar + 1).
|
|
231
|
+
const ctx = {
|
|
232
|
+
paramCounter: params.length + 1,
|
|
233
|
+
params,
|
|
234
|
+
};
|
|
235
|
+
// FROM root
|
|
236
|
+
let fromClause = `FROM "${this.rootCte.name}"`;
|
|
237
|
+
for (const step of this.joinSteps) {
|
|
238
|
+
const keyword = CTE_JOIN_SQL[step.type];
|
|
239
|
+
if (step.type === 'CROSS') {
|
|
240
|
+
fromClause += `\n${keyword} "${step.cte.name}"`;
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
const condBuilder = new conditions_1.ConditionBuilder();
|
|
244
|
+
const { sql: condSql, params: condParams, paramCounter } = condBuilder.build(step.condition, ctx.paramCounter);
|
|
245
|
+
ctx.paramCounter = paramCounter;
|
|
246
|
+
ctx.params.push(...condParams);
|
|
247
|
+
fromClause += `\n${keyword} "${step.cte.name}" ON ${condSql}`;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
// Build the WITH clause from every referenced CTE, in declaration order.
|
|
251
|
+
const cteDecls = [`"${this.rootCte.name}" AS (${this.rootCte.query})`];
|
|
252
|
+
for (const step of this.joinSteps) {
|
|
253
|
+
cteDecls.push(`"${step.cte.name}" AS (${step.cte.query})`);
|
|
254
|
+
}
|
|
255
|
+
// Build SELECT from the projection (root + joined CTE FieldRefs).
|
|
256
|
+
const selection = this.evaluateSelection();
|
|
257
|
+
const selectParts = buildSelectParts(selection, ctx, this.rootCte.name);
|
|
258
|
+
let orderByClause = '';
|
|
259
|
+
if (this.orderByFields.length > 0) {
|
|
260
|
+
const orderParts = this.orderByFields.map(({ field, direction }) => `"${field}" ${direction}`);
|
|
261
|
+
orderByClause = `\nORDER BY ${orderParts.join(', ')}`;
|
|
262
|
+
}
|
|
263
|
+
let limitClause = '';
|
|
264
|
+
if (this.limitValue !== undefined) {
|
|
265
|
+
limitClause = `\nLIMIT ${this.limitValue}`;
|
|
266
|
+
}
|
|
267
|
+
if (this.offsetValue !== undefined) {
|
|
268
|
+
limitClause += `\nOFFSET ${this.offsetValue}`;
|
|
269
|
+
}
|
|
270
|
+
const sqlText = `WITH ${cteDecls.join(', ')}\n` +
|
|
271
|
+
`SELECT ${selectParts.join(', ')}\n${fromClause}${orderByClause}${limitClause}`;
|
|
272
|
+
return { sql: sqlText, params: ctx.params };
|
|
273
|
+
}
|
|
274
|
+
/** Generate the SQL string (for debugging / assertions). */
|
|
275
|
+
toSql() {
|
|
276
|
+
return this.buildQuery().sql;
|
|
277
|
+
}
|
|
278
|
+
/** Execute and return all rows. */
|
|
279
|
+
async toList() {
|
|
280
|
+
const { sql: sqlText, params } = this.buildQuery();
|
|
281
|
+
const result = this.executor
|
|
282
|
+
? await this.executor.query(sqlText, params)
|
|
283
|
+
: await this.client.query(sqlText, params);
|
|
284
|
+
const selection = this.evaluateSelection();
|
|
285
|
+
return transformRows(result.rows, selection);
|
|
286
|
+
}
|
|
287
|
+
/** Execute and return the first row, or null. */
|
|
288
|
+
async first() {
|
|
289
|
+
const results = await this.limit(1).toList();
|
|
290
|
+
return results.length > 0 ? results[0] : null;
|
|
291
|
+
}
|
|
292
|
+
/** Evaluate the user selector against fresh CTE FieldRef proxies. */
|
|
293
|
+
evaluateSelection() {
|
|
294
|
+
const rootMock = createCteFieldRefProxy(this.rootCte);
|
|
295
|
+
const joinMocks = this.joinSteps.map(step => createCteFieldRefProxy(step.cte));
|
|
296
|
+
return this.selector(rootMock, ...joinMocks);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
exports.CteRootQueryBuilder = CteRootQueryBuilder;
|
|
300
|
+
/**
|
|
301
|
+
* The result of joining a CTE onto a CTE-rooted query. Carries the same build
|
|
302
|
+
* machinery as {@link CteRootQueryBuilder} but its `.select(...)` selector
|
|
303
|
+
* receives a FieldRef proxy per source (root first, then each joined CTE in
|
|
304
|
+
* order), and further joins can still be chained.
|
|
305
|
+
*/
|
|
306
|
+
class CteJoinedQueryBuilder extends CteRootQueryBuilder {
|
|
307
|
+
constructor() {
|
|
308
|
+
super(...arguments);
|
|
309
|
+
this._joinSteps = [];
|
|
310
|
+
}
|
|
311
|
+
/** @internal */
|
|
312
|
+
_inheritJoins(steps) {
|
|
313
|
+
this._joinSteps = steps;
|
|
314
|
+
this._setState(steps, undefined, [], undefined, undefined);
|
|
315
|
+
}
|
|
316
|
+
select(selector) {
|
|
317
|
+
const next = new CteRootQueryBuilder(this._getRootCte(), this.client, this.executor);
|
|
318
|
+
next._setState(this._joinSteps, selector, [], undefined, undefined);
|
|
319
|
+
return next;
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Typed `fullOuterJoin` that exposes both already-joined sources (root +
|
|
323
|
+
* first right) to the predicate. (Re-declared so the chained right side keeps
|
|
324
|
+
* a useful element type rather than collapsing to the base signature.)
|
|
325
|
+
*/
|
|
326
|
+
fullOuterJoin(cte, condition) {
|
|
327
|
+
return super.fullOuterJoin(cte, condition);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
exports.CteJoinedQueryBuilder = CteJoinedQueryBuilder;
|
|
331
|
+
/**
|
|
332
|
+
* Build SELECT list fragments from a projection object whose leaves are
|
|
333
|
+
* FieldRefs (qualified with their CTE/table alias), SqlFragments, or literals.
|
|
334
|
+
*/
|
|
335
|
+
function buildSelectParts(selection, ctx, defaultAlias) {
|
|
336
|
+
const parts = [];
|
|
337
|
+
for (const [key, value] of Object.entries(selection)) {
|
|
338
|
+
if (value instanceof conditions_1.SqlFragment) {
|
|
339
|
+
const fragmentSql = value.buildSql(ctx);
|
|
340
|
+
parts.push(`${fragmentSql} as "${key}"`);
|
|
341
|
+
}
|
|
342
|
+
else if (typeof value === 'object' && value !== null && '__dbColumnName' in value) {
|
|
343
|
+
const alias = value.__tableAlias || defaultAlias;
|
|
344
|
+
parts.push(`"${alias}"."${value.__dbColumnName}" as "${key}"`);
|
|
345
|
+
}
|
|
346
|
+
else if (typeof value === 'string') {
|
|
347
|
+
// Bare column name string — qualify with the root alias.
|
|
348
|
+
parts.push(`"${defaultAlias}"."${value}" as "${key}"`);
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
// Literal value
|
|
352
|
+
ctx.params.push(value);
|
|
353
|
+
parts.push(`$${ctx.paramCounter++} as "${key}"`);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
return parts;
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Transform driver rows into the projected shape, re-applying any column /
|
|
360
|
+
* SqlFragment fromDriver mappers and coercing Postgres numeric strings to
|
|
361
|
+
* numbers. NULLs are preserved as `null` (faithful to the SQL — a CTE-rooted
|
|
362
|
+
* projection mirrors raw column output, unlike the entity path which maps
|
|
363
|
+
* absent columns to `undefined`).
|
|
364
|
+
*/
|
|
365
|
+
function transformRows(rows, selection) {
|
|
366
|
+
// Pre-analyze each selected field once.
|
|
367
|
+
const fields = [];
|
|
368
|
+
for (const [key, value] of Object.entries(selection)) {
|
|
369
|
+
let mapper;
|
|
370
|
+
if (value && typeof value === 'object' && typeof value.getMapper === 'function') {
|
|
371
|
+
let m = value.getMapper();
|
|
372
|
+
if (m && typeof m.getType === 'function') {
|
|
373
|
+
m = m.getType();
|
|
374
|
+
}
|
|
375
|
+
if (m && typeof m.fromDriver === 'function') {
|
|
376
|
+
mapper = m;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
fields.push({ key, mapper });
|
|
380
|
+
}
|
|
381
|
+
return rows.map(row => {
|
|
382
|
+
const out = {};
|
|
383
|
+
for (const { key, mapper } of fields) {
|
|
384
|
+
const raw = row[key];
|
|
385
|
+
if (mapper) {
|
|
386
|
+
out[key] = mapper.fromDriver(raw);
|
|
387
|
+
}
|
|
388
|
+
else if (typeof raw === 'string' && NUMERIC_REGEX.test(raw)) {
|
|
389
|
+
out[key] = +raw;
|
|
390
|
+
}
|
|
391
|
+
else {
|
|
392
|
+
out[key] = raw;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
return out;
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
//# sourceMappingURL=cte-root-query.js.map
|