@mikro-orm/sql 7.0.0-dev.321 → 7.0.0-dev.322
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/AbstractSqlDriver.js +4 -4
- package/PivotCollectionPersister.d.ts +2 -11
- package/PivotCollectionPersister.js +59 -59
- package/dialects/mysql/MySqlSchemaHelper.d.ts +1 -1
- package/dialects/mysql/MySqlSchemaHelper.js +4 -4
- package/package.json +2 -2
- package/plugin/index.d.ts +1 -3
- package/plugin/index.js +12 -12
- package/plugin/transformer.d.ts +5 -20
- package/plugin/transformer.js +81 -73
- package/query/ObjectCriteriaNode.js +3 -3
- package/query/QueryBuilder.d.ts +57 -51
- package/query/QueryBuilder.js +339 -368
- package/query/QueryBuilderHelper.d.ts +1 -8
- package/query/QueryBuilderHelper.js +97 -97
- package/query/ScalarCriteriaNode.js +3 -1
- package/schema/DatabaseSchema.d.ts +7 -5
- package/schema/DatabaseSchema.js +50 -33
- package/schema/DatabaseTable.d.ts +7 -5
- package/schema/DatabaseTable.js +77 -59
- package/schema/SchemaComparator.d.ts +1 -3
- package/schema/SchemaComparator.js +18 -18
- package/tsconfig.build.tsbuildinfo +1 -1
- package/typings.d.ts +4 -1
package/query/QueryBuilder.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
var _a;
|
|
1
2
|
import { EntityMetadata, helper, inspect, isRaw, LoadStrategy, LockMode, PopulateHint, QueryFlag, QueryHelper, raw, RawQueryFragment, Reference, ReferenceKind, serialize, Utils, ValidationError, } from '@mikro-orm/core';
|
|
2
3
|
import { JoinType, QueryType } from './enums.js';
|
|
3
4
|
import { QueryBuilderHelper } from './QueryBuilderHelper.js';
|
|
@@ -31,61 +32,54 @@ export class QueryBuilder {
|
|
|
31
32
|
connectionType;
|
|
32
33
|
em;
|
|
33
34
|
loggerContext;
|
|
35
|
+
#state = _a.createDefaultState();
|
|
36
|
+
#helper;
|
|
37
|
+
#query;
|
|
38
|
+
/** @internal */
|
|
39
|
+
static createDefaultState() {
|
|
40
|
+
return {
|
|
41
|
+
aliasCounter: 0,
|
|
42
|
+
explicitAlias: false,
|
|
43
|
+
populateHintFinalized: false,
|
|
44
|
+
joins: {},
|
|
45
|
+
cond: {},
|
|
46
|
+
orderBy: [],
|
|
47
|
+
groupBy: [],
|
|
48
|
+
having: {},
|
|
49
|
+
comments: [],
|
|
50
|
+
hintComments: [],
|
|
51
|
+
subQueries: {},
|
|
52
|
+
aliases: {},
|
|
53
|
+
tptAlias: {},
|
|
54
|
+
ctes: [],
|
|
55
|
+
tptJoinsApplied: false,
|
|
56
|
+
autoJoinedPaths: [],
|
|
57
|
+
populate: [],
|
|
58
|
+
populateMap: {},
|
|
59
|
+
flags: new Set([QueryFlag.CONVERT_CUSTOM_TYPES]),
|
|
60
|
+
finalized: false,
|
|
61
|
+
joinedProps: new Map(),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
34
64
|
get mainAlias() {
|
|
35
65
|
this.ensureFromClause();
|
|
36
|
-
return this.
|
|
66
|
+
return this.#state.mainAlias;
|
|
37
67
|
}
|
|
38
68
|
get alias() {
|
|
39
69
|
return this.mainAlias.aliasName;
|
|
40
70
|
}
|
|
41
71
|
get helper() {
|
|
42
72
|
this.ensureFromClause();
|
|
43
|
-
return this
|
|
73
|
+
return this.#helper;
|
|
44
74
|
}
|
|
45
75
|
get type() {
|
|
46
|
-
return this.
|
|
76
|
+
return this.#state.type ?? QueryType.SELECT;
|
|
47
77
|
}
|
|
48
78
|
/** @internal */
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
aliasCounter = 0;
|
|
53
|
-
flags = new Set([QueryFlag.CONVERT_CUSTOM_TYPES]);
|
|
54
|
-
finalized = false;
|
|
55
|
-
populateHintFinalized = false;
|
|
56
|
-
_joins = {};
|
|
57
|
-
_explicitAlias = false;
|
|
58
|
-
_schema;
|
|
59
|
-
_cond = {};
|
|
60
|
-
_data;
|
|
61
|
-
_orderBy = [];
|
|
62
|
-
_groupBy = [];
|
|
63
|
-
_having = {};
|
|
64
|
-
_returning;
|
|
65
|
-
_onConflict;
|
|
66
|
-
_limit;
|
|
67
|
-
_offset;
|
|
68
|
-
_distinctOn;
|
|
69
|
-
_joinedProps = new Map();
|
|
70
|
-
_cache;
|
|
71
|
-
_indexHint;
|
|
72
|
-
_collation;
|
|
73
|
-
_comments = [];
|
|
74
|
-
_hintComments = [];
|
|
75
|
-
flushMode;
|
|
76
|
-
lockMode;
|
|
77
|
-
lockTables;
|
|
78
|
-
subQueries = {};
|
|
79
|
-
_mainAlias;
|
|
80
|
-
_aliases = {};
|
|
81
|
-
_tptAlias = {}; // maps entity className to alias for TPT parent tables
|
|
82
|
-
_helper;
|
|
83
|
-
_query;
|
|
84
|
-
_unionQuery;
|
|
85
|
-
_ctes = [];
|
|
79
|
+
get state() {
|
|
80
|
+
return this.#state;
|
|
81
|
+
}
|
|
86
82
|
platform;
|
|
87
|
-
tptJoinsApplied = false;
|
|
88
|
-
autoJoinedPaths = [];
|
|
89
83
|
/**
|
|
90
84
|
* @internal
|
|
91
85
|
*/
|
|
@@ -98,15 +92,15 @@ export class QueryBuilder {
|
|
|
98
92
|
this.loggerContext = loggerContext;
|
|
99
93
|
this.platform = this.driver.getPlatform();
|
|
100
94
|
if (alias) {
|
|
101
|
-
this.aliasCounter++;
|
|
102
|
-
this.
|
|
95
|
+
this.#state.aliasCounter++;
|
|
96
|
+
this.#state.explicitAlias = true;
|
|
103
97
|
}
|
|
104
98
|
// @ts-expect-error union type does not match the overloaded method signature
|
|
105
99
|
this.from(entityName, alias);
|
|
106
100
|
}
|
|
107
101
|
select(fields, distinct = false) {
|
|
108
102
|
this.ensureNotFinalized();
|
|
109
|
-
this.
|
|
103
|
+
this.#state.fields = Utils.asArray(fields).flatMap(f => {
|
|
110
104
|
if (typeof f !== 'string') {
|
|
111
105
|
// Normalize sql.ref('prop') and sql.ref('prop').as('alias') to string form
|
|
112
106
|
if (isRaw(f) && f.sql === '??' && f.params.length === 1) {
|
|
@@ -124,7 +118,7 @@ export class QueryBuilder {
|
|
|
124
118
|
return this.resolveNestedPath(f);
|
|
125
119
|
});
|
|
126
120
|
if (distinct) {
|
|
127
|
-
this.flags.add(QueryFlag.DISTINCT);
|
|
121
|
+
this.#state.flags.add(QueryFlag.DISTINCT);
|
|
128
122
|
}
|
|
129
123
|
return this.init(QueryType.SELECT);
|
|
130
124
|
}
|
|
@@ -133,10 +127,10 @@ export class QueryBuilder {
|
|
|
133
127
|
*/
|
|
134
128
|
addSelect(fields) {
|
|
135
129
|
this.ensureNotFinalized();
|
|
136
|
-
if (this.
|
|
130
|
+
if (this.#state.type && this.#state.type !== QueryType.SELECT) {
|
|
137
131
|
return this;
|
|
138
132
|
}
|
|
139
|
-
return this.select([...Utils.asArray(this.
|
|
133
|
+
return this.select([...Utils.asArray(this.#state.fields), ...Utils.asArray(fields)]);
|
|
140
134
|
}
|
|
141
135
|
distinct() {
|
|
142
136
|
this.ensureNotFinalized();
|
|
@@ -144,7 +138,7 @@ export class QueryBuilder {
|
|
|
144
138
|
}
|
|
145
139
|
distinctOn(fields) {
|
|
146
140
|
this.ensureNotFinalized();
|
|
147
|
-
this.
|
|
141
|
+
this.#state.distinctOn = Utils.asArray(fields);
|
|
148
142
|
return this;
|
|
149
143
|
}
|
|
150
144
|
/**
|
|
@@ -219,16 +213,16 @@ export class QueryBuilder {
|
|
|
219
213
|
*/
|
|
220
214
|
count(field, distinct = false) {
|
|
221
215
|
if (field) {
|
|
222
|
-
this.
|
|
216
|
+
this.#state.fields = Utils.asArray(field);
|
|
223
217
|
}
|
|
224
218
|
else if (distinct || this.hasToManyJoins()) {
|
|
225
|
-
this.
|
|
219
|
+
this.#state.fields = this.mainAlias.meta.primaryKeys;
|
|
226
220
|
}
|
|
227
221
|
else {
|
|
228
|
-
this.
|
|
222
|
+
this.#state.fields = [raw('*')];
|
|
229
223
|
}
|
|
230
224
|
if (distinct) {
|
|
231
|
-
this.flags.add(QueryFlag.DISTINCT);
|
|
225
|
+
this.#state.flags.add(QueryFlag.DISTINCT);
|
|
232
226
|
}
|
|
233
227
|
return this.init(QueryType.COUNT);
|
|
234
228
|
}
|
|
@@ -262,30 +256,30 @@ export class QueryBuilder {
|
|
|
262
256
|
* ```
|
|
263
257
|
*/
|
|
264
258
|
joinAndSelect(field, alias, cond = {}, type = JoinType.innerJoin, path, fields, schema) {
|
|
265
|
-
if (!this.
|
|
259
|
+
if (!this.#state.type) {
|
|
266
260
|
this.select('*');
|
|
267
261
|
}
|
|
268
262
|
let subquery;
|
|
269
263
|
if (Array.isArray(field)) {
|
|
270
|
-
const rawFragment = field[1] instanceof
|
|
264
|
+
const rawFragment = field[1] instanceof _a ? field[1].toRaw() : field[1];
|
|
271
265
|
subquery = this.platform.formatQuery(rawFragment.sql, rawFragment.params);
|
|
272
266
|
field = field[0];
|
|
273
267
|
}
|
|
274
268
|
const { prop, key } = this.joinReference(field, alias, cond, type, path, schema, subquery);
|
|
275
269
|
const [fromAlias] = this.helper.splitField(field);
|
|
276
270
|
if (subquery) {
|
|
277
|
-
this.
|
|
271
|
+
this.#state.joins[key].subquery = subquery;
|
|
278
272
|
}
|
|
279
|
-
const populate = this.
|
|
273
|
+
const populate = this.#state.joinedProps.get(fromAlias);
|
|
280
274
|
const item = { field: prop.name, strategy: LoadStrategy.JOINED, children: [] };
|
|
281
275
|
if (populate) {
|
|
282
276
|
populate.children.push(item);
|
|
283
277
|
}
|
|
284
278
|
else {
|
|
285
279
|
// root entity
|
|
286
|
-
this.
|
|
280
|
+
this.#state.populate.push(item);
|
|
287
281
|
}
|
|
288
|
-
this.
|
|
282
|
+
this.#state.joinedProps.set(alias, item);
|
|
289
283
|
this.addSelect(this.getFieldsForJoinedLoad(prop, alias, fields));
|
|
290
284
|
return this;
|
|
291
285
|
}
|
|
@@ -306,12 +300,12 @@ export class QueryBuilder {
|
|
|
306
300
|
getFieldsForJoinedLoad(prop, alias, explicitFields) {
|
|
307
301
|
const fields = [];
|
|
308
302
|
const populate = [];
|
|
309
|
-
const joinKey = Object.keys(this.
|
|
303
|
+
const joinKey = Object.keys(this.#state.joins).find(join => join.endsWith(`#${alias}`));
|
|
310
304
|
const targetMeta = prop.targetMeta;
|
|
311
|
-
const schema = this.
|
|
305
|
+
const schema = this.#state.schema ?? (targetMeta.schema !== '*' ? targetMeta.schema : undefined);
|
|
312
306
|
if (joinKey) {
|
|
313
|
-
const path = this.
|
|
314
|
-
let children = this.
|
|
307
|
+
const path = this.#state.joins[joinKey].path.split('.').slice(1);
|
|
308
|
+
let children = this.#state.populate;
|
|
315
309
|
for (let i = 0; i < path.length; i++) {
|
|
316
310
|
const child = children.filter(hint => {
|
|
317
311
|
const [propName] = hint.field.split(':', 2);
|
|
@@ -361,13 +355,13 @@ export class QueryBuilder {
|
|
|
361
355
|
* @internal
|
|
362
356
|
*/
|
|
363
357
|
scheduleFilterCheck(path) {
|
|
364
|
-
this.autoJoinedPaths.push(path);
|
|
358
|
+
this.#state.autoJoinedPaths.push(path);
|
|
365
359
|
}
|
|
366
360
|
/**
|
|
367
361
|
* @internal
|
|
368
362
|
*/
|
|
369
363
|
async applyJoinedFilters(em, filterOptions) {
|
|
370
|
-
for (const path of this.autoJoinedPaths) {
|
|
364
|
+
for (const path of this.#state.autoJoinedPaths) {
|
|
371
365
|
const join = this.getJoinForPath(path);
|
|
372
366
|
if (join.type === JoinType.pivotJoin) {
|
|
373
367
|
continue;
|
|
@@ -403,10 +397,10 @@ export class QueryBuilder {
|
|
|
403
397
|
withSubQuery(subQuery, alias) {
|
|
404
398
|
this.ensureNotFinalized();
|
|
405
399
|
if (isRaw(subQuery)) {
|
|
406
|
-
this.subQueries[alias] = this.platform.formatQuery(subQuery.sql, subQuery.params);
|
|
400
|
+
this.#state.subQueries[alias] = this.platform.formatQuery(subQuery.sql, subQuery.params);
|
|
407
401
|
}
|
|
408
402
|
else {
|
|
409
|
-
this.subQueries[alias] = subQuery.toString();
|
|
403
|
+
this.#state.subQueries[alias] = subQuery.toString();
|
|
410
404
|
}
|
|
411
405
|
return this;
|
|
412
406
|
}
|
|
@@ -430,13 +424,13 @@ export class QueryBuilder {
|
|
|
430
424
|
platform: this.platform,
|
|
431
425
|
aliasMap: this.getAliasMap(),
|
|
432
426
|
aliased: [QueryType.SELECT, QueryType.COUNT].includes(this.type),
|
|
433
|
-
convertCustomTypes: this.flags.has(QueryFlag.CONVERT_CUSTOM_TYPES),
|
|
427
|
+
convertCustomTypes: this.#state.flags.has(QueryFlag.CONVERT_CUSTOM_TYPES),
|
|
434
428
|
});
|
|
435
429
|
}
|
|
436
430
|
const op = operator || params;
|
|
437
|
-
const topLevel = !op || !(Utils.hasObjectKeys(this.
|
|
431
|
+
const topLevel = !op || !(Utils.hasObjectKeys(this.#state.cond) || RawQueryFragment.hasObjectFragments(this.#state.cond));
|
|
438
432
|
const criteriaNode = CriteriaNodeFactory.createNode(this.metadata, this.mainAlias.entityName, processedCond);
|
|
439
|
-
const ignoreBranching = this.
|
|
433
|
+
const ignoreBranching = this.#state.resolvedPopulateWhere === 'infer';
|
|
440
434
|
if ([QueryType.UPDATE, QueryType.DELETE].includes(this.type) &&
|
|
441
435
|
criteriaNode.willAutoJoin(this, undefined, { ignoreBranching })) {
|
|
442
436
|
// use sub-query to support joining
|
|
@@ -444,18 +438,18 @@ export class QueryBuilder {
|
|
|
444
438
|
this.select(this.mainAlias.meta.primaryKeys, true);
|
|
445
439
|
}
|
|
446
440
|
if (topLevel) {
|
|
447
|
-
this.
|
|
441
|
+
this.#state.cond = criteriaNode.process(this, { ignoreBranching });
|
|
448
442
|
}
|
|
449
|
-
else if (Array.isArray(this.
|
|
450
|
-
this.
|
|
443
|
+
else if (Array.isArray(this.#state.cond[op])) {
|
|
444
|
+
this.#state.cond[op].push(criteriaNode.process(this, { ignoreBranching }));
|
|
451
445
|
}
|
|
452
446
|
else {
|
|
453
|
-
const cond1 = [this.
|
|
454
|
-
this.
|
|
447
|
+
const cond1 = [this.#state.cond, criteriaNode.process(this, { ignoreBranching })];
|
|
448
|
+
this.#state.cond = { [op]: cond1 };
|
|
455
449
|
}
|
|
456
|
-
if (this.
|
|
457
|
-
this.
|
|
458
|
-
this.
|
|
450
|
+
if (this.#state.onConflict) {
|
|
451
|
+
this.#state.onConflict[this.#state.onConflict.length - 1].where = this.helper.processOnConflictCondition(this.#state.cond, this.#state.schema);
|
|
452
|
+
this.#state.cond = {};
|
|
459
453
|
}
|
|
460
454
|
return this;
|
|
461
455
|
}
|
|
@@ -474,7 +468,7 @@ export class QueryBuilder {
|
|
|
474
468
|
processOrderBy(orderBy, reset = true) {
|
|
475
469
|
this.ensureNotFinalized();
|
|
476
470
|
if (reset) {
|
|
477
|
-
this.
|
|
471
|
+
this.#state.orderBy = [];
|
|
478
472
|
}
|
|
479
473
|
const selectAliases = this.getSelectAliases();
|
|
480
474
|
Utils.asArray(orderBy).forEach(orig => {
|
|
@@ -499,7 +493,7 @@ export class QueryBuilder {
|
|
|
499
493
|
convertCustomTypes: false,
|
|
500
494
|
type: 'orderBy',
|
|
501
495
|
});
|
|
502
|
-
this.
|
|
496
|
+
this.#state.orderBy.push(CriteriaNodeFactory.createNode(this.metadata, this.mainAlias.entityName, processed).process(this, {
|
|
503
497
|
matchPopulateJoins: true,
|
|
504
498
|
type: 'orderBy',
|
|
505
499
|
}));
|
|
@@ -509,7 +503,7 @@ export class QueryBuilder {
|
|
|
509
503
|
/** Collect custom aliases from select fields (stored as 'resolved as alias' strings by select()). */
|
|
510
504
|
getSelectAliases() {
|
|
511
505
|
const aliases = new Set();
|
|
512
|
-
for (const field of this.
|
|
506
|
+
for (const field of this.#state.fields ?? []) {
|
|
513
507
|
if (typeof field === 'string') {
|
|
514
508
|
const m = FIELD_ALIAS_RE.exec(field);
|
|
515
509
|
if (m) {
|
|
@@ -521,7 +515,7 @@ export class QueryBuilder {
|
|
|
521
515
|
}
|
|
522
516
|
groupBy(fields) {
|
|
523
517
|
this.ensureNotFinalized();
|
|
524
|
-
this.
|
|
518
|
+
this.#state.groupBy = Utils.asArray(fields).flatMap(f => {
|
|
525
519
|
if (typeof f !== 'string') {
|
|
526
520
|
// Normalize sql.ref('prop') to string for proper formula resolution
|
|
527
521
|
if (isRaw(f) && f.sql === '??' && f.params.length === 1) {
|
|
@@ -549,12 +543,12 @@ export class QueryBuilder {
|
|
|
549
543
|
cond = { [raw(`(${cond})`, params)]: [] };
|
|
550
544
|
}
|
|
551
545
|
const processed = CriteriaNodeFactory.createNode(this.metadata, this.mainAlias.entityName, cond, undefined, undefined, false).process(this, { type: 'having' });
|
|
552
|
-
if (!this.
|
|
553
|
-
this.
|
|
546
|
+
if (!this.#state.having || !operator) {
|
|
547
|
+
this.#state.having = processed;
|
|
554
548
|
}
|
|
555
549
|
else {
|
|
556
|
-
const cond1 = [this.
|
|
557
|
-
this.
|
|
550
|
+
const cond1 = [this.#state.having, processed];
|
|
551
|
+
this.#state.having = { [operator]: cond1 };
|
|
558
552
|
}
|
|
559
553
|
return this;
|
|
560
554
|
}
|
|
@@ -567,8 +561,8 @@ export class QueryBuilder {
|
|
|
567
561
|
onConflict(fields = []) {
|
|
568
562
|
const meta = this.mainAlias.meta;
|
|
569
563
|
this.ensureNotFinalized();
|
|
570
|
-
this.
|
|
571
|
-
this.
|
|
564
|
+
this.#state.onConflict ??= [];
|
|
565
|
+
this.#state.onConflict.push({
|
|
572
566
|
fields: isRaw(fields)
|
|
573
567
|
? fields
|
|
574
568
|
: Utils.asArray(fields).flatMap(f => {
|
|
@@ -580,24 +574,24 @@ export class QueryBuilder {
|
|
|
580
574
|
return this;
|
|
581
575
|
}
|
|
582
576
|
ignore() {
|
|
583
|
-
if (!this.
|
|
577
|
+
if (!this.#state.onConflict) {
|
|
584
578
|
throw new Error('You need to call `qb.onConflict()` first to use `qb.ignore()`');
|
|
585
579
|
}
|
|
586
|
-
this.
|
|
580
|
+
this.#state.onConflict[this.#state.onConflict.length - 1].ignore = true;
|
|
587
581
|
return this;
|
|
588
582
|
}
|
|
589
583
|
merge(data) {
|
|
590
|
-
if (!this.
|
|
584
|
+
if (!this.#state.onConflict) {
|
|
591
585
|
throw new Error('You need to call `qb.onConflict()` first to use `qb.merge()`');
|
|
592
586
|
}
|
|
593
587
|
if (Array.isArray(data) && data.length === 0) {
|
|
594
588
|
return this.ignore();
|
|
595
589
|
}
|
|
596
|
-
this.
|
|
590
|
+
this.#state.onConflict[this.#state.onConflict.length - 1].merge = data;
|
|
597
591
|
return this;
|
|
598
592
|
}
|
|
599
593
|
returning(fields) {
|
|
600
|
-
this.
|
|
594
|
+
this.#state.returning = Utils.asArray(fields);
|
|
601
595
|
return this;
|
|
602
596
|
}
|
|
603
597
|
/**
|
|
@@ -605,9 +599,9 @@ export class QueryBuilder {
|
|
|
605
599
|
*/
|
|
606
600
|
populate(populate, populateWhere, populateFilter) {
|
|
607
601
|
this.ensureNotFinalized();
|
|
608
|
-
this.
|
|
609
|
-
this.
|
|
610
|
-
this.
|
|
602
|
+
this.#state.populate = populate;
|
|
603
|
+
this.#state.populateWhere = populateWhere;
|
|
604
|
+
this.#state.populateFilter = populateFilter;
|
|
611
605
|
return this;
|
|
612
606
|
}
|
|
613
607
|
/**
|
|
@@ -621,7 +615,7 @@ export class QueryBuilder {
|
|
|
621
615
|
*/
|
|
622
616
|
limit(limit, offset = 0) {
|
|
623
617
|
this.ensureNotFinalized();
|
|
624
|
-
this.
|
|
618
|
+
this.#state.limit = limit;
|
|
625
619
|
if (offset) {
|
|
626
620
|
this.offset(offset);
|
|
627
621
|
}
|
|
@@ -637,12 +631,12 @@ export class QueryBuilder {
|
|
|
637
631
|
*/
|
|
638
632
|
offset(offset) {
|
|
639
633
|
this.ensureNotFinalized();
|
|
640
|
-
this.
|
|
634
|
+
this.#state.offset = offset;
|
|
641
635
|
return this;
|
|
642
636
|
}
|
|
643
637
|
withSchema(schema) {
|
|
644
638
|
this.ensureNotFinalized();
|
|
645
|
-
this.
|
|
639
|
+
this.#state.schema = schema;
|
|
646
640
|
return this;
|
|
647
641
|
}
|
|
648
642
|
setLockMode(mode, tables) {
|
|
@@ -650,31 +644,31 @@ export class QueryBuilder {
|
|
|
650
644
|
if (mode != null && ![LockMode.OPTIMISTIC, LockMode.NONE].includes(mode) && !this.context) {
|
|
651
645
|
throw ValidationError.transactionRequired();
|
|
652
646
|
}
|
|
653
|
-
this.lockMode = mode;
|
|
654
|
-
this.lockTables = tables;
|
|
647
|
+
this.#state.lockMode = mode;
|
|
648
|
+
this.#state.lockTables = tables;
|
|
655
649
|
return this;
|
|
656
650
|
}
|
|
657
651
|
setFlushMode(flushMode) {
|
|
658
652
|
this.ensureNotFinalized();
|
|
659
|
-
this.flushMode = flushMode;
|
|
653
|
+
this.#state.flushMode = flushMode;
|
|
660
654
|
return this;
|
|
661
655
|
}
|
|
662
656
|
setFlag(flag) {
|
|
663
657
|
this.ensureNotFinalized();
|
|
664
|
-
this.flags.add(flag);
|
|
658
|
+
this.#state.flags.add(flag);
|
|
665
659
|
return this;
|
|
666
660
|
}
|
|
667
661
|
unsetFlag(flag) {
|
|
668
662
|
this.ensureNotFinalized();
|
|
669
|
-
this.flags.delete(flag);
|
|
663
|
+
this.#state.flags.delete(flag);
|
|
670
664
|
return this;
|
|
671
665
|
}
|
|
672
666
|
hasFlag(flag) {
|
|
673
|
-
return this.flags.has(flag);
|
|
667
|
+
return this.#state.flags.has(flag);
|
|
674
668
|
}
|
|
675
669
|
cache(config = true) {
|
|
676
670
|
this.ensureNotFinalized();
|
|
677
|
-
this.
|
|
671
|
+
this.#state.cache = config;
|
|
678
672
|
return this;
|
|
679
673
|
}
|
|
680
674
|
/**
|
|
@@ -682,7 +676,7 @@ export class QueryBuilder {
|
|
|
682
676
|
*/
|
|
683
677
|
indexHint(sql) {
|
|
684
678
|
this.ensureNotFinalized();
|
|
685
|
-
this.
|
|
679
|
+
this.#state.indexHint = sql;
|
|
686
680
|
return this;
|
|
687
681
|
}
|
|
688
682
|
/**
|
|
@@ -690,7 +684,7 @@ export class QueryBuilder {
|
|
|
690
684
|
*/
|
|
691
685
|
collation(collation) {
|
|
692
686
|
this.ensureNotFinalized();
|
|
693
|
-
this.
|
|
687
|
+
this.#state.collation = collation;
|
|
694
688
|
return this;
|
|
695
689
|
}
|
|
696
690
|
/**
|
|
@@ -698,7 +692,7 @@ export class QueryBuilder {
|
|
|
698
692
|
*/
|
|
699
693
|
comment(comment) {
|
|
700
694
|
this.ensureNotFinalized();
|
|
701
|
-
this.
|
|
695
|
+
this.#state.comments.push(...Utils.asArray(comment));
|
|
702
696
|
return this;
|
|
703
697
|
}
|
|
704
698
|
/**
|
|
@@ -708,43 +702,43 @@ export class QueryBuilder {
|
|
|
708
702
|
*/
|
|
709
703
|
hintComment(comment) {
|
|
710
704
|
this.ensureNotFinalized();
|
|
711
|
-
this.
|
|
705
|
+
this.#state.hintComments.push(...Utils.asArray(comment));
|
|
712
706
|
return this;
|
|
713
707
|
}
|
|
714
708
|
from(target, aliasName) {
|
|
715
709
|
this.ensureNotFinalized();
|
|
716
|
-
if (target instanceof
|
|
710
|
+
if (target instanceof _a) {
|
|
717
711
|
this.fromSubQuery(target, aliasName);
|
|
718
712
|
}
|
|
719
713
|
else if (typeof target === 'string' && !this.metadata.find(target)) {
|
|
720
714
|
this.fromRawTable(target, aliasName);
|
|
721
715
|
}
|
|
722
716
|
else {
|
|
723
|
-
if (aliasName && this.
|
|
724
|
-
throw new Error(`Cannot override the alias to '${aliasName}' since a query already contains references to '${this.
|
|
717
|
+
if (aliasName && this.#state.mainAlias && Utils.className(target) !== this.#state.mainAlias.aliasName) {
|
|
718
|
+
throw new Error(`Cannot override the alias to '${aliasName}' since a query already contains references to '${this.#state.mainAlias.aliasName}'`);
|
|
725
719
|
}
|
|
726
720
|
this.fromEntityName(target, aliasName);
|
|
727
721
|
}
|
|
728
722
|
return this;
|
|
729
723
|
}
|
|
730
724
|
getNativeQuery(processVirtualEntity = true) {
|
|
731
|
-
if (this.
|
|
732
|
-
if (!this
|
|
733
|
-
this
|
|
725
|
+
if (this.#state.unionQuery) {
|
|
726
|
+
if (!this.#query?.qb) {
|
|
727
|
+
this.#query = {};
|
|
734
728
|
const nqb = this.platform.createNativeQueryBuilder();
|
|
735
729
|
nqb.select('*');
|
|
736
|
-
nqb.from(raw(`(${this.
|
|
737
|
-
this.
|
|
730
|
+
nqb.from(raw(`(${this.#state.unionQuery.sql})`, this.#state.unionQuery.params));
|
|
731
|
+
this.#query.qb = nqb;
|
|
738
732
|
}
|
|
739
|
-
return this.
|
|
733
|
+
return this.#query.qb;
|
|
740
734
|
}
|
|
741
|
-
if (this
|
|
742
|
-
return this.
|
|
735
|
+
if (this.#query?.qb) {
|
|
736
|
+
return this.#query.qb;
|
|
743
737
|
}
|
|
744
|
-
this
|
|
738
|
+
this.#query = {};
|
|
745
739
|
this.finalize();
|
|
746
740
|
const qb = this.getQueryBase(processVirtualEntity);
|
|
747
|
-
for (const cte of this.
|
|
741
|
+
for (const cte of this.#state.ctes) {
|
|
748
742
|
const query = cte.query;
|
|
749
743
|
const opts = { columns: cte.columns, materialized: cte.materialized };
|
|
750
744
|
if (cte.recursive) {
|
|
@@ -756,27 +750,27 @@ export class QueryBuilder {
|
|
|
756
750
|
}
|
|
757
751
|
const schema = this.getSchema(this.mainAlias);
|
|
758
752
|
const isNotEmptyObject = (obj) => Utils.hasObjectKeys(obj) || RawQueryFragment.hasObjectFragments(obj);
|
|
759
|
-
Utils.runIfNotEmpty(() => this.helper.appendQueryCondition(this.type, this.
|
|
760
|
-
Utils.runIfNotEmpty(() => qb.groupBy(this.prepareFields(this.
|
|
761
|
-
Utils.runIfNotEmpty(() => this.helper.appendQueryCondition(this.type, this.
|
|
753
|
+
Utils.runIfNotEmpty(() => this.helper.appendQueryCondition(this.type, this.#state.cond, qb), this.#state.cond && !this.#state.onConflict);
|
|
754
|
+
Utils.runIfNotEmpty(() => qb.groupBy(this.prepareFields(this.#state.groupBy, 'groupBy', schema)), isNotEmptyObject(this.#state.groupBy));
|
|
755
|
+
Utils.runIfNotEmpty(() => this.helper.appendQueryCondition(this.type, this.#state.having, qb, undefined, 'having'), isNotEmptyObject(this.#state.having));
|
|
762
756
|
Utils.runIfNotEmpty(() => {
|
|
763
|
-
const queryOrder = this.helper.getQueryOrder(this.type, this.
|
|
757
|
+
const queryOrder = this.helper.getQueryOrder(this.type, this.#state.orderBy, this.#state.populateMap, this.#state.collation);
|
|
764
758
|
if (queryOrder.length > 0) {
|
|
765
759
|
const sql = Utils.unique(queryOrder).join(', ');
|
|
766
760
|
qb.orderBy(sql);
|
|
767
761
|
return;
|
|
768
762
|
}
|
|
769
|
-
}, isNotEmptyObject(this.
|
|
770
|
-
Utils.runIfNotEmpty(() => qb.limit(this.
|
|
771
|
-
Utils.runIfNotEmpty(() => qb.offset(this.
|
|
772
|
-
Utils.runIfNotEmpty(() => qb.comment(this.
|
|
773
|
-
Utils.runIfNotEmpty(() => qb.hintComment(this.
|
|
774
|
-
Utils.runIfNotEmpty(() => this.helper.appendOnConflictClause(QueryType.UPSERT, this.
|
|
775
|
-
if (this.lockMode) {
|
|
776
|
-
this.helper.getLockSQL(qb, this.lockMode, this.lockTables, this.
|
|
777
|
-
}
|
|
778
|
-
this.processReturningStatement(qb, this.mainAlias.meta, this.
|
|
779
|
-
return (this.
|
|
763
|
+
}, isNotEmptyObject(this.#state.orderBy));
|
|
764
|
+
Utils.runIfNotEmpty(() => qb.limit(this.#state.limit), this.#state.limit != null);
|
|
765
|
+
Utils.runIfNotEmpty(() => qb.offset(this.#state.offset), this.#state.offset);
|
|
766
|
+
Utils.runIfNotEmpty(() => qb.comment(this.#state.comments), this.#state.comments);
|
|
767
|
+
Utils.runIfNotEmpty(() => qb.hintComment(this.#state.hintComments), this.#state.hintComments);
|
|
768
|
+
Utils.runIfNotEmpty(() => this.helper.appendOnConflictClause(QueryType.UPSERT, this.#state.onConflict, qb), this.#state.onConflict);
|
|
769
|
+
if (this.#state.lockMode) {
|
|
770
|
+
this.helper.getLockSQL(qb, this.#state.lockMode, this.#state.lockTables, this.#state.joins);
|
|
771
|
+
}
|
|
772
|
+
this.processReturningStatement(qb, this.mainAlias.meta, this.#state.data, this.#state.returning);
|
|
773
|
+
return (this.#query.qb = qb);
|
|
780
774
|
}
|
|
781
775
|
processReturningStatement(qb, meta, data, returning) {
|
|
782
776
|
const usesReturningStatement = this.platform.usesReturningStatement() || this.platform.usesOutputStatement();
|
|
@@ -827,16 +821,16 @@ export class QueryBuilder {
|
|
|
827
821
|
return raw(sql, params);
|
|
828
822
|
}
|
|
829
823
|
toQuery() {
|
|
830
|
-
if (this.
|
|
831
|
-
return this.
|
|
824
|
+
if (this.#state.unionQuery) {
|
|
825
|
+
return this.#state.unionQuery;
|
|
832
826
|
}
|
|
833
|
-
if (this
|
|
834
|
-
return { sql: this.
|
|
827
|
+
if (this.#query?.sql) {
|
|
828
|
+
return { sql: this.#query.sql, params: this.#query.params };
|
|
835
829
|
}
|
|
836
830
|
const query = this.getNativeQuery().compile();
|
|
837
|
-
this.
|
|
838
|
-
this.
|
|
839
|
-
return { sql: this.
|
|
831
|
+
this.#query.sql = query.sql;
|
|
832
|
+
this.#query.params = query.params;
|
|
833
|
+
return { sql: this.#query.sql, params: this.#query.params };
|
|
840
834
|
}
|
|
841
835
|
/**
|
|
842
836
|
* Returns the list of all parameters for this query.
|
|
@@ -868,7 +862,7 @@ export class QueryBuilder {
|
|
|
868
862
|
* @internal
|
|
869
863
|
*/
|
|
870
864
|
getJoinForPath(path, options) {
|
|
871
|
-
const joins = Object.values(this.
|
|
865
|
+
const joins = Object.values(this.#state.joins);
|
|
872
866
|
if (joins.length === 0) {
|
|
873
867
|
return undefined;
|
|
874
868
|
}
|
|
@@ -900,7 +894,7 @@ export class QueryBuilder {
|
|
|
900
894
|
*/
|
|
901
895
|
getNextAlias(entityName = 'e') {
|
|
902
896
|
entityName = Utils.className(entityName);
|
|
903
|
-
return this.driver.config.getNamingStrategy().aliasName(entityName, this.aliasCounter++);
|
|
897
|
+
return this.driver.config.getNamingStrategy().aliasName(entityName, this.#state.aliasCounter++);
|
|
904
898
|
}
|
|
905
899
|
/**
|
|
906
900
|
* Registers a join for a specific polymorphic target type.
|
|
@@ -913,15 +907,15 @@ export class QueryBuilder {
|
|
|
913
907
|
const referencedColumnNames = targetMeta.getPrimaryProps().flatMap(pk => pk.fieldNames);
|
|
914
908
|
const targetProp = { ...prop, targetMeta, referencedColumnNames };
|
|
915
909
|
const aliasedName = `${ownerAlias}.${prop.name}[${targetMeta.className}]#${alias}`;
|
|
916
|
-
this.
|
|
917
|
-
this.
|
|
910
|
+
this.#state.joins[aliasedName] = this.helper.joinManyToOneReference(targetProp, ownerAlias, alias, type, {}, schema);
|
|
911
|
+
this.#state.joins[aliasedName].path = path;
|
|
918
912
|
this.createAlias(targetMeta.class, alias);
|
|
919
913
|
}
|
|
920
914
|
/**
|
|
921
915
|
* @internal
|
|
922
916
|
*/
|
|
923
917
|
getAliasMap() {
|
|
924
|
-
return Object.fromEntries(Object.entries(this.
|
|
918
|
+
return Object.fromEntries(Object.entries(this.#state.aliases).map(([key, value]) => [key, value.entityName]));
|
|
925
919
|
}
|
|
926
920
|
/**
|
|
927
921
|
* Executes this QB and returns the raw results, mapped to the property names (unless disabled via last parameter).
|
|
@@ -936,11 +930,11 @@ export class QueryBuilder {
|
|
|
936
930
|
if (!this.connectionType && (isRunType || this.context)) {
|
|
937
931
|
this.connectionType = 'write';
|
|
938
932
|
}
|
|
939
|
-
if (!this.finalized && method === 'get' && this.type === QueryType.SELECT) {
|
|
933
|
+
if (!this.#state.finalized && method === 'get' && this.type === QueryType.SELECT) {
|
|
940
934
|
this.limit(1);
|
|
941
935
|
}
|
|
942
936
|
const query = this.toQuery();
|
|
943
|
-
const cached = await this.em?.tryCache(this.mainAlias.entityName, this.
|
|
937
|
+
const cached = await this.em?.tryCache(this.mainAlias.entityName, this.#state.cache, [
|
|
944
938
|
'qb.execute',
|
|
945
939
|
query.sql,
|
|
946
940
|
query.params,
|
|
@@ -953,17 +947,17 @@ export class QueryBuilder {
|
|
|
953
947
|
const res = await this.getConnection().execute(query.sql, query.params, method, this.context, loggerContext);
|
|
954
948
|
const meta = this.mainAlias.meta;
|
|
955
949
|
if (!options.mapResults || !meta) {
|
|
956
|
-
await this.em?.storeCache(this.
|
|
950
|
+
await this.em?.storeCache(this.#state.cache, cached, res);
|
|
957
951
|
return res;
|
|
958
952
|
}
|
|
959
953
|
if (method === 'run') {
|
|
960
954
|
return res;
|
|
961
955
|
}
|
|
962
|
-
const joinedProps = this.driver.joinedProps(meta, this.
|
|
956
|
+
const joinedProps = this.driver.joinedProps(meta, this.#state.populate);
|
|
963
957
|
let mapped;
|
|
964
958
|
if (Array.isArray(res)) {
|
|
965
959
|
const map = {};
|
|
966
|
-
mapped = res.map(r => this.driver.mapResult(r, meta, this.
|
|
960
|
+
mapped = res.map(r => this.driver.mapResult(r, meta, this.#state.populate, this, map));
|
|
967
961
|
if (options.mergeResults && joinedProps.length > 0) {
|
|
968
962
|
mapped = this.driver.mergeJoinedResult(mapped, this.mainAlias.meta, joinedProps);
|
|
969
963
|
}
|
|
@@ -972,10 +966,10 @@ export class QueryBuilder {
|
|
|
972
966
|
mapped = [this.driver.mapResult(res, meta, joinedProps, this)];
|
|
973
967
|
}
|
|
974
968
|
if (method === 'get') {
|
|
975
|
-
await this.em?.storeCache(this.
|
|
969
|
+
await this.em?.storeCache(this.#state.cache, cached, mapped[0]);
|
|
976
970
|
return mapped[0];
|
|
977
971
|
}
|
|
978
|
-
await this.em?.storeCache(this.
|
|
972
|
+
await this.em?.storeCache(this.#state.cache, cached, mapped);
|
|
979
973
|
return mapped;
|
|
980
974
|
}
|
|
981
975
|
getConnection() {
|
|
@@ -1011,13 +1005,13 @@ export class QueryBuilder {
|
|
|
1011
1005
|
yield* res;
|
|
1012
1006
|
return;
|
|
1013
1007
|
}
|
|
1014
|
-
const joinedProps = this.driver.joinedProps(meta, this.
|
|
1008
|
+
const joinedProps = this.driver.joinedProps(meta, this.#state.populate);
|
|
1015
1009
|
const stack = [];
|
|
1016
1010
|
const hash = (data) => {
|
|
1017
1011
|
return Utils.getPrimaryKeyHash(meta.primaryKeys.map(pk => data[pk]));
|
|
1018
1012
|
};
|
|
1019
1013
|
for await (const row of res) {
|
|
1020
|
-
const mapped = this.driver.mapResult(row, meta, this.
|
|
1014
|
+
const mapped = this.driver.mapResult(row, meta, this.#state.populate, this);
|
|
1021
1015
|
if (!options.mergeResults || joinedProps.length === 0) {
|
|
1022
1016
|
yield this.mapResult(mapped, options.mapResults);
|
|
1023
1017
|
continue;
|
|
@@ -1046,7 +1040,7 @@ export class QueryBuilder {
|
|
|
1046
1040
|
* Executes the query, returning array of results mapped to entity instances.
|
|
1047
1041
|
*/
|
|
1048
1042
|
async getResultList(limit) {
|
|
1049
|
-
await this.em.tryFlush(this.mainAlias.entityName, { flushMode: this.flushMode });
|
|
1043
|
+
await this.em.tryFlush(this.mainAlias.entityName, { flushMode: this.#state.flushMode });
|
|
1050
1044
|
const res = await this.execute('all', true);
|
|
1051
1045
|
return this.mapResults(res, limit);
|
|
1052
1046
|
}
|
|
@@ -1068,15 +1062,15 @@ export class QueryBuilder {
|
|
|
1068
1062
|
if (!map) {
|
|
1069
1063
|
return row;
|
|
1070
1064
|
}
|
|
1071
|
-
const entity = this.em.map(this.mainAlias.entityName, row, { schema: this.
|
|
1072
|
-
this.propagatePopulateHint(entity, this.
|
|
1065
|
+
const entity = this.em.map(this.mainAlias.entityName, row, { schema: this.#state.schema });
|
|
1066
|
+
this.propagatePopulateHint(entity, this.#state.populate);
|
|
1073
1067
|
return entity;
|
|
1074
1068
|
}
|
|
1075
1069
|
mapResults(res, limit) {
|
|
1076
1070
|
const entities = [];
|
|
1077
1071
|
for (const row of res) {
|
|
1078
1072
|
const entity = this.mapResult(row);
|
|
1079
|
-
this.propagatePopulateHint(entity, this.
|
|
1073
|
+
this.propagatePopulateHint(entity, this.#state.populate);
|
|
1080
1074
|
entities.push(entity);
|
|
1081
1075
|
if (limit != null && --limit === 0) {
|
|
1082
1076
|
break;
|
|
@@ -1088,7 +1082,7 @@ export class QueryBuilder {
|
|
|
1088
1082
|
* Executes the query, returning the first result or null
|
|
1089
1083
|
*/
|
|
1090
1084
|
async getSingleResult() {
|
|
1091
|
-
if (!this.finalized) {
|
|
1085
|
+
if (!this.#state.finalized) {
|
|
1092
1086
|
this.limit(1);
|
|
1093
1087
|
}
|
|
1094
1088
|
const [res] = await this.getResultList(1);
|
|
@@ -1100,7 +1094,7 @@ export class QueryBuilder {
|
|
|
1100
1094
|
res = await this.execute('get', false);
|
|
1101
1095
|
}
|
|
1102
1096
|
else {
|
|
1103
|
-
const qb = (this.
|
|
1097
|
+
const qb = (this.#state.type === undefined ? this : this.clone());
|
|
1104
1098
|
qb.processPopulateHint(); // needs to happen sooner so `qb.hasToManyJoins()` reports correctly
|
|
1105
1099
|
qb.count(field, distinct ?? qb.hasToManyJoins())
|
|
1106
1100
|
.limit(undefined)
|
|
@@ -1173,12 +1167,12 @@ export class QueryBuilder {
|
|
|
1173
1167
|
const parts = [];
|
|
1174
1168
|
const params = [];
|
|
1175
1169
|
for (const qb of all) {
|
|
1176
|
-
const compiled = qb instanceof
|
|
1170
|
+
const compiled = qb instanceof _a ? qb.toQuery() : qb.compile();
|
|
1177
1171
|
parts.push(`(${compiled.sql})`);
|
|
1178
1172
|
params.push(...compiled.params);
|
|
1179
1173
|
}
|
|
1180
1174
|
const result = this.clone(true);
|
|
1181
|
-
result.
|
|
1175
|
+
result.#state.unionQuery = { sql: parts.join(` ${separator} `), params };
|
|
1182
1176
|
return result;
|
|
1183
1177
|
}
|
|
1184
1178
|
with(name, query, options) {
|
|
@@ -1189,12 +1183,12 @@ export class QueryBuilder {
|
|
|
1189
1183
|
}
|
|
1190
1184
|
addCte(name, query, options, recursive) {
|
|
1191
1185
|
this.ensureNotFinalized();
|
|
1192
|
-
if (this.
|
|
1186
|
+
if (this.#state.ctes.some(cte => cte.name === name)) {
|
|
1193
1187
|
throw new Error(`CTE with name '${name}' already exists`);
|
|
1194
1188
|
}
|
|
1195
1189
|
// Eagerly compile QueryBuilder to RawQueryFragment — later mutations to the sub-query won't be reflected
|
|
1196
|
-
const compiled = query instanceof
|
|
1197
|
-
this.
|
|
1190
|
+
const compiled = query instanceof _a ? query.toRaw() : query;
|
|
1191
|
+
this.#state.ctes.push({
|
|
1198
1192
|
name,
|
|
1199
1193
|
query: compiled,
|
|
1200
1194
|
recursive,
|
|
@@ -1204,53 +1198,26 @@ export class QueryBuilder {
|
|
|
1204
1198
|
return this;
|
|
1205
1199
|
}
|
|
1206
1200
|
clone(reset, preserve) {
|
|
1207
|
-
const qb = new
|
|
1208
|
-
reset
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
'_joins',
|
|
1218
|
-
'_joinedProps',
|
|
1219
|
-
'_cond',
|
|
1220
|
-
'_data',
|
|
1221
|
-
'_orderBy',
|
|
1222
|
-
'_schema',
|
|
1223
|
-
'_indexHint',
|
|
1224
|
-
'_collation',
|
|
1225
|
-
'_cache',
|
|
1226
|
-
'subQueries',
|
|
1227
|
-
'lockMode',
|
|
1228
|
-
'lockTables',
|
|
1229
|
-
'_groupBy',
|
|
1230
|
-
'_having',
|
|
1231
|
-
'_returning',
|
|
1232
|
-
'_comments',
|
|
1233
|
-
'_hintComments',
|
|
1234
|
-
'aliasCounter',
|
|
1235
|
-
'_unionQuery',
|
|
1236
|
-
];
|
|
1237
|
-
for (const prop of Object.keys(this)) {
|
|
1238
|
-
if (!preserve?.includes(prop) &&
|
|
1239
|
-
(reset === true || reset.includes(prop) || ['_helper', '_query'].includes(prop))) {
|
|
1240
|
-
continue;
|
|
1201
|
+
const qb = new _a(this.#state.mainAlias.entityName, this.metadata, this.driver, this.context, this.#state.mainAlias.aliasName, this.connectionType, this.em);
|
|
1202
|
+
if (reset !== true) {
|
|
1203
|
+
qb.#state = Utils.copy(this.#state);
|
|
1204
|
+
// CTEs contain NativeQueryBuilder instances that should not be deep-cloned
|
|
1205
|
+
qb.#state.ctes = this.#state.ctes.map(cte => ({ ...cte }));
|
|
1206
|
+
if (Array.isArray(reset)) {
|
|
1207
|
+
const fresh = _a.createDefaultState();
|
|
1208
|
+
for (const key of reset) {
|
|
1209
|
+
qb.#state[key] = fresh[key];
|
|
1210
|
+
}
|
|
1241
1211
|
}
|
|
1242
|
-
qb[prop] = properties.includes(prop) ? Utils.copy(this[prop]) : this[prop];
|
|
1243
|
-
}
|
|
1244
|
-
/* v8 ignore next */
|
|
1245
|
-
if (this._fields && reset !== true && !reset.includes('_fields')) {
|
|
1246
|
-
qb._fields = [...this._fields];
|
|
1247
1212
|
}
|
|
1248
|
-
if (
|
|
1249
|
-
|
|
1213
|
+
else if (preserve) {
|
|
1214
|
+
for (const key of preserve) {
|
|
1215
|
+
qb.#state[key] = Utils.copy(this.#state[key]);
|
|
1216
|
+
}
|
|
1250
1217
|
}
|
|
1251
|
-
qb.
|
|
1252
|
-
qb
|
|
1253
|
-
qb
|
|
1218
|
+
qb.#state.finalized = false;
|
|
1219
|
+
qb.#query = undefined;
|
|
1220
|
+
qb.#helper = qb.createQueryBuilderHelper();
|
|
1254
1221
|
return qb;
|
|
1255
1222
|
}
|
|
1256
1223
|
/**
|
|
@@ -1270,11 +1237,11 @@ export class QueryBuilder {
|
|
|
1270
1237
|
if (typeof meta.expression === 'string') {
|
|
1271
1238
|
return `(${meta.expression}) as ${this.platform.quoteIdentifier(this.alias)}`;
|
|
1272
1239
|
}
|
|
1273
|
-
const res = meta.expression(this.em, this.
|
|
1240
|
+
const res = meta.expression(this.em, this.#state.cond, {});
|
|
1274
1241
|
if (typeof res === 'string') {
|
|
1275
1242
|
return `(${res}) as ${this.platform.quoteIdentifier(this.alias)}`;
|
|
1276
1243
|
}
|
|
1277
|
-
if (res instanceof
|
|
1244
|
+
if (res instanceof _a) {
|
|
1278
1245
|
return `(${res.getFormattedQuery()}) as ${this.platform.quoteIdentifier(this.alias)}`;
|
|
1279
1246
|
}
|
|
1280
1247
|
if (isRaw(res)) {
|
|
@@ -1293,11 +1260,11 @@ export class QueryBuilder {
|
|
|
1293
1260
|
addPropertyJoin(prop, ownerAlias, alias, type, path, schema) {
|
|
1294
1261
|
schema ??= prop.targetMeta?.schema === '*' ? '*' : this.driver.getSchemaName(prop.targetMeta);
|
|
1295
1262
|
const key = `[tpt]${ownerAlias}#${alias}`;
|
|
1296
|
-
this.
|
|
1263
|
+
this.#state.joins[key] =
|
|
1297
1264
|
prop.kind === ReferenceKind.MANY_TO_ONE
|
|
1298
1265
|
? this.helper.joinManyToOneReference(prop, ownerAlias, alias, type, {}, schema)
|
|
1299
1266
|
: this.helper.joinOneToReference(prop, ownerAlias, alias, type, {}, schema);
|
|
1300
|
-
this.
|
|
1267
|
+
this.#state.joins[key].path = path;
|
|
1301
1268
|
return key;
|
|
1302
1269
|
}
|
|
1303
1270
|
joinReference(field, alias, cond, type, path, schema, subquery) {
|
|
@@ -1307,7 +1274,7 @@ export class QueryBuilder {
|
|
|
1307
1274
|
name: '__subquery__',
|
|
1308
1275
|
kind: ReferenceKind.MANY_TO_ONE,
|
|
1309
1276
|
};
|
|
1310
|
-
if (field instanceof
|
|
1277
|
+
if (field instanceof _a) {
|
|
1311
1278
|
prop.type = Utils.className(field.mainAlias.entityName);
|
|
1312
1279
|
prop.targetMeta = field.mainAlias.meta;
|
|
1313
1280
|
field = field.getNativeQuery();
|
|
@@ -1316,7 +1283,7 @@ export class QueryBuilder {
|
|
|
1316
1283
|
field = this.platform.formatQuery(field.sql, field.params);
|
|
1317
1284
|
}
|
|
1318
1285
|
const key = `${this.alias}.${prop.name}#${alias}`;
|
|
1319
|
-
this.
|
|
1286
|
+
this.#state.joins[key] = {
|
|
1320
1287
|
prop,
|
|
1321
1288
|
alias,
|
|
1322
1289
|
type,
|
|
@@ -1332,10 +1299,10 @@ export class QueryBuilder {
|
|
|
1332
1299
|
}
|
|
1333
1300
|
const [fromAlias, fromField] = this.helper.splitField(field);
|
|
1334
1301
|
const q = (str) => `'${str}'`;
|
|
1335
|
-
if (!this.
|
|
1336
|
-
throw new Error(`Trying to join ${q(fromField)} with alias ${q(fromAlias)}, but ${q(fromAlias)} is not a known alias. Available aliases are: ${Object.keys(this.
|
|
1302
|
+
if (!this.#state.aliases[fromAlias]) {
|
|
1303
|
+
throw new Error(`Trying to join ${q(fromField)} with alias ${q(fromAlias)}, but ${q(fromAlias)} is not a known alias. Available aliases are: ${Object.keys(this.#state.aliases).map(q).join(', ')}.`);
|
|
1337
1304
|
}
|
|
1338
|
-
const entityName = this.
|
|
1305
|
+
const entityName = this.#state.aliases[fromAlias].entityName;
|
|
1339
1306
|
const meta = this.metadata.get(entityName);
|
|
1340
1307
|
const prop = meta.properties[fromField];
|
|
1341
1308
|
if (!prop) {
|
|
@@ -1358,10 +1325,10 @@ export class QueryBuilder {
|
|
|
1358
1325
|
const criteriaNode = CriteriaNodeFactory.createNode(this.metadata, prop.targetMeta.class, cond);
|
|
1359
1326
|
cond = criteriaNode.process(this, { ignoreBranching: true, alias });
|
|
1360
1327
|
let aliasedName = `${fromAlias}.${prop.name}#${alias}`;
|
|
1361
|
-
path ??= `${Object.values(this.
|
|
1328
|
+
path ??= `${Object.values(this.#state.joins).find(j => j.alias === fromAlias)?.path ?? Utils.className(entityName)}.${prop.name}`;
|
|
1362
1329
|
if (prop.kind === ReferenceKind.ONE_TO_MANY) {
|
|
1363
|
-
this.
|
|
1364
|
-
this.
|
|
1330
|
+
this.#state.joins[aliasedName] = this.helper.joinOneToReference(prop, fromAlias, alias, type, cond, schema);
|
|
1331
|
+
this.#state.joins[aliasedName].path ??= path;
|
|
1365
1332
|
}
|
|
1366
1333
|
else if (prop.kind === ReferenceKind.MANY_TO_MANY) {
|
|
1367
1334
|
let pivotAlias = alias;
|
|
@@ -1371,19 +1338,19 @@ export class QueryBuilder {
|
|
|
1371
1338
|
aliasedName = `${fromAlias}.${prop.name}#${pivotAlias}`;
|
|
1372
1339
|
}
|
|
1373
1340
|
const joins = this.helper.joinManyToManyReference(prop, fromAlias, alias, pivotAlias, type, cond, path, schema);
|
|
1374
|
-
Object.assign(this.
|
|
1341
|
+
Object.assign(this.#state.joins, joins);
|
|
1375
1342
|
this.createAlias(prop.pivotEntity, pivotAlias);
|
|
1376
|
-
this.
|
|
1343
|
+
this.#state.joins[aliasedName].path ??= path;
|
|
1377
1344
|
aliasedName = Object.keys(joins)[1];
|
|
1378
1345
|
}
|
|
1379
1346
|
else if (prop.kind === ReferenceKind.ONE_TO_ONE) {
|
|
1380
|
-
this.
|
|
1381
|
-
this.
|
|
1347
|
+
this.#state.joins[aliasedName] = this.helper.joinOneToReference(prop, ownerAlias, alias, type, cond, schema);
|
|
1348
|
+
this.#state.joins[aliasedName].path ??= path;
|
|
1382
1349
|
}
|
|
1383
1350
|
else {
|
|
1384
1351
|
// MANY_TO_ONE
|
|
1385
|
-
this.
|
|
1386
|
-
this.
|
|
1352
|
+
this.#state.joins[aliasedName] = this.helper.joinManyToOneReference(prop, ownerAlias, alias, type, cond, schema);
|
|
1353
|
+
this.#state.joins[aliasedName].path ??= path;
|
|
1387
1354
|
}
|
|
1388
1355
|
return { prop, key: aliasedName };
|
|
1389
1356
|
}
|
|
@@ -1406,9 +1373,9 @@ export class QueryBuilder {
|
|
|
1406
1373
|
field = asMatch[1].trim();
|
|
1407
1374
|
customAlias = asMatch[2];
|
|
1408
1375
|
}
|
|
1409
|
-
const join = Object.keys(this.
|
|
1376
|
+
const join = Object.keys(this.#state.joins).find(k => field === k.substring(0, k.indexOf('#')));
|
|
1410
1377
|
if (join && type === 'where') {
|
|
1411
|
-
ret.push(...this.helper.mapJoinColumns(this.type, this.
|
|
1378
|
+
ret.push(...this.helper.mapJoinColumns(this.type, this.#state.joins[join]));
|
|
1412
1379
|
return;
|
|
1413
1380
|
}
|
|
1414
1381
|
const [a, f] = this.helper.splitField(field);
|
|
@@ -1422,7 +1389,7 @@ export class QueryBuilder {
|
|
|
1422
1389
|
}
|
|
1423
1390
|
if (prop?.embedded || (prop?.kind === ReferenceKind.EMBEDDED && prop.object)) {
|
|
1424
1391
|
const name = prop.embeddedPath?.join('.') ?? prop.fieldNames[0];
|
|
1425
|
-
const aliased = this.
|
|
1392
|
+
const aliased = this.#state.aliases[a] ? `${a}.${name}` : name;
|
|
1426
1393
|
ret.push(getFieldName(aliased, customAlias));
|
|
1427
1394
|
return;
|
|
1428
1395
|
}
|
|
@@ -1455,16 +1422,16 @@ export class QueryBuilder {
|
|
|
1455
1422
|
ret.push(getFieldName(field, customAlias));
|
|
1456
1423
|
});
|
|
1457
1424
|
const requiresSQLConversion = this.mainAlias.meta.props.filter(p => p.hasConvertToJSValueSQL && p.persist !== false);
|
|
1458
|
-
if (this.flags.has(QueryFlag.CONVERT_CUSTOM_TYPES) &&
|
|
1425
|
+
if (this.#state.flags.has(QueryFlag.CONVERT_CUSTOM_TYPES) &&
|
|
1459
1426
|
(fields.includes('*') || fields.includes(`${this.mainAlias.aliasName}.*`)) &&
|
|
1460
1427
|
requiresSQLConversion.length > 0) {
|
|
1461
1428
|
for (const p of requiresSQLConversion) {
|
|
1462
1429
|
ret.push(this.helper.mapper(p.name, this.type));
|
|
1463
1430
|
}
|
|
1464
1431
|
}
|
|
1465
|
-
for (const f of Object.keys(this.
|
|
1466
|
-
if (type === 'where' && this.
|
|
1467
|
-
ret.push(...this.helper.mapJoinColumns(this.type, this.
|
|
1432
|
+
for (const f of Object.keys(this.#state.populateMap)) {
|
|
1433
|
+
if (type === 'where' && this.#state.joins[f]) {
|
|
1434
|
+
ret.push(...this.helper.mapJoinColumns(this.type, this.#state.joins[f]));
|
|
1468
1435
|
}
|
|
1469
1436
|
}
|
|
1470
1437
|
return Utils.unique(ret);
|
|
@@ -1480,16 +1447,16 @@ export class QueryBuilder {
|
|
|
1480
1447
|
}
|
|
1481
1448
|
const parts = field.split('.');
|
|
1482
1449
|
// Simple alias.property case - let prepareFields handle it
|
|
1483
|
-
if (parts.length === 2 && this.
|
|
1450
|
+
if (parts.length === 2 && this.#state.aliases[parts[0]]) {
|
|
1484
1451
|
return field;
|
|
1485
1452
|
}
|
|
1486
1453
|
// Start with root alias
|
|
1487
1454
|
let currentAlias = parts[0];
|
|
1488
|
-
let currentMeta = this.
|
|
1489
|
-
? this.metadata.get(this.
|
|
1455
|
+
let currentMeta = this.#state.aliases[currentAlias]
|
|
1456
|
+
? this.metadata.get(this.#state.aliases[currentAlias].entityName)
|
|
1490
1457
|
: this.mainAlias.meta;
|
|
1491
1458
|
// If first part is not an alias, it's a property of the main entity
|
|
1492
|
-
if (!this.
|
|
1459
|
+
if (!this.#state.aliases[currentAlias]) {
|
|
1493
1460
|
currentAlias = this.mainAlias.aliasName;
|
|
1494
1461
|
parts.unshift(currentAlias);
|
|
1495
1462
|
}
|
|
@@ -1527,14 +1494,14 @@ export class QueryBuilder {
|
|
|
1527
1494
|
}
|
|
1528
1495
|
// Find existing join or create new one
|
|
1529
1496
|
const joinPath = parts.slice(0, i + 1).join('.');
|
|
1530
|
-
const existingJoinKey = Object.keys(this.
|
|
1531
|
-
const join = this.
|
|
1497
|
+
const existingJoinKey = Object.keys(this.#state.joins).find(k => {
|
|
1498
|
+
const join = this.#state.joins[k];
|
|
1532
1499
|
// Check by path or by key prefix (key format is `alias.field#joinAlias`)
|
|
1533
1500
|
return join.path === joinPath || k.startsWith(`${currentAlias}.${propName}#`);
|
|
1534
1501
|
});
|
|
1535
1502
|
let joinAlias;
|
|
1536
1503
|
if (existingJoinKey) {
|
|
1537
|
-
joinAlias = this.
|
|
1504
|
+
joinAlias = this.#state.joins[existingJoinKey].alias;
|
|
1538
1505
|
}
|
|
1539
1506
|
else {
|
|
1540
1507
|
joinAlias = this.getNextAlias(prop.targetMeta?.className ?? propName);
|
|
@@ -1551,18 +1518,18 @@ export class QueryBuilder {
|
|
|
1551
1518
|
}
|
|
1552
1519
|
init(type, data, cond) {
|
|
1553
1520
|
this.ensureNotFinalized();
|
|
1554
|
-
this.
|
|
1555
|
-
if ([QueryType.UPDATE, QueryType.DELETE].includes(type) && Utils.hasObjectKeys(this.
|
|
1521
|
+
this.#state.type = type;
|
|
1522
|
+
if ([QueryType.UPDATE, QueryType.DELETE].includes(type) && Utils.hasObjectKeys(this.#state.cond)) {
|
|
1556
1523
|
throw new Error(`You are trying to call \`qb.where().${type.toLowerCase()}()\`. Calling \`qb.${type.toLowerCase()}()\` before \`qb.where()\` is required.`);
|
|
1557
1524
|
}
|
|
1558
1525
|
if (!this.helper.isTableNameAliasRequired(type)) {
|
|
1559
|
-
|
|
1526
|
+
this.#state.fields = undefined;
|
|
1560
1527
|
}
|
|
1561
1528
|
if (data) {
|
|
1562
1529
|
if (Utils.isEntity(data)) {
|
|
1563
1530
|
data = this.em?.getComparator().prepareEntity(data) ?? serialize(data);
|
|
1564
1531
|
}
|
|
1565
|
-
this.
|
|
1532
|
+
this.#state.data = this.helper.processData(data, this.#state.flags.has(QueryFlag.CONVERT_CUSTOM_TYPES), false);
|
|
1566
1533
|
}
|
|
1567
1534
|
if (cond) {
|
|
1568
1535
|
this.where(cond);
|
|
@@ -1570,9 +1537,9 @@ export class QueryBuilder {
|
|
|
1570
1537
|
return this;
|
|
1571
1538
|
}
|
|
1572
1539
|
getQueryBase(processVirtualEntity) {
|
|
1573
|
-
const qb = this.platform.createNativeQueryBuilder().setFlags(this.flags);
|
|
1540
|
+
const qb = this.platform.createNativeQueryBuilder().setFlags(this.#state.flags);
|
|
1574
1541
|
const { subQuery, aliasName, entityName, meta, rawTableName } = this.mainAlias;
|
|
1575
|
-
const requiresAlias = this.finalized && (this.
|
|
1542
|
+
const requiresAlias = this.#state.finalized && (this.#state.explicitAlias || this.helper.isTableNameAliasRequired(this.type));
|
|
1576
1543
|
const alias = requiresAlias ? aliasName : undefined;
|
|
1577
1544
|
const schema = this.getSchema(this.mainAlias);
|
|
1578
1545
|
const tableName = rawTableName
|
|
@@ -1582,42 +1549,42 @@ export class QueryBuilder {
|
|
|
1582
1549
|
: subQuery
|
|
1583
1550
|
? raw(`(${subQuery.sql}) as ${this.platform.quoteIdentifier(aliasName)}`, subQuery.params)
|
|
1584
1551
|
: this.helper.getTableName(entityName);
|
|
1585
|
-
const joinSchema = this.
|
|
1586
|
-
const schemaOverride = this.
|
|
1552
|
+
const joinSchema = this.#state.schema ?? this.em?.schema ?? schema;
|
|
1553
|
+
const schemaOverride = this.#state.schema ?? this.em?.schema;
|
|
1587
1554
|
if (meta.virtual && processVirtualEntity) {
|
|
1588
|
-
qb.from(raw(this.fromVirtual(meta)), { indexHint: this.
|
|
1555
|
+
qb.from(raw(this.fromVirtual(meta)), { indexHint: this.#state.indexHint });
|
|
1589
1556
|
}
|
|
1590
1557
|
else {
|
|
1591
1558
|
qb.from(tableName, {
|
|
1592
1559
|
schema: rawTableName ? undefined : schema,
|
|
1593
1560
|
alias,
|
|
1594
|
-
indexHint: this.
|
|
1561
|
+
indexHint: this.#state.indexHint,
|
|
1595
1562
|
});
|
|
1596
1563
|
}
|
|
1597
1564
|
switch (this.type) {
|
|
1598
1565
|
case QueryType.SELECT:
|
|
1599
|
-
qb.select(this.prepareFields(this.
|
|
1600
|
-
if (this.
|
|
1601
|
-
qb.distinctOn(this.prepareFields(this.
|
|
1566
|
+
qb.select(this.prepareFields(this.#state.fields, 'where', schema));
|
|
1567
|
+
if (this.#state.distinctOn) {
|
|
1568
|
+
qb.distinctOn(this.prepareFields(this.#state.distinctOn, 'where', schema));
|
|
1602
1569
|
}
|
|
1603
|
-
else if (this.flags.has(QueryFlag.DISTINCT)) {
|
|
1570
|
+
else if (this.#state.flags.has(QueryFlag.DISTINCT)) {
|
|
1604
1571
|
qb.distinct();
|
|
1605
1572
|
}
|
|
1606
|
-
this.helper.processJoins(qb, this.
|
|
1573
|
+
this.helper.processJoins(qb, this.#state.joins, joinSchema, schemaOverride);
|
|
1607
1574
|
break;
|
|
1608
1575
|
case QueryType.COUNT: {
|
|
1609
|
-
const fields = this.
|
|
1610
|
-
qb.count(fields, this.flags.has(QueryFlag.DISTINCT));
|
|
1611
|
-
this.helper.processJoins(qb, this.
|
|
1576
|
+
const fields = this.#state.fields.map(f => this.helper.mapper(f, this.type, undefined, undefined, schema));
|
|
1577
|
+
qb.count(fields, this.#state.flags.has(QueryFlag.DISTINCT));
|
|
1578
|
+
this.helper.processJoins(qb, this.#state.joins, joinSchema, schemaOverride);
|
|
1612
1579
|
break;
|
|
1613
1580
|
}
|
|
1614
1581
|
case QueryType.INSERT:
|
|
1615
|
-
qb.insert(this.
|
|
1582
|
+
qb.insert(this.#state.data);
|
|
1616
1583
|
break;
|
|
1617
1584
|
case QueryType.UPDATE:
|
|
1618
|
-
qb.update(this.
|
|
1619
|
-
this.helper.processJoins(qb, this.
|
|
1620
|
-
this.helper.updateVersionProperty(qb, this.
|
|
1585
|
+
qb.update(this.#state.data);
|
|
1586
|
+
this.helper.processJoins(qb, this.#state.joins, joinSchema, schemaOverride);
|
|
1587
|
+
this.helper.updateVersionProperty(qb, this.#state.data);
|
|
1621
1588
|
break;
|
|
1622
1589
|
case QueryType.DELETE:
|
|
1623
1590
|
qb.delete();
|
|
@@ -1668,17 +1635,17 @@ export class QueryBuilder {
|
|
|
1668
1635
|
![QueryType.SELECT, QueryType.COUNT].includes(this.type)) {
|
|
1669
1636
|
return;
|
|
1670
1637
|
}
|
|
1671
|
-
if (this.tptJoinsApplied) {
|
|
1638
|
+
if (this.#state.tptJoinsApplied) {
|
|
1672
1639
|
return;
|
|
1673
1640
|
}
|
|
1674
|
-
this.tptJoinsApplied = true;
|
|
1641
|
+
this.#state.tptJoinsApplied = true;
|
|
1675
1642
|
let childMeta = meta;
|
|
1676
1643
|
let childAlias = this.mainAlias.aliasName;
|
|
1677
1644
|
while (childMeta.tptParent) {
|
|
1678
1645
|
const parentMeta = childMeta.tptParent;
|
|
1679
1646
|
const parentAlias = this.getNextAlias(parentMeta.className);
|
|
1680
1647
|
this.createAlias(parentMeta.class, parentAlias);
|
|
1681
|
-
this.
|
|
1648
|
+
this.#state.tptAlias[parentMeta.className] = parentAlias;
|
|
1682
1649
|
this.addPropertyJoin(childMeta.tptParentProp, childAlias, parentAlias, JoinType.innerJoin, `[tpt]${childMeta.className}`);
|
|
1683
1650
|
childMeta = parentMeta;
|
|
1684
1651
|
childAlias = parentAlias;
|
|
@@ -1694,17 +1661,17 @@ export class QueryBuilder {
|
|
|
1694
1661
|
![QueryType.SELECT, QueryType.COUNT].includes(this.type)) {
|
|
1695
1662
|
return;
|
|
1696
1663
|
}
|
|
1697
|
-
if (!this.
|
|
1664
|
+
if (!this.#state.fields?.includes('*') && !this.#state.fields?.includes(`${this.mainAlias.aliasName}.*`)) {
|
|
1698
1665
|
return;
|
|
1699
1666
|
}
|
|
1700
1667
|
let parentMeta = meta.tptParent;
|
|
1701
1668
|
while (parentMeta) {
|
|
1702
|
-
const parentAlias = this.
|
|
1669
|
+
const parentAlias = this.#state.tptAlias[parentMeta.className];
|
|
1703
1670
|
if (parentAlias) {
|
|
1704
1671
|
const schema = parentMeta.schema === '*' ? '*' : this.driver.getSchemaName(parentMeta);
|
|
1705
1672
|
parentMeta
|
|
1706
1673
|
.ownProps.filter(prop => this.platform.shouldHaveColumn(prop, []))
|
|
1707
|
-
.forEach(prop => this.
|
|
1674
|
+
.forEach(prop => this.#state.fields.push(...this.driver.mapPropToFieldNames(this, prop, parentAlias, parentMeta, schema)));
|
|
1708
1675
|
}
|
|
1709
1676
|
parentMeta = parentMeta.tptParent;
|
|
1710
1677
|
}
|
|
@@ -1719,32 +1686,32 @@ export class QueryBuilder {
|
|
|
1719
1686
|
if (!descendants?.length || ![QueryType.SELECT, QueryType.COUNT].includes(this.type)) {
|
|
1720
1687
|
return;
|
|
1721
1688
|
}
|
|
1722
|
-
if (!this.
|
|
1689
|
+
if (!this.#state.fields?.includes('*') && !this.#state.fields?.includes(`${this.mainAlias.aliasName}.*`)) {
|
|
1723
1690
|
return;
|
|
1724
1691
|
}
|
|
1725
1692
|
// LEFT JOIN each descendant table and add their fields
|
|
1726
1693
|
for (const childMeta of descendants) {
|
|
1727
1694
|
const childAlias = this.getNextAlias(childMeta.className);
|
|
1728
1695
|
this.createAlias(childMeta.class, childAlias);
|
|
1729
|
-
this.
|
|
1696
|
+
this.#state.tptAlias[childMeta.className] = childAlias;
|
|
1730
1697
|
this.addPropertyJoin(childMeta.tptInverseProp, this.mainAlias.aliasName, childAlias, JoinType.leftJoin, `[tpt]${meta.className}`);
|
|
1731
1698
|
// Add child fields
|
|
1732
1699
|
const schema = childMeta.schema === '*' ? '*' : this.driver.getSchemaName(childMeta);
|
|
1733
1700
|
childMeta
|
|
1734
1701
|
.ownProps.filter(prop => !prop.primary && this.platform.shouldHaveColumn(prop, []))
|
|
1735
|
-
.forEach(prop => this.
|
|
1702
|
+
.forEach(prop => this.#state.fields.push(...this.driver.mapPropToFieldNames(this, prop, childAlias, childMeta, schema)));
|
|
1736
1703
|
}
|
|
1737
1704
|
// Add computed discriminator (CASE WHEN to determine concrete type)
|
|
1738
1705
|
// descendants is pre-sorted by depth (deepest first) during discovery
|
|
1739
1706
|
if (meta.tptDiscriminatorColumn) {
|
|
1740
|
-
this.
|
|
1707
|
+
this.#state.fields.push(this.driver.buildTPTDiscriminatorExpression(meta, descendants, this.#state.tptAlias, this.mainAlias.aliasName));
|
|
1741
1708
|
}
|
|
1742
1709
|
}
|
|
1743
1710
|
finalize() {
|
|
1744
|
-
if (this.finalized) {
|
|
1711
|
+
if (this.#state.finalized) {
|
|
1745
1712
|
return;
|
|
1746
1713
|
}
|
|
1747
|
-
if (!this.
|
|
1714
|
+
if (!this.#state.type) {
|
|
1748
1715
|
this.select('*');
|
|
1749
1716
|
}
|
|
1750
1717
|
const meta = this.mainAlias.meta;
|
|
@@ -1754,99 +1721,102 @@ export class QueryBuilder {
|
|
|
1754
1721
|
this.applyTPTPolymorphicJoins();
|
|
1755
1722
|
this.processPopulateHint();
|
|
1756
1723
|
this.processNestedJoins();
|
|
1757
|
-
if (meta && (this.
|
|
1724
|
+
if (meta && (this.#state.fields?.includes('*') || this.#state.fields?.includes(`${this.mainAlias.aliasName}.*`))) {
|
|
1758
1725
|
const schema = this.getSchema(this.mainAlias);
|
|
1759
1726
|
// Create a column mapping with unquoted aliases - quoting should be handled by the user via `quote` helper
|
|
1760
1727
|
// For TPT, use helper to resolve correct alias per property (inherited props use parent alias)
|
|
1761
1728
|
const quotedMainAlias = this.platform.quoteIdentifier(this.mainAlias.aliasName).toString();
|
|
1762
1729
|
const columns = meta.createColumnMappingObject(prop => this.helper.getTPTAliasForProperty(prop.name, this.mainAlias.aliasName), quotedMainAlias);
|
|
1763
1730
|
meta.props
|
|
1764
|
-
.filter(prop => prop.formula && (!prop.lazy || this.flags.has(QueryFlag.INCLUDE_LAZY_FORMULAS)))
|
|
1731
|
+
.filter(prop => prop.formula && (!prop.lazy || this.#state.flags.has(QueryFlag.INCLUDE_LAZY_FORMULAS)))
|
|
1765
1732
|
.map(prop => {
|
|
1766
1733
|
const aliased = this.platform.quoteIdentifier(prop.fieldNames[0]);
|
|
1767
1734
|
const table = this.helper.createFormulaTable(quotedMainAlias, meta, schema);
|
|
1768
1735
|
return `${this.driver.evaluateFormula(prop.formula, columns, table)} as ${aliased}`;
|
|
1769
1736
|
})
|
|
1770
|
-
.filter(field => !this.
|
|
1737
|
+
.filter(field => !this.#state.fields.some(f => {
|
|
1771
1738
|
if (isRaw(f)) {
|
|
1772
1739
|
return f.sql === field && f.params.length === 0;
|
|
1773
1740
|
}
|
|
1774
1741
|
return f === field;
|
|
1775
1742
|
}))
|
|
1776
|
-
.forEach(field => this.
|
|
1743
|
+
.forEach(field => this.#state.fields.push(raw(field)));
|
|
1777
1744
|
}
|
|
1778
|
-
QueryHelper.processObjectParams(this.
|
|
1779
|
-
QueryHelper.processObjectParams(this.
|
|
1780
|
-
QueryHelper.processObjectParams(this.
|
|
1745
|
+
QueryHelper.processObjectParams(this.#state.data);
|
|
1746
|
+
QueryHelper.processObjectParams(this.#state.cond);
|
|
1747
|
+
QueryHelper.processObjectParams(this.#state.having);
|
|
1781
1748
|
// automatically enable paginate flag when we detect to-many joins, but only if there is no `group by` clause
|
|
1782
|
-
if (!this.flags.has(QueryFlag.DISABLE_PAGINATE) &&
|
|
1783
|
-
this.
|
|
1749
|
+
if (!this.#state.flags.has(QueryFlag.DISABLE_PAGINATE) &&
|
|
1750
|
+
this.#state.groupBy.length === 0 &&
|
|
1751
|
+
this.hasToManyJoins()) {
|
|
1752
|
+
this.#state.flags.add(QueryFlag.PAGINATE);
|
|
1784
1753
|
}
|
|
1785
1754
|
if (meta &&
|
|
1786
1755
|
!meta.virtual &&
|
|
1787
|
-
this.flags.has(QueryFlag.PAGINATE) &&
|
|
1788
|
-
!this.flags.has(QueryFlag.DISABLE_PAGINATE) &&
|
|
1789
|
-
(this.
|
|
1756
|
+
this.#state.flags.has(QueryFlag.PAGINATE) &&
|
|
1757
|
+
!this.#state.flags.has(QueryFlag.DISABLE_PAGINATE) &&
|
|
1758
|
+
(this.#state.limit > 0 || this.#state.offset > 0)) {
|
|
1790
1759
|
this.wrapPaginateSubQuery(meta);
|
|
1791
1760
|
}
|
|
1792
|
-
if (meta &&
|
|
1761
|
+
if (meta &&
|
|
1762
|
+
(this.#state.flags.has(QueryFlag.UPDATE_SUB_QUERY) || this.#state.flags.has(QueryFlag.DELETE_SUB_QUERY))) {
|
|
1793
1763
|
this.wrapModifySubQuery(meta);
|
|
1794
1764
|
}
|
|
1795
|
-
this.finalized = true;
|
|
1765
|
+
this.#state.finalized = true;
|
|
1796
1766
|
}
|
|
1797
1767
|
/** @internal */
|
|
1798
1768
|
processPopulateHint() {
|
|
1799
|
-
if (this.populateHintFinalized) {
|
|
1769
|
+
if (this.#state.populateHintFinalized) {
|
|
1800
1770
|
return;
|
|
1801
1771
|
}
|
|
1802
1772
|
const meta = this.mainAlias.meta;
|
|
1803
|
-
if (meta && this.flags.has(QueryFlag.AUTO_JOIN_ONE_TO_ONE_OWNER)) {
|
|
1804
|
-
const relationsToPopulate = this.
|
|
1773
|
+
if (meta && this.#state.flags.has(QueryFlag.AUTO_JOIN_ONE_TO_ONE_OWNER)) {
|
|
1774
|
+
const relationsToPopulate = this.#state.populate.map(({ field }) => field);
|
|
1805
1775
|
meta.relations
|
|
1806
1776
|
.filter(prop => prop.kind === ReferenceKind.ONE_TO_ONE &&
|
|
1807
1777
|
!prop.owner &&
|
|
1808
1778
|
!relationsToPopulate.includes(prop.name) &&
|
|
1809
1779
|
!relationsToPopulate.includes(`${prop.name}:ref`))
|
|
1810
1780
|
.map(prop => ({ field: `${prop.name}:ref` }))
|
|
1811
|
-
.forEach(item => this.
|
|
1781
|
+
.forEach(item => this.#state.populate.push(item));
|
|
1812
1782
|
}
|
|
1813
|
-
this.
|
|
1783
|
+
this.#state.populate.forEach(({ field }) => {
|
|
1814
1784
|
const [fromAlias, fromField] = this.helper.splitField(field);
|
|
1815
1785
|
const aliasedField = `${fromAlias}.${fromField}`;
|
|
1816
|
-
const join = Object.keys(this.
|
|
1817
|
-
if (join && this.
|
|
1818
|
-
this.
|
|
1786
|
+
const join = Object.keys(this.#state.joins).find(k => `${aliasedField}#${this.#state.joins[k].alias}` === k);
|
|
1787
|
+
if (join && this.#state.joins[join] && this.helper.isOneToOneInverse(fromField)) {
|
|
1788
|
+
this.#state.populateMap[join] = this.#state.joins[join].alias;
|
|
1819
1789
|
return;
|
|
1820
1790
|
}
|
|
1821
1791
|
if (meta && this.helper.isOneToOneInverse(fromField)) {
|
|
1822
1792
|
const prop = meta.properties[fromField];
|
|
1823
1793
|
const alias = this.getNextAlias(prop.pivotEntity ?? prop.targetMeta.class);
|
|
1824
1794
|
const aliasedName = `${fromAlias}.${prop.name}#${alias}`;
|
|
1825
|
-
this.
|
|
1826
|
-
this.
|
|
1827
|
-
`${Object.values(this.
|
|
1828
|
-
this.
|
|
1795
|
+
this.#state.joins[aliasedName] = this.helper.joinOneToReference(prop, this.mainAlias.aliasName, alias, JoinType.leftJoin);
|
|
1796
|
+
this.#state.joins[aliasedName].path =
|
|
1797
|
+
`${Object.values(this.#state.joins).find(j => j.alias === fromAlias)?.path ?? meta.className}.${prop.name}`;
|
|
1798
|
+
this.#state.populateMap[aliasedName] = this.#state.joins[aliasedName].alias;
|
|
1829
1799
|
this.createAlias(prop.targetMeta.class, alias);
|
|
1830
1800
|
}
|
|
1831
1801
|
});
|
|
1832
1802
|
this.processPopulateWhere(false);
|
|
1833
1803
|
this.processPopulateWhere(true);
|
|
1834
|
-
this.populateHintFinalized = true;
|
|
1804
|
+
this.#state.populateHintFinalized = true;
|
|
1835
1805
|
}
|
|
1836
1806
|
processPopulateWhere(filter) {
|
|
1837
|
-
const
|
|
1838
|
-
if (
|
|
1807
|
+
const value = filter ? this.#state.populateFilter : this.#state.populateWhere;
|
|
1808
|
+
if (value == null || value === PopulateHint.ALL) {
|
|
1839
1809
|
return;
|
|
1840
1810
|
}
|
|
1841
|
-
let joins = Object.values(this.
|
|
1811
|
+
let joins = Object.values(this.#state.joins);
|
|
1842
1812
|
for (const join of joins) {
|
|
1843
1813
|
join.cond_ ??= join.cond;
|
|
1844
1814
|
join.cond = { ...join.cond };
|
|
1845
1815
|
}
|
|
1846
|
-
if (typeof
|
|
1847
|
-
const cond = CriteriaNodeFactory.createNode(this.metadata, this.mainAlias.entityName,
|
|
1816
|
+
if (typeof value === 'object') {
|
|
1817
|
+
const cond = CriteriaNodeFactory.createNode(this.metadata, this.mainAlias.entityName, value).process(this, { matchPopulateJoins: true, ignoreBranching: true, preferNoBranch: true, filter });
|
|
1848
1818
|
// there might be new joins created by processing the `populateWhere` object
|
|
1849
|
-
joins = Object.values(this.
|
|
1819
|
+
joins = Object.values(this.#state.joins);
|
|
1850
1820
|
this.mergeOnConditions(joins, cond, filter);
|
|
1851
1821
|
}
|
|
1852
1822
|
}
|
|
@@ -1892,10 +1862,10 @@ export class QueryBuilder {
|
|
|
1892
1862
|
* otherwise the inner join could discard rows of the root table.
|
|
1893
1863
|
*/
|
|
1894
1864
|
processNestedJoins() {
|
|
1895
|
-
if (this.flags.has(QueryFlag.DISABLE_NESTED_INNER_JOIN)) {
|
|
1865
|
+
if (this.#state.flags.has(QueryFlag.DISABLE_NESTED_INNER_JOIN)) {
|
|
1896
1866
|
return;
|
|
1897
1867
|
}
|
|
1898
|
-
const joins = Object.values(this.
|
|
1868
|
+
const joins = Object.values(this.#state.joins);
|
|
1899
1869
|
const lookupParentGroup = (j) => {
|
|
1900
1870
|
return j.nested ?? (j.parent ? lookupParentGroup(j.parent) : undefined);
|
|
1901
1871
|
};
|
|
@@ -1918,30 +1888,30 @@ export class QueryBuilder {
|
|
|
1918
1888
|
}
|
|
1919
1889
|
}
|
|
1920
1890
|
hasToManyJoins() {
|
|
1921
|
-
return Object.values(this.
|
|
1891
|
+
return Object.values(this.#state.joins).some(join => {
|
|
1922
1892
|
return [ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(join.prop.kind);
|
|
1923
1893
|
});
|
|
1924
1894
|
}
|
|
1925
1895
|
wrapPaginateSubQuery(meta) {
|
|
1926
1896
|
const schema = this.getSchema(this.mainAlias);
|
|
1927
1897
|
const pks = this.prepareFields(meta.primaryKeys, 'sub-query', schema);
|
|
1928
|
-
const subQuery = this.clone(['
|
|
1898
|
+
const subQuery = this.clone(['orderBy', 'fields', 'lockMode', 'lockTables'])
|
|
1929
1899
|
.select(pks)
|
|
1930
1900
|
.groupBy(pks)
|
|
1931
|
-
.limit(this.
|
|
1901
|
+
.limit(this.#state.limit);
|
|
1932
1902
|
// revert the on conditions added via populateWhere, we want to apply those only once
|
|
1933
|
-
for (const join of Object.values(subQuery.
|
|
1903
|
+
for (const join of Object.values(subQuery.#state.joins)) {
|
|
1934
1904
|
if (join.cond_) {
|
|
1935
1905
|
join.cond = join.cond_;
|
|
1936
1906
|
}
|
|
1937
1907
|
}
|
|
1938
|
-
if (this.
|
|
1939
|
-
subQuery.offset(this.
|
|
1908
|
+
if (this.#state.offset) {
|
|
1909
|
+
subQuery.offset(this.#state.offset);
|
|
1940
1910
|
}
|
|
1941
1911
|
const addToSelect = [];
|
|
1942
|
-
if (this.
|
|
1912
|
+
if (this.#state.orderBy.length > 0) {
|
|
1943
1913
|
const orderBy = [];
|
|
1944
|
-
for (const orderMap of this.
|
|
1914
|
+
for (const orderMap of this.#state.orderBy) {
|
|
1945
1915
|
for (const field of Utils.getObjectQueryKeys(orderMap)) {
|
|
1946
1916
|
const direction = orderMap[field];
|
|
1947
1917
|
if (RawQueryFragment.isKnownFragmentSymbol(field)) {
|
|
@@ -1962,11 +1932,11 @@ export class QueryBuilder {
|
|
|
1962
1932
|
}
|
|
1963
1933
|
subQuery.orderBy(orderBy);
|
|
1964
1934
|
}
|
|
1965
|
-
subQuery.finalized = true;
|
|
1935
|
+
subQuery.#state.finalized = true;
|
|
1966
1936
|
const innerQuery = subQuery.as(this.mainAlias.aliasName).clear('select').select(pks);
|
|
1967
1937
|
if (addToSelect.length > 0) {
|
|
1968
1938
|
addToSelect.forEach(prop => {
|
|
1969
|
-
const field = this.
|
|
1939
|
+
const field = this.#state.fields.find(field => {
|
|
1970
1940
|
if (typeof field === 'object' && field && '__as' in field) {
|
|
1971
1941
|
return field.__as === prop;
|
|
1972
1942
|
}
|
|
@@ -1992,18 +1962,18 @@ export class QueryBuilder {
|
|
|
1992
1962
|
// https://stackoverflow.com/questions/17892762/mysql-this-version-of-mysql-doesnt-yet-support-limit-in-all-any-some-subqu
|
|
1993
1963
|
const subSubQuery = this.platform.createNativeQueryBuilder();
|
|
1994
1964
|
subSubQuery.select(pks).from(innerQuery);
|
|
1995
|
-
this.
|
|
1996
|
-
this.
|
|
1965
|
+
this.#state.limit = undefined;
|
|
1966
|
+
this.#state.offset = undefined;
|
|
1997
1967
|
// Save the original WHERE conditions before pruning joins
|
|
1998
|
-
const originalCond = this.
|
|
1968
|
+
const originalCond = this.#state.cond;
|
|
1999
1969
|
const populatePaths = this.getPopulatePaths();
|
|
2000
|
-
if (!this.
|
|
1970
|
+
if (!this.#state.fields.some(field => isRaw(field))) {
|
|
2001
1971
|
this.pruneJoinsForPagination(meta, populatePaths);
|
|
2002
1972
|
}
|
|
2003
1973
|
// Transfer WHERE conditions to ORDER BY joins (GH #6160)
|
|
2004
1974
|
this.transferConditionsForOrderByJoins(meta, originalCond, populatePaths);
|
|
2005
1975
|
const { sql, params } = subSubQuery.compile();
|
|
2006
|
-
this.select(this.
|
|
1976
|
+
this.select(this.#state.fields).where({
|
|
2007
1977
|
[Utils.getPrimaryKeyHash(meta.primaryKeys)]: { $in: raw(sql, params) },
|
|
2008
1978
|
});
|
|
2009
1979
|
}
|
|
@@ -2022,7 +1992,7 @@ export class QueryBuilder {
|
|
|
2022
1992
|
}
|
|
2023
1993
|
}
|
|
2024
1994
|
}
|
|
2025
|
-
addPath(this.
|
|
1995
|
+
addPath(this.#state.populate);
|
|
2026
1996
|
return paths;
|
|
2027
1997
|
}
|
|
2028
1998
|
normalizeJoinPath(join, meta) {
|
|
@@ -2034,14 +2004,14 @@ export class QueryBuilder {
|
|
|
2034
2004
|
* GH #6160
|
|
2035
2005
|
*/
|
|
2036
2006
|
transferConditionsForOrderByJoins(meta, cond, populatePaths) {
|
|
2037
|
-
if (!cond || this.
|
|
2007
|
+
if (!cond || this.#state.orderBy.length === 0) {
|
|
2038
2008
|
return;
|
|
2039
2009
|
}
|
|
2040
|
-
const orderByAliases = new Set(this.
|
|
2010
|
+
const orderByAliases = new Set(this.#state.orderBy
|
|
2041
2011
|
.flatMap(hint => Object.keys(hint))
|
|
2042
2012
|
.filter(k => !RawQueryFragment.isKnownFragmentSymbol(k))
|
|
2043
2013
|
.map(k => k.split('.')[0]));
|
|
2044
|
-
for (const join of Object.values(this.
|
|
2014
|
+
for (const join of Object.values(this.#state.joins)) {
|
|
2045
2015
|
const joinPath = this.normalizeJoinPath(join, meta);
|
|
2046
2016
|
const isPopulateJoin = populatePaths.has(joinPath);
|
|
2047
2017
|
// Only transfer conditions for joins used for ORDER BY but not for population
|
|
@@ -2054,8 +2024,8 @@ export class QueryBuilder {
|
|
|
2054
2024
|
* Removes joins that are not used for population or ordering to improve performance.
|
|
2055
2025
|
*/
|
|
2056
2026
|
pruneJoinsForPagination(meta, populatePaths) {
|
|
2057
|
-
const orderByAliases = this.
|
|
2058
|
-
const joins = Object.entries(this.
|
|
2027
|
+
const orderByAliases = this.#state.orderBy.flatMap(hint => Object.keys(hint)).map(k => k.split('.')[0]);
|
|
2028
|
+
const joins = Object.entries(this.#state.joins);
|
|
2059
2029
|
const rootAlias = this.alias;
|
|
2060
2030
|
function addParentAlias(alias) {
|
|
2061
2031
|
const join = joins.find(j => j[1].alias === alias);
|
|
@@ -2070,7 +2040,7 @@ export class QueryBuilder {
|
|
|
2070
2040
|
for (const [key, join] of joins) {
|
|
2071
2041
|
const path = this.normalizeJoinPath(join, meta);
|
|
2072
2042
|
if (!populatePaths.has(path) && !orderByAliases.includes(join.alias)) {
|
|
2073
|
-
delete this.
|
|
2043
|
+
delete this.#state.joins[key];
|
|
2074
2044
|
}
|
|
2075
2045
|
}
|
|
2076
2046
|
}
|
|
@@ -2102,25 +2072,25 @@ export class QueryBuilder {
|
|
|
2102
2072
|
}
|
|
2103
2073
|
wrapModifySubQuery(meta) {
|
|
2104
2074
|
const subQuery = this.clone();
|
|
2105
|
-
subQuery.finalized = true;
|
|
2075
|
+
subQuery.#state.finalized = true;
|
|
2106
2076
|
// wrap one more time to get around MySQL limitations
|
|
2107
2077
|
// https://stackoverflow.com/questions/45494/mysql-error-1093-cant-specify-target-table-for-update-in-from-clause
|
|
2108
2078
|
const subSubQuery = this.platform.createNativeQueryBuilder();
|
|
2109
|
-
const method = this.flags.has(QueryFlag.UPDATE_SUB_QUERY) ? 'update' : 'delete';
|
|
2079
|
+
const method = this.#state.flags.has(QueryFlag.UPDATE_SUB_QUERY) ? 'update' : 'delete';
|
|
2110
2080
|
const schema = this.getSchema(this.mainAlias);
|
|
2111
2081
|
const pks = this.prepareFields(meta.primaryKeys, 'sub-query', schema);
|
|
2112
|
-
this.
|
|
2113
|
-
this.
|
|
2082
|
+
this.#state.cond = {}; // otherwise we would trigger validation error
|
|
2083
|
+
this.#state.joins = {}; // included in the subquery
|
|
2114
2084
|
subSubQuery.select(pks).from(subQuery.as(this.mainAlias.aliasName));
|
|
2115
2085
|
const { sql, params } = subSubQuery.compile();
|
|
2116
|
-
this[method](this.
|
|
2086
|
+
this[method](this.#state.data).where({
|
|
2117
2087
|
[Utils.getPrimaryKeyHash(meta.primaryKeys)]: { $in: raw(sql, params) },
|
|
2118
2088
|
});
|
|
2119
2089
|
}
|
|
2120
2090
|
getSchema(alias) {
|
|
2121
2091
|
const { meta } = alias;
|
|
2122
2092
|
const metaSchema = meta.schema && meta.schema !== '*' ? meta.schema : undefined;
|
|
2123
|
-
const schema = this.
|
|
2093
|
+
const schema = this.#state.schema ?? metaSchema ?? this.em?.schema ?? this.em?.config.getSchema(true);
|
|
2124
2094
|
if (schema === this.platform.getDefaultSchemaName()) {
|
|
2125
2095
|
return undefined;
|
|
2126
2096
|
}
|
|
@@ -2130,51 +2100,51 @@ export class QueryBuilder {
|
|
|
2130
2100
|
createAlias(entityName, aliasName, subQuery) {
|
|
2131
2101
|
const meta = this.metadata.find(entityName);
|
|
2132
2102
|
const alias = { aliasName, entityName, meta, subQuery };
|
|
2133
|
-
this.
|
|
2103
|
+
this.#state.aliases[aliasName] = alias;
|
|
2134
2104
|
return alias;
|
|
2135
2105
|
}
|
|
2136
2106
|
createMainAlias(entityName, aliasName, subQuery) {
|
|
2137
|
-
this.
|
|
2138
|
-
this
|
|
2139
|
-
return this.
|
|
2107
|
+
this.#state.mainAlias = this.createAlias(entityName, aliasName, subQuery);
|
|
2108
|
+
this.#helper = this.createQueryBuilderHelper();
|
|
2109
|
+
return this.#state.mainAlias;
|
|
2140
2110
|
}
|
|
2141
2111
|
fromSubQuery(target, aliasName) {
|
|
2142
2112
|
const { entityName } = target.mainAlias;
|
|
2143
2113
|
aliasName ??= this.getNextAlias(entityName);
|
|
2144
|
-
const subQuery = target.
|
|
2114
|
+
const subQuery = target.#state.unionQuery ? target.toRaw() : target.getNativeQuery();
|
|
2145
2115
|
this.createMainAlias(entityName, aliasName, subQuery);
|
|
2146
2116
|
}
|
|
2147
2117
|
fromEntityName(entityName, aliasName) {
|
|
2148
|
-
aliasName ??= this.
|
|
2118
|
+
aliasName ??= this.#state.mainAlias?.aliasName ?? this.getNextAlias(entityName);
|
|
2149
2119
|
this.createMainAlias(entityName, aliasName);
|
|
2150
2120
|
}
|
|
2151
2121
|
fromRawTable(tableName, aliasName) {
|
|
2152
|
-
aliasName ??= this.
|
|
2122
|
+
aliasName ??= this.#state.mainAlias?.aliasName ?? this.getNextAlias(tableName);
|
|
2153
2123
|
const meta = new EntityMetadata({
|
|
2154
2124
|
className: tableName,
|
|
2155
2125
|
collection: tableName,
|
|
2156
2126
|
});
|
|
2157
2127
|
meta.root = meta;
|
|
2158
|
-
this.
|
|
2128
|
+
this.#state.mainAlias = {
|
|
2159
2129
|
aliasName,
|
|
2160
2130
|
entityName: tableName,
|
|
2161
2131
|
meta,
|
|
2162
2132
|
rawTableName: tableName,
|
|
2163
2133
|
};
|
|
2164
|
-
this.
|
|
2165
|
-
this
|
|
2134
|
+
this.#state.aliases[aliasName] = this.#state.mainAlias;
|
|
2135
|
+
this.#helper = this.createQueryBuilderHelper();
|
|
2166
2136
|
}
|
|
2167
2137
|
createQueryBuilderHelper() {
|
|
2168
|
-
return new QueryBuilderHelper(this.mainAlias.entityName, this.mainAlias.aliasName, this.
|
|
2138
|
+
return new QueryBuilderHelper(this.mainAlias.entityName, this.mainAlias.aliasName, this.#state.aliases, this.#state.subQueries, this.driver, this.#state.tptAlias);
|
|
2169
2139
|
}
|
|
2170
2140
|
ensureFromClause() {
|
|
2171
2141
|
/* v8 ignore next */
|
|
2172
|
-
if (!this.
|
|
2142
|
+
if (!this.#state.mainAlias) {
|
|
2173
2143
|
throw new Error(`Cannot proceed to build a query because the main alias is not set.`);
|
|
2174
2144
|
}
|
|
2175
2145
|
}
|
|
2176
2146
|
ensureNotFinalized() {
|
|
2177
|
-
if (this.finalized) {
|
|
2147
|
+
if (this.#state.finalized) {
|
|
2178
2148
|
throw new Error('This QueryBuilder instance is already finalized, clone it first if you want to modify it.');
|
|
2179
2149
|
}
|
|
2180
2150
|
}
|
|
@@ -2191,26 +2161,27 @@ export class QueryBuilder {
|
|
|
2191
2161
|
.forEach(k => delete object[k]);
|
|
2192
2162
|
hidden.forEach(k => delete object[k]);
|
|
2193
2163
|
let prefix = this.type ? this.type.substring(0, 1) + this.type.toLowerCase().substring(1) : '';
|
|
2194
|
-
if (this.
|
|
2195
|
-
object.data = this.
|
|
2164
|
+
if (this.#state.data) {
|
|
2165
|
+
object.data = this.#state.data;
|
|
2196
2166
|
}
|
|
2197
|
-
if (this.
|
|
2198
|
-
object.schema = this.
|
|
2167
|
+
if (this.#state.schema) {
|
|
2168
|
+
object.schema = this.#state.schema;
|
|
2199
2169
|
}
|
|
2200
|
-
if (!Utils.isEmpty(this.
|
|
2201
|
-
object.where = this.
|
|
2170
|
+
if (!Utils.isEmpty(this.#state.cond)) {
|
|
2171
|
+
object.where = this.#state.cond;
|
|
2202
2172
|
}
|
|
2203
|
-
if (this.
|
|
2173
|
+
if (this.#state.onConflict?.[0]) {
|
|
2204
2174
|
prefix = 'Upsert';
|
|
2205
|
-
object.onConflict = this.
|
|
2175
|
+
object.onConflict = this.#state.onConflict[0];
|
|
2206
2176
|
}
|
|
2207
|
-
if (!Utils.isEmpty(this.
|
|
2208
|
-
object.orderBy = this.
|
|
2177
|
+
if (!Utils.isEmpty(this.#state.orderBy)) {
|
|
2178
|
+
object.orderBy = this.#state.orderBy;
|
|
2209
2179
|
}
|
|
2210
|
-
const name = this.
|
|
2211
|
-
? `${prefix}QueryBuilder<${Utils.className(this.
|
|
2180
|
+
const name = this.#state.mainAlias
|
|
2181
|
+
? `${prefix}QueryBuilder<${Utils.className(this.#state.mainAlias?.entityName)}>`
|
|
2212
2182
|
: 'QueryBuilder';
|
|
2213
2183
|
const ret = inspect(object, { depth });
|
|
2214
2184
|
return ret === '[Object]' ? `[${name}]` : name + ' ' + ret;
|
|
2215
2185
|
}
|
|
2216
2186
|
}
|
|
2187
|
+
_a = QueryBuilder;
|