metal-orm 1.0.15 → 1.0.17
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 +64 -61
- package/dist/decorators/index.cjs +490 -175
- package/dist/decorators/index.cjs.map +1 -1
- package/dist/decorators/index.d.cts +1 -5
- package/dist/decorators/index.d.ts +1 -5
- package/dist/decorators/index.js +490 -175
- package/dist/decorators/index.js.map +1 -1
- package/dist/index.cjs +1044 -483
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +67 -15
- package/dist/index.d.ts +67 -15
- package/dist/index.js +1033 -482
- package/dist/index.js.map +1 -1
- package/dist/{select-Bkv8g8u_.d.cts → select-BPCn6MOH.d.cts} +486 -32
- package/dist/{select-Bkv8g8u_.d.ts → select-BPCn6MOH.d.ts} +486 -32
- package/package.json +2 -1
- package/src/codegen/naming-strategy.ts +64 -0
- package/src/codegen/typescript.ts +48 -53
- package/src/core/ast/aggregate-functions.ts +50 -4
- package/src/core/ast/expression-builders.ts +22 -15
- package/src/core/ast/expression-nodes.ts +6 -0
- package/src/core/ddl/introspect/functions/postgres.ts +2 -6
- package/src/core/ddl/schema-generator.ts +3 -2
- package/src/core/ddl/schema-introspect.ts +1 -1
- package/src/core/dialect/abstract.ts +40 -8
- package/src/core/dialect/mssql/functions.ts +24 -15
- package/src/core/dialect/postgres/functions.ts +33 -24
- package/src/core/dialect/sqlite/functions.ts +19 -12
- package/src/core/functions/datetime.ts +2 -1
- package/src/core/functions/numeric.ts +2 -1
- package/src/core/functions/standard-strategy.ts +52 -12
- package/src/core/functions/text.ts +2 -1
- package/src/core/functions/types.ts +8 -8
- package/src/decorators/column.ts +13 -4
- package/src/index.ts +13 -5
- package/src/orm/domain-event-bus.ts +43 -25
- package/src/orm/entity-context.ts +30 -0
- package/src/orm/entity-meta.ts +42 -2
- package/src/orm/entity-metadata.ts +1 -6
- package/src/orm/entity.ts +88 -88
- package/src/orm/execute.ts +42 -25
- package/src/orm/execution-context.ts +18 -0
- package/src/orm/hydration-context.ts +16 -0
- package/src/orm/identity-map.ts +4 -0
- package/src/orm/interceptor-pipeline.ts +29 -0
- package/src/orm/lazy-batch.ts +6 -6
- package/src/orm/orm-session.ts +245 -0
- package/src/orm/orm.ts +58 -0
- package/src/orm/query-logger.ts +15 -0
- package/src/orm/relation-change-processor.ts +5 -1
- package/src/orm/relations/belongs-to.ts +45 -44
- package/src/orm/relations/has-many.ts +44 -43
- package/src/orm/relations/has-one.ts +140 -139
- package/src/orm/relations/many-to-many.ts +46 -45
- package/src/orm/runtime-types.ts +60 -2
- package/src/orm/transaction-runner.ts +7 -0
- package/src/orm/unit-of-work.ts +7 -1
- package/src/query-builder/insert-query-state.ts +13 -3
- package/src/query-builder/select-helpers.ts +50 -0
- package/src/query-builder/select.ts +616 -18
- package/src/query-builder/update-query-state.ts +31 -9
- package/src/schema/types.ts +16 -6
- package/src/orm/orm-context.ts +0 -159
|
@@ -1,494 +1,1092 @@
|
|
|
1
1
|
import { TableDef } from '../schema/table.js';
|
|
2
|
+
|
|
2
3
|
import { ColumnDef } from '../schema/column.js';
|
|
4
|
+
|
|
3
5
|
import { SelectQueryNode, SetOperationKind } from '../core/ast/query.js';
|
|
6
|
+
|
|
4
7
|
import { HydrationPlan } from '../core/hydration/types.js';
|
|
8
|
+
|
|
5
9
|
import {
|
|
10
|
+
|
|
6
11
|
ColumnNode,
|
|
12
|
+
|
|
7
13
|
ExpressionNode,
|
|
14
|
+
|
|
8
15
|
FunctionNode,
|
|
16
|
+
|
|
9
17
|
LiteralNode,
|
|
18
|
+
|
|
10
19
|
BinaryExpressionNode,
|
|
20
|
+
|
|
11
21
|
CaseExpressionNode,
|
|
22
|
+
|
|
12
23
|
WindowFunctionNode,
|
|
24
|
+
|
|
13
25
|
exists,
|
|
26
|
+
|
|
14
27
|
notExists
|
|
28
|
+
|
|
15
29
|
} from '../core/ast/expression.js';
|
|
30
|
+
|
|
16
31
|
import { CompiledQuery, Dialect } from '../core/dialect/abstract.js';
|
|
32
|
+
|
|
17
33
|
import { DialectKey, resolveDialectInput } from '../core/dialect/dialect-factory.js';
|
|
18
34
|
|
|
35
|
+
|
|
36
|
+
|
|
19
37
|
type SelectDialectInput = Dialect | DialectKey;
|
|
38
|
+
|
|
20
39
|
import { SelectQueryState } from './select-query-state.js';
|
|
40
|
+
|
|
21
41
|
import { HydrationManager } from './hydration-manager.js';
|
|
42
|
+
|
|
22
43
|
import {
|
|
44
|
+
|
|
23
45
|
resolveSelectQueryBuilderDependencies,
|
|
46
|
+
|
|
24
47
|
SelectQueryBuilderContext,
|
|
48
|
+
|
|
25
49
|
SelectQueryBuilderDependencies,
|
|
50
|
+
|
|
26
51
|
SelectQueryBuilderEnvironment
|
|
52
|
+
|
|
27
53
|
} from './select-query-builder-deps.js';
|
|
54
|
+
|
|
28
55
|
import { QueryAstService } from './query-ast-service.js';
|
|
29
|
-
import { ColumnSelector } from './column-selector.js';
|
|
30
|
-
import { RelationManager } from './relation-manager.js';
|
|
31
|
-
import { RelationIncludeOptions } from './relation-types.js';
|
|
32
|
-
import { JOIN_KINDS, JoinKind, ORDER_DIRECTIONS, OrderDirection } from '../core/sql/sql.js';
|
|
33
|
-
import { Entity, RelationMap } from '../schema/types.js';
|
|
34
|
-
import { OrmContext } from '../orm/orm-context.js';
|
|
35
|
-
import { executeHydrated } from '../orm/execute.js';
|
|
36
|
-
import { createJoinNode } from '../core/ast/join-node.js';
|
|
37
56
|
|
|
38
|
-
|
|
57
|
+
import { ColumnSelector } from './column-selector.js';
|
|
58
|
+
|
|
59
|
+
import { RelationManager } from './relation-manager.js';
|
|
60
|
+
|
|
61
|
+
import { RelationIncludeOptions } from './relation-types.js';
|
|
62
|
+
|
|
63
|
+
import type { RelationDef } from '../schema/relation.js';
|
|
64
|
+
|
|
65
|
+
import { JOIN_KINDS, JoinKind, ORDER_DIRECTIONS, OrderDirection } from '../core/sql/sql.js';
|
|
66
|
+
|
|
67
|
+
import { Entity, RelationMap, RelationTargetTable } from '../schema/types.js';
|
|
68
|
+
|
|
69
|
+
import { OrmSession } from '../orm/orm-session.ts';
|
|
70
|
+
|
|
71
|
+
import { ExecutionContext } from '../orm/execution-context.js';
|
|
72
|
+
|
|
73
|
+
import { HydrationContext } from '../orm/hydration-context.js';
|
|
74
|
+
|
|
75
|
+
import { executeHydrated, executeHydratedWithContexts } from '../orm/execute.js';
|
|
76
|
+
|
|
77
|
+
import { createJoinNode } from '../core/ast/join-node.js';
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
type ColumnSelectionValue = ColumnDef | FunctionNode | CaseExpressionNode | WindowFunctionNode;
|
|
81
|
+
|
|
82
|
+
type DeepSelectConfig<TTable extends TableDef> = {
|
|
83
|
+
root?: (keyof TTable['columns'] & string)[];
|
|
84
|
+
} & {
|
|
85
|
+
[K in keyof TTable['relations'] & string]?: (
|
|
86
|
+
keyof RelationTargetTable<TTable['relations'][K]>['columns'] & string
|
|
87
|
+
)[];
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
|
|
39
93
|
* Main query builder class for constructing SQL SELECT queries
|
|
94
|
+
|
|
40
95
|
* @typeParam T - Result type for projections (unused)
|
|
96
|
+
|
|
41
97
|
* @typeParam TTable - Table definition being queried
|
|
98
|
+
|
|
42
99
|
*/
|
|
100
|
+
|
|
43
101
|
export class SelectQueryBuilder<T = any, TTable extends TableDef = TableDef> {
|
|
102
|
+
|
|
44
103
|
private readonly env: SelectQueryBuilderEnvironment;
|
|
104
|
+
|
|
45
105
|
private readonly context: SelectQueryBuilderContext;
|
|
106
|
+
|
|
46
107
|
private readonly columnSelector: ColumnSelector;
|
|
108
|
+
|
|
47
109
|
private readonly relationManager: RelationManager;
|
|
110
|
+
|
|
48
111
|
private readonly lazyRelations: Set<string>;
|
|
49
112
|
|
|
113
|
+
|
|
114
|
+
|
|
50
115
|
/**
|
|
116
|
+
|
|
51
117
|
* Creates a new SelectQueryBuilder instance
|
|
118
|
+
|
|
52
119
|
* @param table - Table definition to query
|
|
120
|
+
|
|
53
121
|
* @param state - Optional initial query state
|
|
122
|
+
|
|
54
123
|
* @param hydration - Optional hydration manager
|
|
124
|
+
|
|
55
125
|
* @param dependencies - Optional query builder dependencies
|
|
126
|
+
|
|
56
127
|
*/
|
|
128
|
+
|
|
57
129
|
constructor(
|
|
130
|
+
|
|
58
131
|
table: TTable,
|
|
132
|
+
|
|
59
133
|
state?: SelectQueryState,
|
|
134
|
+
|
|
60
135
|
hydration?: HydrationManager,
|
|
136
|
+
|
|
61
137
|
dependencies?: Partial<SelectQueryBuilderDependencies>,
|
|
138
|
+
|
|
62
139
|
lazyRelations?: Set<string>
|
|
140
|
+
|
|
63
141
|
) {
|
|
142
|
+
|
|
64
143
|
const deps = resolveSelectQueryBuilderDependencies(dependencies);
|
|
144
|
+
|
|
65
145
|
this.env = { table, deps };
|
|
146
|
+
|
|
66
147
|
const initialState = state ?? deps.createState(table);
|
|
148
|
+
|
|
67
149
|
const initialHydration = hydration ?? deps.createHydration(table);
|
|
150
|
+
|
|
68
151
|
this.context = {
|
|
152
|
+
|
|
69
153
|
state: initialState,
|
|
154
|
+
|
|
70
155
|
hydration: initialHydration
|
|
156
|
+
|
|
71
157
|
};
|
|
158
|
+
|
|
72
159
|
this.lazyRelations = new Set(lazyRelations ?? []);
|
|
160
|
+
|
|
73
161
|
this.columnSelector = new ColumnSelector(this.env);
|
|
162
|
+
|
|
74
163
|
this.relationManager = new RelationManager(this.env);
|
|
164
|
+
|
|
75
165
|
}
|
|
76
166
|
|
|
167
|
+
|
|
168
|
+
|
|
77
169
|
private clone(
|
|
170
|
+
|
|
78
171
|
context: SelectQueryBuilderContext = this.context,
|
|
172
|
+
|
|
79
173
|
lazyRelations = new Set(this.lazyRelations)
|
|
174
|
+
|
|
80
175
|
): SelectQueryBuilder<T, TTable> {
|
|
176
|
+
|
|
81
177
|
return new SelectQueryBuilder(this.env.table as TTable, context.state, context.hydration, this.env.deps, lazyRelations);
|
|
178
|
+
|
|
82
179
|
}
|
|
83
180
|
|
|
181
|
+
|
|
182
|
+
|
|
84
183
|
private resolveQueryNode(query: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode): SelectQueryNode {
|
|
184
|
+
|
|
85
185
|
return typeof (query as any).getAST === 'function'
|
|
186
|
+
|
|
86
187
|
? (query as SelectQueryBuilder<any, TableDef<any>>).getAST()
|
|
188
|
+
|
|
87
189
|
: (query as SelectQueryNode);
|
|
190
|
+
|
|
88
191
|
}
|
|
89
192
|
|
|
193
|
+
|
|
194
|
+
|
|
90
195
|
private createChildBuilder<R, TChild extends TableDef>(table: TChild): SelectQueryBuilder<R, TChild> {
|
|
196
|
+
|
|
91
197
|
return new SelectQueryBuilder(table, undefined, undefined, this.env.deps);
|
|
198
|
+
|
|
92
199
|
}
|
|
93
200
|
|
|
201
|
+
|
|
202
|
+
|
|
94
203
|
private applyAst(
|
|
204
|
+
|
|
95
205
|
context: SelectQueryBuilderContext,
|
|
206
|
+
|
|
96
207
|
mutator: (service: QueryAstService) => SelectQueryState
|
|
208
|
+
|
|
97
209
|
): SelectQueryBuilderContext {
|
|
210
|
+
|
|
98
211
|
const astService = this.env.deps.createQueryAstService(this.env.table, context.state);
|
|
212
|
+
|
|
99
213
|
const nextState = mutator(astService);
|
|
214
|
+
|
|
100
215
|
return { state: nextState, hydration: context.hydration };
|
|
216
|
+
|
|
101
217
|
}
|
|
102
218
|
|
|
219
|
+
|
|
220
|
+
|
|
103
221
|
private applyJoin(
|
|
222
|
+
|
|
104
223
|
context: SelectQueryBuilderContext,
|
|
224
|
+
|
|
105
225
|
table: TableDef,
|
|
226
|
+
|
|
106
227
|
condition: BinaryExpressionNode,
|
|
228
|
+
|
|
107
229
|
kind: JoinKind
|
|
230
|
+
|
|
108
231
|
): SelectQueryBuilderContext {
|
|
232
|
+
|
|
109
233
|
const joinNode = createJoinNode(kind, table.name, condition);
|
|
234
|
+
|
|
110
235
|
return this.applyAst(context, service => service.withJoin(joinNode));
|
|
236
|
+
|
|
111
237
|
}
|
|
112
238
|
|
|
239
|
+
|
|
240
|
+
|
|
113
241
|
private applySetOperation(
|
|
242
|
+
|
|
114
243
|
operator: SetOperationKind,
|
|
244
|
+
|
|
115
245
|
query: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode
|
|
246
|
+
|
|
116
247
|
): SelectQueryBuilderContext {
|
|
248
|
+
|
|
117
249
|
const subAst = this.resolveQueryNode(query);
|
|
250
|
+
|
|
118
251
|
return this.applyAst(this.context, service => service.withSetOperation(operator, subAst));
|
|
252
|
+
|
|
119
253
|
}
|
|
120
254
|
|
|
255
|
+
|
|
256
|
+
|
|
121
257
|
/**
|
|
258
|
+
|
|
122
259
|
* Selects specific columns for the query
|
|
260
|
+
|
|
123
261
|
* @param columns - Record of column definitions, function nodes, case expressions, or window functions
|
|
262
|
+
|
|
124
263
|
* @returns New query builder instance with selected columns
|
|
264
|
+
|
|
125
265
|
*/
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
266
|
+
|
|
267
|
+
select(columns: Record<string, ColumnSelectionValue>): SelectQueryBuilder<T, TTable> {
|
|
268
|
+
|
|
269
|
+
return this.clone(this.columnSelector.select(this.context, columns));
|
|
270
|
+
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Selects columns from the root table by name (typed).
|
|
276
|
+
* @param cols - Column names on the root table
|
|
277
|
+
*/
|
|
278
|
+
selectColumns<K extends keyof TTable['columns'] & string>(...cols: K[]): SelectQueryBuilder<T, TTable> {
|
|
279
|
+
const selection: Record<string, ColumnDef> = {};
|
|
280
|
+
|
|
281
|
+
for (const key of cols) {
|
|
282
|
+
const col = this.env.table.columns[key];
|
|
283
|
+
if (!col) {
|
|
284
|
+
throw new Error(`Column '${key}' not found on table '${this.env.table.name}'`);
|
|
285
|
+
}
|
|
286
|
+
selection[key] = col;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return this.select(selection);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
|
|
129
293
|
|
|
130
294
|
/**
|
|
295
|
+
|
|
131
296
|
* Selects raw column expressions
|
|
297
|
+
|
|
132
298
|
* @param cols - Column expressions as strings
|
|
299
|
+
|
|
133
300
|
* @returns New query builder instance with raw column selections
|
|
301
|
+
|
|
134
302
|
*/
|
|
303
|
+
|
|
135
304
|
selectRaw(...cols: string[]): SelectQueryBuilder<T, TTable> {
|
|
305
|
+
|
|
136
306
|
return this.clone(this.columnSelector.selectRaw(this.context, cols));
|
|
307
|
+
|
|
137
308
|
}
|
|
138
309
|
|
|
310
|
+
|
|
311
|
+
|
|
139
312
|
/**
|
|
313
|
+
|
|
140
314
|
* Adds a Common Table Expression (CTE) to the query
|
|
315
|
+
|
|
141
316
|
* @param name - Name of the CTE
|
|
317
|
+
|
|
142
318
|
* @param query - Query builder or query node for the CTE
|
|
319
|
+
|
|
143
320
|
* @param columns - Optional column names for the CTE
|
|
321
|
+
|
|
144
322
|
* @returns New query builder instance with the CTE
|
|
323
|
+
|
|
145
324
|
*/
|
|
325
|
+
|
|
146
326
|
with(name: string, query: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode, columns?: string[]): SelectQueryBuilder<T, TTable> {
|
|
327
|
+
|
|
147
328
|
const subAst = this.resolveQueryNode(query);
|
|
329
|
+
|
|
148
330
|
const nextContext = this.applyAst(this.context, service => service.withCte(name, subAst, columns, false));
|
|
331
|
+
|
|
149
332
|
return this.clone(nextContext);
|
|
333
|
+
|
|
150
334
|
}
|
|
151
335
|
|
|
336
|
+
|
|
337
|
+
|
|
152
338
|
/**
|
|
339
|
+
|
|
153
340
|
* Adds a recursive Common Table Expression (CTE) to the query
|
|
341
|
+
|
|
154
342
|
* @param name - Name of the CTE
|
|
343
|
+
|
|
155
344
|
* @param query - Query builder or query node for the CTE
|
|
345
|
+
|
|
156
346
|
* @param columns - Optional column names for the CTE
|
|
347
|
+
|
|
157
348
|
* @returns New query builder instance with the recursive CTE
|
|
349
|
+
|
|
158
350
|
*/
|
|
351
|
+
|
|
159
352
|
withRecursive(name: string, query: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode, columns?: string[]): SelectQueryBuilder<T, TTable> {
|
|
353
|
+
|
|
160
354
|
const subAst = this.resolveQueryNode(query);
|
|
355
|
+
|
|
161
356
|
const nextContext = this.applyAst(this.context, service => service.withCte(name, subAst, columns, true));
|
|
357
|
+
|
|
162
358
|
return this.clone(nextContext);
|
|
359
|
+
|
|
163
360
|
}
|
|
164
361
|
|
|
362
|
+
|
|
363
|
+
|
|
165
364
|
/**
|
|
365
|
+
|
|
166
366
|
* Selects a subquery as a column
|
|
367
|
+
|
|
167
368
|
* @param alias - Alias for the subquery column
|
|
369
|
+
|
|
168
370
|
* @param sub - Query builder or query node for the subquery
|
|
371
|
+
|
|
169
372
|
* @returns New query builder instance with the subquery selection
|
|
373
|
+
|
|
170
374
|
*/
|
|
375
|
+
|
|
171
376
|
selectSubquery(alias: string, sub: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode): SelectQueryBuilder<T, TTable> {
|
|
377
|
+
|
|
172
378
|
const query = this.resolveQueryNode(sub);
|
|
379
|
+
|
|
173
380
|
return this.clone(this.columnSelector.selectSubquery(this.context, alias, query));
|
|
381
|
+
|
|
174
382
|
}
|
|
175
383
|
|
|
384
|
+
|
|
385
|
+
|
|
176
386
|
/**
|
|
387
|
+
|
|
177
388
|
* Adds an INNER JOIN to the query
|
|
389
|
+
|
|
178
390
|
* @param table - Table to join
|
|
391
|
+
|
|
179
392
|
* @param condition - Join condition expression
|
|
393
|
+
|
|
180
394
|
* @returns New query builder instance with the INNER JOIN
|
|
395
|
+
|
|
181
396
|
*/
|
|
397
|
+
|
|
182
398
|
innerJoin(table: TableDef, condition: BinaryExpressionNode): SelectQueryBuilder<T, TTable> {
|
|
399
|
+
|
|
183
400
|
const nextContext = this.applyJoin(this.context, table, condition, JOIN_KINDS.INNER);
|
|
401
|
+
|
|
184
402
|
return this.clone(nextContext);
|
|
403
|
+
|
|
185
404
|
}
|
|
186
405
|
|
|
406
|
+
|
|
407
|
+
|
|
187
408
|
/**
|
|
409
|
+
|
|
188
410
|
* Adds a LEFT JOIN to the query
|
|
411
|
+
|
|
189
412
|
* @param table - Table to join
|
|
413
|
+
|
|
190
414
|
* @param condition - Join condition expression
|
|
415
|
+
|
|
191
416
|
* @returns New query builder instance with the LEFT JOIN
|
|
417
|
+
|
|
192
418
|
*/
|
|
419
|
+
|
|
193
420
|
leftJoin(table: TableDef, condition: BinaryExpressionNode): SelectQueryBuilder<T, TTable> {
|
|
421
|
+
|
|
194
422
|
const nextContext = this.applyJoin(this.context, table, condition, JOIN_KINDS.LEFT);
|
|
423
|
+
|
|
195
424
|
return this.clone(nextContext);
|
|
425
|
+
|
|
196
426
|
}
|
|
197
427
|
|
|
428
|
+
|
|
429
|
+
|
|
198
430
|
/**
|
|
431
|
+
|
|
199
432
|
* Adds a RIGHT JOIN to the query
|
|
433
|
+
|
|
200
434
|
* @param table - Table to join
|
|
435
|
+
|
|
201
436
|
* @param condition - Join condition expression
|
|
437
|
+
|
|
202
438
|
* @returns New query builder instance with the RIGHT JOIN
|
|
439
|
+
|
|
203
440
|
*/
|
|
441
|
+
|
|
204
442
|
rightJoin(table: TableDef, condition: BinaryExpressionNode): SelectQueryBuilder<T, TTable> {
|
|
443
|
+
|
|
205
444
|
const nextContext = this.applyJoin(this.context, table, condition, JOIN_KINDS.RIGHT);
|
|
445
|
+
|
|
206
446
|
return this.clone(nextContext);
|
|
447
|
+
|
|
207
448
|
}
|
|
208
449
|
|
|
450
|
+
|
|
451
|
+
|
|
209
452
|
/**
|
|
453
|
+
|
|
210
454
|
* Matches records based on a relationship
|
|
455
|
+
|
|
211
456
|
* @param relationName - Name of the relationship to match
|
|
457
|
+
|
|
212
458
|
* @param predicate - Optional predicate expression
|
|
459
|
+
|
|
213
460
|
* @returns New query builder instance with the relationship match
|
|
461
|
+
|
|
214
462
|
*/
|
|
463
|
+
|
|
215
464
|
match(relationName: string, predicate?: ExpressionNode): SelectQueryBuilder<T, TTable> {
|
|
465
|
+
|
|
216
466
|
const nextContext = this.relationManager.match(this.context, relationName, predicate);
|
|
467
|
+
|
|
217
468
|
return this.clone(nextContext);
|
|
469
|
+
|
|
218
470
|
}
|
|
219
471
|
|
|
472
|
+
|
|
473
|
+
|
|
220
474
|
/**
|
|
475
|
+
|
|
221
476
|
* Joins a related table
|
|
477
|
+
|
|
222
478
|
* @param relationName - Name of the relationship to join
|
|
479
|
+
|
|
223
480
|
* @param joinKind - Type of join (defaults to INNER)
|
|
481
|
+
|
|
224
482
|
* @param extraCondition - Optional additional join condition
|
|
483
|
+
|
|
225
484
|
* @returns New query builder instance with the relationship join
|
|
485
|
+
|
|
226
486
|
*/
|
|
487
|
+
|
|
227
488
|
joinRelation(
|
|
489
|
+
|
|
228
490
|
relationName: string,
|
|
491
|
+
|
|
229
492
|
joinKind: JoinKind = JOIN_KINDS.INNER,
|
|
493
|
+
|
|
230
494
|
extraCondition?: ExpressionNode
|
|
495
|
+
|
|
231
496
|
): SelectQueryBuilder<T, TTable> {
|
|
497
|
+
|
|
232
498
|
const nextContext = this.relationManager.joinRelation(this.context, relationName, joinKind, extraCondition);
|
|
499
|
+
|
|
233
500
|
return this.clone(nextContext);
|
|
501
|
+
|
|
234
502
|
}
|
|
235
503
|
|
|
504
|
+
|
|
505
|
+
|
|
236
506
|
/**
|
|
507
|
+
|
|
237
508
|
* Includes related data in the query results
|
|
509
|
+
|
|
238
510
|
* @param relationName - Name of the relationship to include
|
|
511
|
+
|
|
239
512
|
* @param options - Optional include options
|
|
513
|
+
|
|
240
514
|
* @returns New query builder instance with the relationship inclusion
|
|
515
|
+
|
|
241
516
|
*/
|
|
517
|
+
|
|
242
518
|
include(relationName: string, options?: RelationIncludeOptions): SelectQueryBuilder<T, TTable> {
|
|
519
|
+
|
|
243
520
|
const nextContext = this.relationManager.include(this.context, relationName, options);
|
|
521
|
+
|
|
244
522
|
return this.clone(nextContext);
|
|
245
|
-
}
|
|
246
523
|
|
|
247
|
-
includeLazy<K extends keyof RelationMap<TTable>>(relationName: K): SelectQueryBuilder<T, TTable> {
|
|
248
|
-
const nextLazy = new Set(this.lazyRelations);
|
|
249
|
-
nextLazy.add(relationName as string);
|
|
250
|
-
return this.clone(this.context, nextLazy);
|
|
251
524
|
}
|
|
252
525
|
|
|
526
|
+
|
|
527
|
+
|
|
528
|
+
includeLazy<K extends keyof RelationMap<TTable>>(relationName: K): SelectQueryBuilder<T, TTable> {
|
|
529
|
+
|
|
530
|
+
const nextLazy = new Set(this.lazyRelations);
|
|
531
|
+
|
|
532
|
+
nextLazy.add(relationName as string);
|
|
533
|
+
|
|
534
|
+
return this.clone(this.context, nextLazy);
|
|
535
|
+
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
/**
|
|
539
|
+
* Selects columns for a related table in a single hop.
|
|
540
|
+
*/
|
|
541
|
+
selectRelationColumns<
|
|
542
|
+
K extends keyof TTable['relations'] & string,
|
|
543
|
+
TRel extends RelationDef = TTable['relations'][K],
|
|
544
|
+
TTarget extends TableDef = RelationTargetTable<TRel>,
|
|
545
|
+
C extends keyof TTarget['columns'] & string = keyof TTarget['columns'] & string
|
|
546
|
+
>(relationName: K, ...cols: C[]): SelectQueryBuilder<T, TTable> {
|
|
547
|
+
const relation = this.env.table.relations[relationName] as RelationDef | undefined;
|
|
548
|
+
if (!relation) {
|
|
549
|
+
throw new Error(`Relation '${relationName}' not found on table '${this.env.table.name}'`);
|
|
550
|
+
}
|
|
551
|
+
const target = relation.target;
|
|
552
|
+
|
|
553
|
+
for (const col of cols) {
|
|
554
|
+
if (!target.columns[col]) {
|
|
555
|
+
throw new Error(
|
|
556
|
+
`Column '${col}' not found on related table '${target.name}' for relation '${relationName}'`
|
|
557
|
+
);
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
return this.include(relationName as string, { columns: cols as string[] });
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
|
|
565
|
+
/**
|
|
566
|
+
* Convenience alias for selecting specific columns from a relation.
|
|
567
|
+
*/
|
|
568
|
+
includePick<
|
|
569
|
+
K extends keyof TTable['relations'] & string,
|
|
570
|
+
TRel extends RelationDef = TTable['relations'][K],
|
|
571
|
+
TTarget extends TableDef = RelationTargetTable<TRel>,
|
|
572
|
+
C extends keyof TTarget['columns'] & string = keyof TTarget['columns'] & string
|
|
573
|
+
>(relationName: K, cols: C[]): SelectQueryBuilder<T, TTable> {
|
|
574
|
+
return this.selectRelationColumns(relationName, ...cols);
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* Selects columns for the root table and relations from a single config object.
|
|
580
|
+
*/
|
|
581
|
+
selectColumnsDeep(config: DeepSelectConfig<TTable>): SelectQueryBuilder<T, TTable> {
|
|
582
|
+
let qb: SelectQueryBuilder<T, TTable> = this;
|
|
583
|
+
|
|
584
|
+
if (config.root?.length) {
|
|
585
|
+
qb = qb.selectColumns(...config.root);
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
for (const key of Object.keys(config) as (keyof typeof config)[]) {
|
|
589
|
+
if (key === 'root') continue;
|
|
590
|
+
const relName = key as keyof TTable['relations'] & string;
|
|
591
|
+
const cols = config[relName as keyof DeepSelectConfig<TTable>] as string[] | undefined;
|
|
592
|
+
if (!cols || !cols.length) continue;
|
|
593
|
+
qb = qb.selectRelationColumns(relName, ...(cols as string[]));
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
return qb;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
|
|
600
|
+
|
|
253
601
|
getLazyRelations(): (keyof RelationMap<TTable>)[] {
|
|
602
|
+
|
|
254
603
|
return Array.from(this.lazyRelations) as (keyof RelationMap<TTable>)[];
|
|
604
|
+
|
|
255
605
|
}
|
|
256
606
|
|
|
607
|
+
|
|
608
|
+
|
|
257
609
|
getTable(): TTable {
|
|
610
|
+
|
|
258
611
|
return this.env.table as TTable;
|
|
612
|
+
|
|
259
613
|
}
|
|
260
614
|
|
|
261
|
-
|
|
615
|
+
|
|
616
|
+
|
|
617
|
+
async execute(ctx: OrmSession): Promise<Entity<TTable>[]> {
|
|
618
|
+
|
|
262
619
|
return executeHydrated(ctx, this);
|
|
620
|
+
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
|
|
624
|
+
|
|
625
|
+
async executeWithContexts(execCtx: ExecutionContext, hydCtx: HydrationContext): Promise<Entity<TTable>[]> {
|
|
626
|
+
|
|
627
|
+
return executeHydratedWithContexts(execCtx, hydCtx, this);
|
|
628
|
+
|
|
263
629
|
}
|
|
264
630
|
|
|
631
|
+
|
|
632
|
+
|
|
265
633
|
/**
|
|
634
|
+
|
|
266
635
|
* Adds a WHERE condition to the query
|
|
636
|
+
|
|
267
637
|
* @param expr - Expression for the WHERE clause
|
|
638
|
+
|
|
268
639
|
* @returns New query builder instance with the WHERE condition
|
|
640
|
+
|
|
269
641
|
*/
|
|
642
|
+
|
|
270
643
|
where(expr: ExpressionNode): SelectQueryBuilder<T, TTable> {
|
|
644
|
+
|
|
271
645
|
const nextContext = this.applyAst(this.context, service => service.withWhere(expr));
|
|
646
|
+
|
|
272
647
|
return this.clone(nextContext);
|
|
648
|
+
|
|
273
649
|
}
|
|
274
650
|
|
|
651
|
+
|
|
652
|
+
|
|
275
653
|
/**
|
|
654
|
+
|
|
276
655
|
* Adds a GROUP BY clause to the query
|
|
656
|
+
|
|
277
657
|
* @param col - Column definition or column node to group by
|
|
658
|
+
|
|
278
659
|
* @returns New query builder instance with the GROUP BY clause
|
|
660
|
+
|
|
279
661
|
*/
|
|
662
|
+
|
|
280
663
|
groupBy(col: ColumnDef | ColumnNode): SelectQueryBuilder<T, TTable> {
|
|
664
|
+
|
|
281
665
|
const nextContext = this.applyAst(this.context, service => service.withGroupBy(col));
|
|
666
|
+
|
|
282
667
|
return this.clone(nextContext);
|
|
668
|
+
|
|
283
669
|
}
|
|
284
670
|
|
|
671
|
+
|
|
672
|
+
|
|
285
673
|
/**
|
|
674
|
+
|
|
286
675
|
* Adds a HAVING condition to the query
|
|
676
|
+
|
|
287
677
|
* @param expr - Expression for the HAVING clause
|
|
678
|
+
|
|
288
679
|
* @returns New query builder instance with the HAVING condition
|
|
680
|
+
|
|
289
681
|
*/
|
|
682
|
+
|
|
290
683
|
having(expr: ExpressionNode): SelectQueryBuilder<T, TTable> {
|
|
684
|
+
|
|
291
685
|
const nextContext = this.applyAst(this.context, service => service.withHaving(expr));
|
|
686
|
+
|
|
292
687
|
return this.clone(nextContext);
|
|
688
|
+
|
|
293
689
|
}
|
|
294
690
|
|
|
691
|
+
|
|
692
|
+
|
|
295
693
|
/**
|
|
694
|
+
|
|
296
695
|
* Adds an ORDER BY clause to the query
|
|
696
|
+
|
|
297
697
|
* @param col - Column definition or column node to order by
|
|
698
|
+
|
|
298
699
|
* @param direction - Order direction (defaults to ASC)
|
|
700
|
+
|
|
299
701
|
* @returns New query builder instance with the ORDER BY clause
|
|
702
|
+
|
|
300
703
|
*/
|
|
704
|
+
|
|
301
705
|
orderBy(col: ColumnDef | ColumnNode, direction: OrderDirection = ORDER_DIRECTIONS.ASC): SelectQueryBuilder<T, TTable> {
|
|
706
|
+
|
|
302
707
|
const nextContext = this.applyAst(this.context, service => service.withOrderBy(col, direction));
|
|
708
|
+
|
|
303
709
|
return this.clone(nextContext);
|
|
710
|
+
|
|
304
711
|
}
|
|
305
712
|
|
|
713
|
+
|
|
714
|
+
|
|
306
715
|
/**
|
|
716
|
+
|
|
307
717
|
* Adds a DISTINCT clause to the query
|
|
718
|
+
|
|
308
719
|
* @param cols - Columns to make distinct
|
|
720
|
+
|
|
309
721
|
* @returns New query builder instance with the DISTINCT clause
|
|
722
|
+
|
|
310
723
|
*/
|
|
724
|
+
|
|
311
725
|
distinct(...cols: (ColumnDef | ColumnNode)[]): SelectQueryBuilder<T, TTable> {
|
|
726
|
+
|
|
312
727
|
return this.clone(this.columnSelector.distinct(this.context, cols));
|
|
728
|
+
|
|
313
729
|
}
|
|
314
730
|
|
|
731
|
+
|
|
732
|
+
|
|
315
733
|
/**
|
|
734
|
+
|
|
316
735
|
* Adds a LIMIT clause to the query
|
|
736
|
+
|
|
317
737
|
* @param n - Maximum number of rows to return
|
|
738
|
+
|
|
318
739
|
* @returns New query builder instance with the LIMIT clause
|
|
740
|
+
|
|
319
741
|
*/
|
|
742
|
+
|
|
320
743
|
limit(n: number): SelectQueryBuilder<T, TTable> {
|
|
744
|
+
|
|
321
745
|
const nextContext = this.applyAst(this.context, service => service.withLimit(n));
|
|
746
|
+
|
|
322
747
|
return this.clone(nextContext);
|
|
748
|
+
|
|
323
749
|
}
|
|
324
750
|
|
|
751
|
+
|
|
752
|
+
|
|
325
753
|
/**
|
|
754
|
+
|
|
326
755
|
* Adds an OFFSET clause to the query
|
|
756
|
+
|
|
327
757
|
* @param n - Number of rows to skip
|
|
758
|
+
|
|
328
759
|
* @returns New query builder instance with the OFFSET clause
|
|
760
|
+
|
|
329
761
|
*/
|
|
762
|
+
|
|
330
763
|
offset(n: number): SelectQueryBuilder<T, TTable> {
|
|
764
|
+
|
|
331
765
|
const nextContext = this.applyAst(this.context, service => service.withOffset(n));
|
|
766
|
+
|
|
332
767
|
return this.clone(nextContext);
|
|
768
|
+
|
|
333
769
|
}
|
|
334
770
|
|
|
771
|
+
|
|
772
|
+
|
|
335
773
|
/**
|
|
774
|
+
|
|
336
775
|
* Combines this query with another using UNION
|
|
776
|
+
|
|
337
777
|
* @param query - Query to union with
|
|
778
|
+
|
|
338
779
|
* @returns New query builder instance with the set operation
|
|
780
|
+
|
|
339
781
|
*/
|
|
782
|
+
|
|
340
783
|
union(query: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode): SelectQueryBuilder<T, TTable> {
|
|
784
|
+
|
|
341
785
|
return this.clone(this.applySetOperation('UNION', query));
|
|
786
|
+
|
|
342
787
|
}
|
|
343
788
|
|
|
789
|
+
|
|
790
|
+
|
|
344
791
|
/**
|
|
792
|
+
|
|
345
793
|
* Combines this query with another using UNION ALL
|
|
794
|
+
|
|
346
795
|
* @param query - Query to union with
|
|
796
|
+
|
|
347
797
|
* @returns New query builder instance with the set operation
|
|
798
|
+
|
|
348
799
|
*/
|
|
800
|
+
|
|
349
801
|
unionAll(query: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode): SelectQueryBuilder<T, TTable> {
|
|
802
|
+
|
|
350
803
|
return this.clone(this.applySetOperation('UNION ALL', query));
|
|
804
|
+
|
|
351
805
|
}
|
|
352
806
|
|
|
807
|
+
|
|
808
|
+
|
|
353
809
|
/**
|
|
810
|
+
|
|
354
811
|
* Combines this query with another using INTERSECT
|
|
812
|
+
|
|
355
813
|
* @param query - Query to intersect with
|
|
814
|
+
|
|
356
815
|
* @returns New query builder instance with the set operation
|
|
816
|
+
|
|
357
817
|
*/
|
|
818
|
+
|
|
358
819
|
intersect(query: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode): SelectQueryBuilder<T, TTable> {
|
|
820
|
+
|
|
359
821
|
return this.clone(this.applySetOperation('INTERSECT', query));
|
|
822
|
+
|
|
360
823
|
}
|
|
361
824
|
|
|
825
|
+
|
|
826
|
+
|
|
362
827
|
/**
|
|
828
|
+
|
|
363
829
|
* Combines this query with another using EXCEPT
|
|
830
|
+
|
|
364
831
|
* @param query - Query to subtract
|
|
832
|
+
|
|
365
833
|
* @returns New query builder instance with the set operation
|
|
834
|
+
|
|
366
835
|
*/
|
|
836
|
+
|
|
367
837
|
except(query: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode): SelectQueryBuilder<T, TTable> {
|
|
838
|
+
|
|
368
839
|
return this.clone(this.applySetOperation('EXCEPT', query));
|
|
840
|
+
|
|
369
841
|
}
|
|
370
842
|
|
|
843
|
+
|
|
844
|
+
|
|
371
845
|
/**
|
|
846
|
+
|
|
372
847
|
* Adds a WHERE EXISTS condition to the query
|
|
848
|
+
|
|
373
849
|
* @param subquery - Subquery to check for existence
|
|
850
|
+
|
|
374
851
|
* @returns New query builder instance with the WHERE EXISTS condition
|
|
852
|
+
|
|
375
853
|
*/
|
|
854
|
+
|
|
376
855
|
whereExists(subquery: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode): SelectQueryBuilder<T, TTable> {
|
|
856
|
+
|
|
377
857
|
const subAst = this.resolveQueryNode(subquery);
|
|
858
|
+
|
|
378
859
|
return this.where(exists(subAst));
|
|
860
|
+
|
|
379
861
|
}
|
|
380
862
|
|
|
863
|
+
|
|
864
|
+
|
|
381
865
|
/**
|
|
866
|
+
|
|
382
867
|
* Adds a WHERE NOT EXISTS condition to the query
|
|
868
|
+
|
|
383
869
|
* @param subquery - Subquery to check for non-existence
|
|
870
|
+
|
|
384
871
|
* @returns New query builder instance with the WHERE NOT EXISTS condition
|
|
872
|
+
|
|
385
873
|
*/
|
|
874
|
+
|
|
386
875
|
whereNotExists(subquery: SelectQueryBuilder<any, TableDef<any>> | SelectQueryNode): SelectQueryBuilder<T, TTable> {
|
|
876
|
+
|
|
387
877
|
const subAst = this.resolveQueryNode(subquery);
|
|
878
|
+
|
|
388
879
|
return this.where(notExists(subAst));
|
|
880
|
+
|
|
389
881
|
}
|
|
390
882
|
|
|
883
|
+
|
|
884
|
+
|
|
391
885
|
/**
|
|
886
|
+
|
|
392
887
|
* Adds a WHERE EXISTS condition based on a relationship
|
|
888
|
+
|
|
393
889
|
* @param relationName - Name of the relationship to check
|
|
890
|
+
|
|
394
891
|
* @param callback - Optional callback to modify the relationship query
|
|
892
|
+
|
|
395
893
|
* @returns New query builder instance with the relationship existence check
|
|
894
|
+
|
|
396
895
|
*/
|
|
896
|
+
|
|
397
897
|
whereHas(
|
|
898
|
+
|
|
398
899
|
relationName: string,
|
|
900
|
+
|
|
399
901
|
callback?: <TChildTable extends TableDef>(
|
|
902
|
+
|
|
400
903
|
qb: SelectQueryBuilder<any, TChildTable>
|
|
904
|
+
|
|
401
905
|
) => SelectQueryBuilder<any, TChildTable>
|
|
906
|
+
|
|
402
907
|
): SelectQueryBuilder<T, TTable> {
|
|
908
|
+
|
|
403
909
|
const relation = this.env.table.relations[relationName];
|
|
910
|
+
|
|
404
911
|
if (!relation) {
|
|
912
|
+
|
|
405
913
|
throw new Error(`Relation '${relationName}' not found on table '${this.env.table.name}'`);
|
|
914
|
+
|
|
406
915
|
}
|
|
407
916
|
|
|
917
|
+
|
|
918
|
+
|
|
408
919
|
let subQb = this.createChildBuilder<any, typeof relation.target>(relation.target);
|
|
920
|
+
|
|
409
921
|
if (callback) {
|
|
922
|
+
|
|
410
923
|
subQb = callback(subQb);
|
|
924
|
+
|
|
411
925
|
}
|
|
412
926
|
|
|
927
|
+
|
|
928
|
+
|
|
413
929
|
const subAst = subQb.getAST();
|
|
930
|
+
|
|
414
931
|
const finalSubAst = this.relationManager.applyRelationCorrelation(this.context, relationName, subAst);
|
|
932
|
+
|
|
415
933
|
return this.where(exists(finalSubAst));
|
|
934
|
+
|
|
416
935
|
}
|
|
417
936
|
|
|
937
|
+
|
|
938
|
+
|
|
418
939
|
/**
|
|
940
|
+
|
|
419
941
|
* Adds a WHERE NOT EXISTS condition based on a relationship
|
|
942
|
+
|
|
420
943
|
* @param relationName - Name of the relationship to check
|
|
944
|
+
|
|
421
945
|
* @param callback - Optional callback to modify the relationship query
|
|
946
|
+
|
|
422
947
|
* @returns New query builder instance with the relationship non-existence check
|
|
948
|
+
|
|
423
949
|
*/
|
|
950
|
+
|
|
424
951
|
whereHasNot(
|
|
952
|
+
|
|
425
953
|
relationName: string,
|
|
954
|
+
|
|
426
955
|
callback?: <TChildTable extends TableDef>(
|
|
956
|
+
|
|
427
957
|
qb: SelectQueryBuilder<any, TChildTable>
|
|
958
|
+
|
|
428
959
|
) => SelectQueryBuilder<any, TChildTable>
|
|
960
|
+
|
|
429
961
|
): SelectQueryBuilder<T, TTable> {
|
|
962
|
+
|
|
430
963
|
const relation = this.env.table.relations[relationName];
|
|
964
|
+
|
|
431
965
|
if (!relation) {
|
|
966
|
+
|
|
432
967
|
throw new Error(`Relation '${relationName}' not found on table '${this.env.table.name}'`);
|
|
968
|
+
|
|
433
969
|
}
|
|
434
970
|
|
|
971
|
+
|
|
972
|
+
|
|
435
973
|
let subQb = this.createChildBuilder<any, typeof relation.target>(relation.target);
|
|
974
|
+
|
|
436
975
|
if (callback) {
|
|
976
|
+
|
|
437
977
|
subQb = callback(subQb);
|
|
978
|
+
|
|
438
979
|
}
|
|
439
980
|
|
|
981
|
+
|
|
982
|
+
|
|
440
983
|
const subAst = subQb.getAST();
|
|
984
|
+
|
|
441
985
|
const finalSubAst = this.relationManager.applyRelationCorrelation(this.context, relationName, subAst);
|
|
986
|
+
|
|
442
987
|
return this.where(notExists(finalSubAst));
|
|
988
|
+
|
|
443
989
|
}
|
|
444
990
|
|
|
991
|
+
|
|
992
|
+
|
|
445
993
|
/**
|
|
994
|
+
|
|
446
995
|
* Compiles the query to SQL for a specific dialect
|
|
996
|
+
|
|
447
997
|
* @param dialect - Database dialect to compile for
|
|
998
|
+
|
|
448
999
|
* @returns Compiled query with SQL and parameters
|
|
1000
|
+
|
|
449
1001
|
*/
|
|
1002
|
+
|
|
450
1003
|
compile(dialect: SelectDialectInput): CompiledQuery {
|
|
1004
|
+
|
|
451
1005
|
const resolved = resolveDialectInput(dialect);
|
|
1006
|
+
|
|
452
1007
|
return resolved.compileSelect(this.context.state.ast);
|
|
1008
|
+
|
|
453
1009
|
}
|
|
454
1010
|
|
|
1011
|
+
|
|
1012
|
+
|
|
455
1013
|
/**
|
|
1014
|
+
|
|
456
1015
|
* Converts the query to SQL string for a specific dialect
|
|
1016
|
+
|
|
457
1017
|
* @param dialect - Database dialect to generate SQL for
|
|
1018
|
+
|
|
458
1019
|
* @returns SQL string representation of the query
|
|
1020
|
+
|
|
459
1021
|
*/
|
|
1022
|
+
|
|
460
1023
|
toSql(dialect: SelectDialectInput): string {
|
|
1024
|
+
|
|
461
1025
|
return this.compile(dialect).sql;
|
|
1026
|
+
|
|
462
1027
|
}
|
|
463
1028
|
|
|
1029
|
+
|
|
1030
|
+
|
|
464
1031
|
/**
|
|
1032
|
+
|
|
465
1033
|
* Gets the hydration plan for the query
|
|
1034
|
+
|
|
466
1035
|
* @returns Hydration plan or undefined if none exists
|
|
1036
|
+
|
|
467
1037
|
*/
|
|
1038
|
+
|
|
468
1039
|
getHydrationPlan(): HydrationPlan | undefined {
|
|
1040
|
+
|
|
469
1041
|
return this.context.hydration.getPlan();
|
|
1042
|
+
|
|
470
1043
|
}
|
|
471
1044
|
|
|
1045
|
+
|
|
1046
|
+
|
|
472
1047
|
/**
|
|
1048
|
+
|
|
473
1049
|
* Gets the Abstract Syntax Tree (AST) representation of the query
|
|
1050
|
+
|
|
474
1051
|
* @returns Query AST with hydration applied
|
|
1052
|
+
|
|
475
1053
|
*/
|
|
1054
|
+
|
|
476
1055
|
getAST(): SelectQueryNode {
|
|
1056
|
+
|
|
477
1057
|
return this.context.hydration.applyToAst(this.context.state.ast);
|
|
1058
|
+
|
|
478
1059
|
}
|
|
1060
|
+
|
|
479
1061
|
}
|
|
480
1062
|
|
|
1063
|
+
|
|
1064
|
+
|
|
481
1065
|
/**
|
|
1066
|
+
|
|
482
1067
|
* Creates a column node for use in expressions
|
|
1068
|
+
|
|
483
1069
|
* @param table - Table name
|
|
1070
|
+
|
|
484
1071
|
* @param name - Column name
|
|
1072
|
+
|
|
485
1073
|
* @returns ColumnNode with the specified table and name
|
|
1074
|
+
|
|
486
1075
|
*/
|
|
1076
|
+
|
|
487
1077
|
export const createColumn = (table: string, name: string): ColumnNode => ({ type: 'Column', table, name });
|
|
488
1078
|
|
|
1079
|
+
|
|
1080
|
+
|
|
489
1081
|
/**
|
|
1082
|
+
|
|
490
1083
|
* Creates a literal value node for use in expressions
|
|
1084
|
+
|
|
491
1085
|
* @param val - Literal value (string or number)
|
|
1086
|
+
|
|
492
1087
|
* @returns LiteralNode with the specified value
|
|
1088
|
+
|
|
493
1089
|
*/
|
|
1090
|
+
|
|
494
1091
|
export const createLiteral = (val: string | number): LiteralNode => ({ type: 'Literal', value: val });
|
|
1092
|
+
|