@mikro-orm/knex 6.0.0-dev.11 → 6.0.0-dev.110
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/AbstractSqlConnection.d.ts +8 -4
- package/AbstractSqlConnection.js +30 -18
- package/AbstractSqlDriver.d.ts +16 -17
- package/AbstractSqlDriver.js +271 -113
- package/AbstractSqlPlatform.d.ts +5 -4
- package/AbstractSqlPlatform.js +34 -5
- package/MonkeyPatchable.d.ts +1 -0
- package/MonkeyPatchable.js +3 -0
- package/README.md +64 -107
- package/SqlEntityManager.d.ts +2 -6
- package/SqlEntityManager.js +5 -9
- package/SqlEntityRepository.d.ts +7 -6
- package/SqlEntityRepository.js +11 -8
- package/index.mjs +22 -6
- package/package.json +8 -8
- package/query/ArrayCriteriaNode.d.ts +3 -3
- package/query/CriteriaNode.d.ts +8 -8
- package/query/CriteriaNode.js +16 -9
- package/query/CriteriaNodeFactory.d.ts +6 -6
- package/query/CriteriaNodeFactory.js +10 -13
- package/query/ObjectCriteriaNode.d.ts +3 -3
- package/query/ObjectCriteriaNode.js +12 -8
- package/query/QueryBuilder.d.ts +39 -19
- package/query/QueryBuilder.js +331 -111
- package/query/QueryBuilderHelper.d.ts +9 -13
- package/query/QueryBuilderHelper.js +153 -107
- package/query/ScalarCriteriaNode.d.ts +3 -2
- package/query/ScalarCriteriaNode.js +9 -6
- package/query/enums.js +1 -1
- package/schema/DatabaseSchema.d.ts +5 -2
- package/schema/DatabaseSchema.js +26 -8
- package/schema/DatabaseTable.d.ts +4 -2
- package/schema/DatabaseTable.js +54 -29
- package/schema/SchemaComparator.js +12 -2
- package/schema/SchemaHelper.d.ts +6 -4
- package/schema/SchemaHelper.js +11 -4
- package/schema/SqlSchemaGenerator.d.ts +3 -6
- package/schema/SqlSchemaGenerator.js +61 -28
- package/typings.d.ts +13 -7
package/query/QueryBuilder.js
CHANGED
|
@@ -26,6 +26,12 @@ const CriteriaNodeFactory_1 = require("./CriteriaNodeFactory");
|
|
|
26
26
|
* ```
|
|
27
27
|
*/
|
|
28
28
|
class QueryBuilder {
|
|
29
|
+
metadata;
|
|
30
|
+
driver;
|
|
31
|
+
context;
|
|
32
|
+
connectionType;
|
|
33
|
+
em;
|
|
34
|
+
logging;
|
|
29
35
|
get mainAlias() {
|
|
30
36
|
this.ensureFromClause();
|
|
31
37
|
return this._mainAlias;
|
|
@@ -37,31 +43,56 @@ class QueryBuilder {
|
|
|
37
43
|
this.ensureFromClause();
|
|
38
44
|
return this._helper;
|
|
39
45
|
}
|
|
46
|
+
/** @internal */
|
|
47
|
+
type;
|
|
48
|
+
/** @internal */
|
|
49
|
+
_fields;
|
|
50
|
+
/** @internal */
|
|
51
|
+
_populate = [];
|
|
52
|
+
/** @internal */
|
|
53
|
+
_populateWhere;
|
|
54
|
+
/** @internal */
|
|
55
|
+
_populateMap = {};
|
|
56
|
+
aliasCounter = 0;
|
|
57
|
+
flags = new Set([core_1.QueryFlag.CONVERT_CUSTOM_TYPES]);
|
|
58
|
+
finalized = false;
|
|
59
|
+
_joins = {};
|
|
60
|
+
_explicitAlias = false;
|
|
61
|
+
_schema;
|
|
62
|
+
_cond = {};
|
|
63
|
+
_data;
|
|
64
|
+
_orderBy = [];
|
|
65
|
+
_groupBy = [];
|
|
66
|
+
_having = {};
|
|
67
|
+
_returning;
|
|
68
|
+
_onConflict;
|
|
69
|
+
_limit;
|
|
70
|
+
_offset;
|
|
71
|
+
_distinctOn;
|
|
72
|
+
_joinedProps = new Map();
|
|
73
|
+
_cache;
|
|
74
|
+
_indexHint;
|
|
75
|
+
_comments = [];
|
|
76
|
+
_hintComments = [];
|
|
77
|
+
flushMode;
|
|
78
|
+
lockMode;
|
|
79
|
+
lockTables;
|
|
80
|
+
subQueries = {};
|
|
81
|
+
_mainAlias;
|
|
82
|
+
_aliases = {};
|
|
83
|
+
_helper;
|
|
84
|
+
platform;
|
|
85
|
+
knex;
|
|
40
86
|
/**
|
|
41
87
|
* @internal
|
|
42
88
|
*/
|
|
43
|
-
constructor(entityName, metadata, driver, context, alias, connectionType, em) {
|
|
89
|
+
constructor(entityName, metadata, driver, context, alias, connectionType, em, logging) {
|
|
44
90
|
this.metadata = metadata;
|
|
45
91
|
this.driver = driver;
|
|
46
92
|
this.context = context;
|
|
47
93
|
this.connectionType = connectionType;
|
|
48
94
|
this.em = em;
|
|
49
|
-
|
|
50
|
-
this._populate = [];
|
|
51
|
-
/** @internal */
|
|
52
|
-
this._populateMap = {};
|
|
53
|
-
this.aliasCounter = 0;
|
|
54
|
-
this.flags = new Set([core_1.QueryFlag.CONVERT_CUSTOM_TYPES]);
|
|
55
|
-
this.finalized = false;
|
|
56
|
-
this._joins = {};
|
|
57
|
-
this._explicitAlias = false;
|
|
58
|
-
this._cond = {};
|
|
59
|
-
this._orderBy = [];
|
|
60
|
-
this._groupBy = [];
|
|
61
|
-
this._having = {};
|
|
62
|
-
this._joinedProps = new Map();
|
|
63
|
-
this.subQueries = {};
|
|
64
|
-
this._aliases = {};
|
|
95
|
+
this.logging = logging;
|
|
65
96
|
this.platform = this.driver.getPlatform();
|
|
66
97
|
this.knex = this.driver.getConnection(this.connectionType).getKnex();
|
|
67
98
|
if (alias) {
|
|
@@ -116,27 +147,39 @@ class QueryBuilder {
|
|
|
116
147
|
this._fields = this.mainAlias.metadata.primaryKeys;
|
|
117
148
|
}
|
|
118
149
|
else {
|
|
119
|
-
this._fields = [
|
|
150
|
+
this._fields = [(0, core_1.raw)('*')];
|
|
120
151
|
}
|
|
121
152
|
if (distinct) {
|
|
122
153
|
this.flags.add(core_1.QueryFlag.DISTINCT);
|
|
123
154
|
}
|
|
124
155
|
return this.init(enums_1.QueryType.COUNT);
|
|
125
156
|
}
|
|
126
|
-
join(field, alias, cond = {}, type = 'innerJoin', path) {
|
|
127
|
-
this.joinReference(field, alias, cond, type, path);
|
|
157
|
+
join(field, alias, cond = {}, type = 'innerJoin', path, schema) {
|
|
158
|
+
this.joinReference(field, alias, cond, type, path, schema);
|
|
159
|
+
return this;
|
|
160
|
+
}
|
|
161
|
+
innerJoin(field, alias, cond = {}, schema) {
|
|
162
|
+
this.join(field, alias, cond, 'innerJoin', undefined, schema);
|
|
128
163
|
return this;
|
|
129
164
|
}
|
|
130
|
-
leftJoin(field, alias, cond = {}) {
|
|
131
|
-
return this.join(field, alias, cond, 'leftJoin');
|
|
165
|
+
leftJoin(field, alias, cond = {}, schema) {
|
|
166
|
+
return this.join(field, alias, cond, 'leftJoin', undefined, schema);
|
|
132
167
|
}
|
|
133
|
-
joinAndSelect(field, alias, cond = {}, type = 'innerJoin', path) {
|
|
168
|
+
joinAndSelect(field, alias, cond = {}, type = 'innerJoin', path, fields, schema) {
|
|
134
169
|
if (!this.type) {
|
|
135
170
|
this.select('*');
|
|
136
171
|
}
|
|
137
|
-
|
|
138
|
-
|
|
172
|
+
let subquery;
|
|
173
|
+
if (Array.isArray(field)) {
|
|
174
|
+
subquery = field[1] instanceof QueryBuilder ? field[1].getFormattedQuery() : field[1].toString();
|
|
175
|
+
field = field[0];
|
|
176
|
+
}
|
|
177
|
+
const prop = this.joinReference(field, alias, cond, type, path, schema);
|
|
139
178
|
const [fromAlias] = this.helper.splitField(field);
|
|
179
|
+
if (subquery) {
|
|
180
|
+
this._joins[`${fromAlias}.${prop.name}#${alias}`].subquery = subquery;
|
|
181
|
+
}
|
|
182
|
+
this.addSelect(this.getFieldsForJoinedLoad(prop, alias, fields));
|
|
140
183
|
const populate = this._joinedProps.get(fromAlias);
|
|
141
184
|
const item = { field: prop.name, strategy: core_1.LoadStrategy.JOINED, children: [] };
|
|
142
185
|
if (populate) {
|
|
@@ -148,13 +191,16 @@ class QueryBuilder {
|
|
|
148
191
|
this._joinedProps.set(alias, item);
|
|
149
192
|
return this;
|
|
150
193
|
}
|
|
151
|
-
leftJoinAndSelect(field, alias, cond = {}) {
|
|
152
|
-
return this.joinAndSelect(field, alias, cond, 'leftJoin');
|
|
194
|
+
leftJoinAndSelect(field, alias, cond = {}, fields, schema) {
|
|
195
|
+
return this.joinAndSelect(field, alias, cond, 'leftJoin', undefined, fields, schema);
|
|
153
196
|
}
|
|
154
|
-
|
|
197
|
+
innerJoinAndSelect(field, alias, cond = {}, fields, schema) {
|
|
198
|
+
return this.joinAndSelect(field, alias, cond, 'innerJoin', undefined, fields, schema);
|
|
199
|
+
}
|
|
200
|
+
getFieldsForJoinedLoad(prop, alias, explicitFields) {
|
|
155
201
|
const fields = [];
|
|
156
202
|
prop.targetMeta.props
|
|
157
|
-
.filter(prop => this.platform.shouldHaveColumn(prop, this._populate))
|
|
203
|
+
.filter(prop => explicitFields ? explicitFields.includes(prop.name) || prop.primary : this.platform.shouldHaveColumn(prop, this._populate))
|
|
158
204
|
.forEach(prop => fields.push(...this.driver.mapPropToFieldNames(this, prop, alias)));
|
|
159
205
|
return fields;
|
|
160
206
|
}
|
|
@@ -165,9 +211,15 @@ class QueryBuilder {
|
|
|
165
211
|
}
|
|
166
212
|
where(cond, params, operator) {
|
|
167
213
|
this.ensureNotFinalized();
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
214
|
+
const rawField = core_1.RawQueryFragment.getKnownFragment(cond);
|
|
215
|
+
if (rawField) {
|
|
216
|
+
const sql = this.platform.formatQuery(rawField.sql, rawField.params);
|
|
217
|
+
cond = { [(0, core_1.raw)(`(${sql})`)]: core_1.Utils.asArray(params) };
|
|
218
|
+
operator ??= '$and';
|
|
219
|
+
}
|
|
220
|
+
else if (core_1.Utils.isString(cond)) {
|
|
221
|
+
cond = { [(0, core_1.raw)(`(${cond})`, core_1.Utils.asArray(params))]: [] };
|
|
222
|
+
operator ??= '$and';
|
|
171
223
|
}
|
|
172
224
|
else {
|
|
173
225
|
cond = core_1.QueryHelper.processWhere({
|
|
@@ -235,15 +287,22 @@ class QueryBuilder {
|
|
|
235
287
|
having(cond = {}, params) {
|
|
236
288
|
this.ensureNotFinalized();
|
|
237
289
|
if (core_1.Utils.isString(cond)) {
|
|
238
|
-
cond = { [`(${cond})
|
|
290
|
+
cond = { [(0, core_1.raw)(`(${cond})`, params)]: [] };
|
|
239
291
|
}
|
|
240
292
|
this._having = CriteriaNodeFactory_1.CriteriaNodeFactory.createNode(this.metadata, this.mainAlias.entityName, cond).process(this);
|
|
241
293
|
return this;
|
|
242
294
|
}
|
|
243
295
|
onConflict(fields = []) {
|
|
296
|
+
const meta = this.mainAlias.metadata;
|
|
244
297
|
this.ensureNotFinalized();
|
|
245
|
-
this._onConflict
|
|
246
|
-
this._onConflict.push({
|
|
298
|
+
this._onConflict ??= [];
|
|
299
|
+
this._onConflict.push({
|
|
300
|
+
fields: core_1.Utils.asArray(fields).flatMap(f => {
|
|
301
|
+
const key = f.toString();
|
|
302
|
+
/* istanbul ignore next */
|
|
303
|
+
return meta.properties[key]?.fieldNames ?? [key];
|
|
304
|
+
}),
|
|
305
|
+
});
|
|
247
306
|
return this;
|
|
248
307
|
}
|
|
249
308
|
ignore() {
|
|
@@ -263,6 +322,10 @@ class QueryBuilder {
|
|
|
263
322
|
this._onConflict[this._onConflict.length - 1].merge = data;
|
|
264
323
|
return this;
|
|
265
324
|
}
|
|
325
|
+
returning(fields) {
|
|
326
|
+
this._returning = fields != null ? core_1.Utils.asArray(fields) : fields;
|
|
327
|
+
return this;
|
|
328
|
+
}
|
|
266
329
|
/**
|
|
267
330
|
* @internal
|
|
268
331
|
*/
|
|
@@ -272,17 +335,6 @@ class QueryBuilder {
|
|
|
272
335
|
this._populateWhere = populateWhere;
|
|
273
336
|
return this;
|
|
274
337
|
}
|
|
275
|
-
/**
|
|
276
|
-
* @internal
|
|
277
|
-
*/
|
|
278
|
-
ref(field) {
|
|
279
|
-
return this.knex.ref(field);
|
|
280
|
-
}
|
|
281
|
-
raw(sql, bindings = []) {
|
|
282
|
-
const raw = this.knex.raw(sql, bindings);
|
|
283
|
-
raw.__raw = true; // tag it as there is now way to check via `instanceof`
|
|
284
|
-
return raw;
|
|
285
|
-
}
|
|
286
338
|
limit(limit, offset = 0) {
|
|
287
339
|
this.ensureNotFinalized();
|
|
288
340
|
this._limit = limit;
|
|
@@ -338,6 +390,24 @@ class QueryBuilder {
|
|
|
338
390
|
this._indexHint = sql;
|
|
339
391
|
return this;
|
|
340
392
|
}
|
|
393
|
+
/**
|
|
394
|
+
* Prepend comment to the sql query using the syntax `/* ... *‍/`. Some characters are forbidden such as `/*, *‍/` and `?`.
|
|
395
|
+
*/
|
|
396
|
+
comment(comment) {
|
|
397
|
+
this.ensureNotFinalized();
|
|
398
|
+
this._comments.push(...core_1.Utils.asArray(comment));
|
|
399
|
+
return this;
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Add hints to the query using comment-like syntax `/*+ ... *‍/`. MySQL and Oracle use this syntax for optimizer hints.
|
|
403
|
+
* Also various DB proxies and routers use this syntax to pass hints to alter their behavior. In other dialects the hints
|
|
404
|
+
* are ignored as simple comments.
|
|
405
|
+
*/
|
|
406
|
+
hintComment(comment) {
|
|
407
|
+
this.ensureNotFinalized();
|
|
408
|
+
this._hintComments.push(...core_1.Utils.asArray(comment));
|
|
409
|
+
return this;
|
|
410
|
+
}
|
|
341
411
|
from(target, aliasName) {
|
|
342
412
|
this.ensureNotFinalized();
|
|
343
413
|
if (target instanceof QueryBuilder) {
|
|
@@ -355,17 +425,21 @@ class QueryBuilder {
|
|
|
355
425
|
getKnexQuery() {
|
|
356
426
|
this.finalize();
|
|
357
427
|
const qb = this.getQueryBase();
|
|
428
|
+
qb.__raw = true; // tag it as there is now way to check via `instanceof`
|
|
358
429
|
core_1.Utils.runIfNotEmpty(() => this.helper.appendQueryCondition(this.type ?? enums_1.QueryType.SELECT, this._cond, qb), this._cond && !this._onConflict);
|
|
359
430
|
core_1.Utils.runIfNotEmpty(() => qb.groupBy(this.prepareFields(this._groupBy, 'groupBy')), this._groupBy);
|
|
360
431
|
core_1.Utils.runIfNotEmpty(() => this.helper.appendQueryCondition(this.type ?? enums_1.QueryType.SELECT, this._having, qb, undefined, 'having'), this._having);
|
|
361
432
|
core_1.Utils.runIfNotEmpty(() => {
|
|
362
433
|
const queryOrder = this.helper.getQueryOrder(this.type ?? enums_1.QueryType.SELECT, this._orderBy, this._populateMap);
|
|
363
434
|
if (queryOrder) {
|
|
364
|
-
|
|
435
|
+
qb.orderByRaw(queryOrder);
|
|
436
|
+
return;
|
|
365
437
|
}
|
|
366
438
|
}, this._orderBy);
|
|
367
439
|
core_1.Utils.runIfNotEmpty(() => qb.limit(this._limit), this._limit != null);
|
|
368
440
|
core_1.Utils.runIfNotEmpty(() => qb.offset(this._offset), this._offset);
|
|
441
|
+
core_1.Utils.runIfNotEmpty(() => this._comments.forEach(comment => qb.comment(comment)), this._comments);
|
|
442
|
+
core_1.Utils.runIfNotEmpty(() => this._hintComments.forEach(comment => qb.hintComment(comment)), this._hintComments);
|
|
369
443
|
core_1.Utils.runIfNotEmpty(() => this.helper.appendOnConflictClause(this.type ?? enums_1.QueryType.SELECT, this._onConflict, qb), this._onConflict);
|
|
370
444
|
if (this.type === enums_1.QueryType.TRUNCATE && this.platform.usesCascadeStatement()) {
|
|
371
445
|
return this.knex.raw(qb.toSQL().toNative().sql + ' cascade');
|
|
@@ -373,26 +447,35 @@ class QueryBuilder {
|
|
|
373
447
|
if (this.lockMode) {
|
|
374
448
|
this.helper.getLockSQL(qb, this.lockMode, this.lockTables);
|
|
375
449
|
}
|
|
376
|
-
this.helper.finalize(this.type ?? enums_1.QueryType.SELECT, qb, this.mainAlias.metadata);
|
|
450
|
+
this.helper.finalize(this.type ?? enums_1.QueryType.SELECT, qb, this.mainAlias.metadata, this._data, this._returning);
|
|
377
451
|
return qb;
|
|
378
452
|
}
|
|
379
453
|
/**
|
|
380
454
|
* Returns the query with parameters as wildcards.
|
|
381
455
|
*/
|
|
382
456
|
getQuery() {
|
|
383
|
-
return this.
|
|
457
|
+
return this.toQuery().sql;
|
|
458
|
+
}
|
|
459
|
+
#query;
|
|
460
|
+
toQuery() {
|
|
461
|
+
if (this.#query) {
|
|
462
|
+
return this.#query;
|
|
463
|
+
}
|
|
464
|
+
const sql = this.getKnexQuery().toSQL();
|
|
465
|
+
const query = sql.toNative();
|
|
466
|
+
return this.#query = { sql: query.sql, params: query.bindings ?? [], _sql: sql };
|
|
384
467
|
}
|
|
385
468
|
/**
|
|
386
469
|
* Returns the list of all parameters for this query.
|
|
387
470
|
*/
|
|
388
471
|
getParams() {
|
|
389
|
-
return this.
|
|
472
|
+
return this.toQuery().params;
|
|
390
473
|
}
|
|
391
474
|
/**
|
|
392
475
|
* Returns raw interpolated query string with all the parameters inlined.
|
|
393
476
|
*/
|
|
394
477
|
getFormattedQuery() {
|
|
395
|
-
const query = this.
|
|
478
|
+
const query = this.toQuery()._sql;
|
|
396
479
|
return this.platform.formatQuery(query.sql, query.bindings);
|
|
397
480
|
}
|
|
398
481
|
/**
|
|
@@ -434,7 +517,7 @@ class QueryBuilder {
|
|
|
434
517
|
return cached.data;
|
|
435
518
|
}
|
|
436
519
|
const type = this.connectionType || (method === 'run' ? 'write' : 'read');
|
|
437
|
-
const res = await this.driver.getConnection(type).execute(query.sql, query.bindings, method, this.context);
|
|
520
|
+
const res = await this.driver.getConnection(type).execute(query.sql, query.bindings, method, this.context, this.logging);
|
|
438
521
|
const meta = this.mainAlias.metadata;
|
|
439
522
|
if (!mapResults || !meta) {
|
|
440
523
|
await this.em?.storeCache(this._cache, cached, res);
|
|
@@ -463,9 +546,29 @@ class QueryBuilder {
|
|
|
463
546
|
await this.em.tryFlush(this.mainAlias.entityName, { flushMode: this.flushMode });
|
|
464
547
|
let res = await this.execute('all', true);
|
|
465
548
|
if (this._joinedProps.size > 0) {
|
|
466
|
-
res = this.driver.mergeJoinedResult(res, this.mainAlias.metadata);
|
|
549
|
+
res = this.driver.mergeJoinedResult(res, this.mainAlias.metadata, [...this._joinedProps.values()]);
|
|
550
|
+
}
|
|
551
|
+
const entities = [];
|
|
552
|
+
function propagatePopulateHint(entity, hint) {
|
|
553
|
+
(0, core_1.helper)(entity).__serializationContext.populate ??= hint;
|
|
554
|
+
hint.forEach(pop => {
|
|
555
|
+
const value = entity[pop.field];
|
|
556
|
+
if (core_1.Utils.isEntity(value, true)) {
|
|
557
|
+
(0, core_1.helper)(value).populated();
|
|
558
|
+
propagatePopulateHint(value, pop.children ?? []);
|
|
559
|
+
}
|
|
560
|
+
else if (core_1.Utils.isCollection(value)) {
|
|
561
|
+
value.populated();
|
|
562
|
+
value.getItems(false).forEach(item => propagatePopulateHint(item, pop.children ?? []));
|
|
563
|
+
}
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
for (const r of res) {
|
|
567
|
+
const entity = this.em.map(this.mainAlias.entityName, r, { schema: this._schema });
|
|
568
|
+
propagatePopulateHint(entity, this._populate);
|
|
569
|
+
entities.push(entity);
|
|
467
570
|
}
|
|
468
|
-
return
|
|
571
|
+
return entities;
|
|
469
572
|
}
|
|
470
573
|
/**
|
|
471
574
|
* Executes the query, returning the first result or null
|
|
@@ -483,17 +586,30 @@ class QueryBuilder {
|
|
|
483
586
|
res = await this.execute('get', false);
|
|
484
587
|
}
|
|
485
588
|
else {
|
|
486
|
-
const qb = this.clone();
|
|
589
|
+
const qb = this.type === undefined ? this : this.clone();
|
|
487
590
|
qb.count(field, distinct ?? qb.hasToManyJoins()).limit(undefined).offset(undefined).orderBy([]);
|
|
488
591
|
res = await qb.execute('get', false);
|
|
489
592
|
}
|
|
490
593
|
return res ? +res.count : 0;
|
|
491
594
|
}
|
|
595
|
+
/**
|
|
596
|
+
* Executes the query, returning both array of results and total count query (without offset and limit).
|
|
597
|
+
*/
|
|
598
|
+
async getResultAndCount() {
|
|
599
|
+
return Promise.all([
|
|
600
|
+
this.getResultList(),
|
|
601
|
+
this.getCount(),
|
|
602
|
+
]);
|
|
603
|
+
}
|
|
492
604
|
/**
|
|
493
605
|
* Provides promise-like interface so we can await the QB instance.
|
|
494
606
|
*/
|
|
495
607
|
then(onfulfilled, onrejected) {
|
|
496
|
-
|
|
608
|
+
let type = this.type ?? enums_1.QueryType.SELECT;
|
|
609
|
+
if (this.flags.has(core_1.QueryFlag.UPDATE_SUB_QUERY) || this.flags.has(core_1.QueryFlag.DELETE_SUB_QUERY)) {
|
|
610
|
+
type = enums_1.QueryType.UPDATE;
|
|
611
|
+
}
|
|
612
|
+
switch (type) {
|
|
497
613
|
case enums_1.QueryType.INSERT:
|
|
498
614
|
case enums_1.QueryType.UPDATE:
|
|
499
615
|
case enums_1.QueryType.DELETE:
|
|
@@ -516,7 +632,10 @@ class QueryBuilder {
|
|
|
516
632
|
/* istanbul ignore next */
|
|
517
633
|
alias = meta?.properties[f]?.fieldNames[0] ?? alias;
|
|
518
634
|
}
|
|
519
|
-
|
|
635
|
+
const ret = qb.as(alias);
|
|
636
|
+
// tag the instance, so it is possible to detect it easily
|
|
637
|
+
Object.defineProperty(ret, '__as', { enumerable: false, value: alias });
|
|
638
|
+
return ret;
|
|
520
639
|
}
|
|
521
640
|
clone() {
|
|
522
641
|
const qb = new QueryBuilder(this.mainAlias.entityName, this.metadata, this.driver, this.context, this.mainAlias.aliasName, this.connectionType, this.em);
|
|
@@ -524,7 +643,8 @@ class QueryBuilder {
|
|
|
524
643
|
// clone array/object properties
|
|
525
644
|
const properties = [
|
|
526
645
|
'flags', '_populate', '_populateWhere', '_populateMap', '_joins', '_joinedProps', '_cond', '_data', '_orderBy',
|
|
527
|
-
'_schema', '_indexHint', '_cache', 'subQueries', 'lockMode', 'lockTables',
|
|
646
|
+
'_schema', '_indexHint', '_cache', 'subQueries', 'lockMode', 'lockTables', '_groupBy', '_having', '_returning',
|
|
647
|
+
'_comments', '_hintComments',
|
|
528
648
|
];
|
|
529
649
|
properties.forEach(prop => qb[prop] = core_1.Utils.copy(this[prop]));
|
|
530
650
|
/* istanbul ignore else */
|
|
@@ -552,14 +672,39 @@ class QueryBuilder {
|
|
|
552
672
|
}
|
|
553
673
|
return qb;
|
|
554
674
|
}
|
|
555
|
-
joinReference(field, alias, cond, type, path) {
|
|
675
|
+
joinReference(field, alias, cond, type, path, schema) {
|
|
556
676
|
this.ensureNotFinalized();
|
|
677
|
+
if (typeof field === 'object') {
|
|
678
|
+
const prop = {
|
|
679
|
+
name: '__subquery__',
|
|
680
|
+
kind: core_1.ReferenceKind.MANY_TO_ONE,
|
|
681
|
+
};
|
|
682
|
+
if (field instanceof QueryBuilder) {
|
|
683
|
+
prop.type = field.mainAlias.entityName;
|
|
684
|
+
prop.targetMeta = field.mainAlias.metadata;
|
|
685
|
+
field = field.getKnexQuery();
|
|
686
|
+
}
|
|
687
|
+
this._joins[`${this.alias}.${prop.name}#${alias}`] = {
|
|
688
|
+
prop,
|
|
689
|
+
alias,
|
|
690
|
+
type,
|
|
691
|
+
cond,
|
|
692
|
+
schema,
|
|
693
|
+
subquery: field.toString(),
|
|
694
|
+
ownerAlias: this.alias,
|
|
695
|
+
};
|
|
696
|
+
return prop;
|
|
697
|
+
}
|
|
557
698
|
const [fromAlias, fromField] = this.helper.splitField(field);
|
|
558
|
-
const
|
|
699
|
+
const q = (str) => `'${str}'`;
|
|
700
|
+
if (!this._aliases[fromAlias]) {
|
|
701
|
+
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._aliases).map(q).join(', ')}.`);
|
|
702
|
+
}
|
|
703
|
+
const entityName = this._aliases[fromAlias].entityName;
|
|
559
704
|
const meta = this.metadata.get(entityName);
|
|
560
705
|
const prop = meta.properties[fromField];
|
|
561
706
|
if (!prop) {
|
|
562
|
-
throw new Error(`Trying to join ${field}, but ${fromField} is not a defined relation on ${meta.className}
|
|
707
|
+
throw new Error(`Trying to join ${q(field)}, but ${q(fromField)} is not a defined relation on ${meta.className}.`);
|
|
563
708
|
}
|
|
564
709
|
this.createAlias(prop.type, alias);
|
|
565
710
|
cond = core_1.QueryHelper.processWhere({
|
|
@@ -571,26 +716,26 @@ class QueryBuilder {
|
|
|
571
716
|
aliased: !this.type || [enums_1.QueryType.SELECT, enums_1.QueryType.COUNT].includes(this.type),
|
|
572
717
|
});
|
|
573
718
|
let aliasedName = `${fromAlias}.${prop.name}#${alias}`;
|
|
574
|
-
path
|
|
575
|
-
if (prop.
|
|
576
|
-
this._joins[aliasedName] = this.helper.joinOneToReference(prop, fromAlias, alias, type, cond);
|
|
719
|
+
path ??= `${(Object.values(this._joins).find(j => j.alias === fromAlias)?.path ?? entityName)}.${prop.name}`;
|
|
720
|
+
if (prop.kind === core_1.ReferenceKind.ONE_TO_MANY) {
|
|
721
|
+
this._joins[aliasedName] = this.helper.joinOneToReference(prop, fromAlias, alias, type, cond, schema);
|
|
577
722
|
}
|
|
578
|
-
else if (prop.
|
|
723
|
+
else if (prop.kind === core_1.ReferenceKind.MANY_TO_MANY) {
|
|
579
724
|
let pivotAlias = alias;
|
|
580
725
|
if (type !== 'pivotJoin') {
|
|
581
726
|
const oldPivotAlias = this.getAliasForJoinPath(path + '[pivot]');
|
|
582
727
|
pivotAlias = oldPivotAlias ?? this.getNextAlias(prop.pivotEntity);
|
|
583
728
|
aliasedName = `${fromAlias}.${prop.name}#${pivotAlias}`;
|
|
584
729
|
}
|
|
585
|
-
const joins = this.helper.joinManyToManyReference(prop, fromAlias, alias, pivotAlias, type, cond, path);
|
|
730
|
+
const joins = this.helper.joinManyToManyReference(prop, fromAlias, alias, pivotAlias, type, cond, path, schema);
|
|
586
731
|
Object.assign(this._joins, joins);
|
|
587
732
|
this.createAlias(prop.pivotEntity, pivotAlias);
|
|
588
733
|
}
|
|
589
|
-
else if (prop.
|
|
590
|
-
this._joins[aliasedName] = this.helper.joinOneToReference(prop, fromAlias, alias, type, cond);
|
|
734
|
+
else if (prop.kind === core_1.ReferenceKind.ONE_TO_ONE) {
|
|
735
|
+
this._joins[aliasedName] = this.helper.joinOneToReference(prop, fromAlias, alias, type, cond, schema);
|
|
591
736
|
}
|
|
592
737
|
else { // MANY_TO_ONE
|
|
593
|
-
this._joins[aliasedName] = this.helper.joinManyToOneReference(prop, fromAlias, alias, type, cond);
|
|
738
|
+
this._joins[aliasedName] = this.helper.joinManyToOneReference(prop, fromAlias, alias, type, cond, schema);
|
|
594
739
|
}
|
|
595
740
|
if (!this._joins[aliasedName].path && path) {
|
|
596
741
|
this._joins[aliasedName].path = path;
|
|
@@ -600,25 +745,34 @@ class QueryBuilder {
|
|
|
600
745
|
prepareFields(fields, type = 'where') {
|
|
601
746
|
const ret = [];
|
|
602
747
|
fields.forEach(field => {
|
|
748
|
+
const rawField = core_1.RawQueryFragment.getKnownFragment(field);
|
|
749
|
+
if (rawField) {
|
|
750
|
+
const sql = this.platform.formatQuery(rawField.sql, rawField.params);
|
|
751
|
+
ret.push(this.knex.raw(sql));
|
|
752
|
+
return;
|
|
753
|
+
}
|
|
603
754
|
if (!core_1.Utils.isString(field)) {
|
|
604
|
-
|
|
755
|
+
ret.push(field);
|
|
756
|
+
return;
|
|
605
757
|
}
|
|
606
758
|
const join = Object.keys(this._joins).find(k => field === k.substring(0, k.indexOf('#')));
|
|
607
759
|
if (join && type === 'where') {
|
|
608
|
-
|
|
760
|
+
ret.push(...this.helper.mapJoinColumns(this.type ?? enums_1.QueryType.SELECT, this._joins[join]));
|
|
761
|
+
return;
|
|
609
762
|
}
|
|
610
763
|
const [a, f] = this.helper.splitField(field);
|
|
611
764
|
const prop = this.helper.getProperty(f, a);
|
|
612
765
|
/* istanbul ignore next */
|
|
613
|
-
if (prop && [core_1.
|
|
766
|
+
if (prop && [core_1.ReferenceKind.ONE_TO_MANY, core_1.ReferenceKind.MANY_TO_MANY].includes(prop.kind)) {
|
|
614
767
|
return;
|
|
615
768
|
}
|
|
616
769
|
if (prop?.embedded) {
|
|
617
|
-
const
|
|
770
|
+
const name = this._aliases[a] ? `${a}.${prop.fieldNames[0]}` : prop.fieldNames[0];
|
|
771
|
+
const fieldName = this.helper.mapper(name, this.type);
|
|
618
772
|
ret.push(fieldName);
|
|
619
773
|
return;
|
|
620
774
|
}
|
|
621
|
-
if (prop?.
|
|
775
|
+
if (prop?.kind === core_1.ReferenceKind.EMBEDDED) {
|
|
622
776
|
if (prop.object) {
|
|
623
777
|
ret.push(this.helper.mapper(prop.fieldNames[0], this.type));
|
|
624
778
|
}
|
|
@@ -637,11 +791,15 @@ class QueryBuilder {
|
|
|
637
791
|
}
|
|
638
792
|
return;
|
|
639
793
|
}
|
|
794
|
+
if (prop && prop.fieldNames.length > 1) {
|
|
795
|
+
ret.push(...prop.fieldNames.map(f => this.helper.mapper(f, this.type)));
|
|
796
|
+
return;
|
|
797
|
+
}
|
|
640
798
|
ret.push(this.helper.mapper(field, this.type));
|
|
641
799
|
});
|
|
642
800
|
const meta = this.mainAlias.metadata;
|
|
643
801
|
/* istanbul ignore next */
|
|
644
|
-
const requiresSQLConversion = meta?.props.filter(p => p.
|
|
802
|
+
const requiresSQLConversion = meta?.props.filter(p => p.hasConvertToJSValueSQL) ?? [];
|
|
645
803
|
if (this.flags.has(core_1.QueryFlag.CONVERT_CUSTOM_TYPES) && (fields.includes('*') || fields.includes(`${this.mainAlias.aliasName}.*`)) && requiresSQLConversion.length > 0) {
|
|
646
804
|
requiresSQLConversion.forEach(p => ret.push(this.helper.mapper(p.name, this.type)));
|
|
647
805
|
}
|
|
@@ -650,7 +808,7 @@ class QueryBuilder {
|
|
|
650
808
|
const cols = this.helper.mapJoinColumns(this.type ?? enums_1.QueryType.SELECT, this._joins[f]);
|
|
651
809
|
ret.push(...cols);
|
|
652
810
|
}
|
|
653
|
-
if (this._joins[f].prop.
|
|
811
|
+
if (this._joins[f].prop.kind !== core_1.ReferenceKind.ONE_TO_ONE && this._joins[f].inverseJoinColumns) {
|
|
654
812
|
this._joins[f].inverseJoinColumns.forEach(inverseJoinColumn => {
|
|
655
813
|
core_1.Utils.renameKey(this._cond, inverseJoinColumn, `${this._joins[f].alias}.${inverseJoinColumn}`);
|
|
656
814
|
});
|
|
@@ -669,7 +827,7 @@ class QueryBuilder {
|
|
|
669
827
|
}
|
|
670
828
|
if (data) {
|
|
671
829
|
if (core_1.Utils.isEntity(data)) {
|
|
672
|
-
data = (0, core_1.
|
|
830
|
+
data = this.em?.getComparator().prepareEntity(data) ?? (0, core_1.serialize)(data);
|
|
673
831
|
}
|
|
674
832
|
this._data = this.helper.processData(data, this.flags.has(core_1.QueryFlag.CONVERT_CUSTOM_TYPES));
|
|
675
833
|
}
|
|
@@ -723,6 +881,24 @@ class QueryBuilder {
|
|
|
723
881
|
}
|
|
724
882
|
return qb;
|
|
725
883
|
}
|
|
884
|
+
applyDiscriminatorCondition() {
|
|
885
|
+
const meta = this.mainAlias.metadata;
|
|
886
|
+
if (!meta?.discriminatorValue) {
|
|
887
|
+
return;
|
|
888
|
+
}
|
|
889
|
+
const types = Object.values(meta.root.discriminatorMap).map(cls => this.metadata.find(cls));
|
|
890
|
+
const children = [];
|
|
891
|
+
const lookUpChildren = (ret, type) => {
|
|
892
|
+
const children = types.filter(meta2 => meta2.extends === type);
|
|
893
|
+
children.forEach(m => lookUpChildren(ret, m.className));
|
|
894
|
+
ret.push(...children.filter(c => c.discriminatorValue));
|
|
895
|
+
return children;
|
|
896
|
+
};
|
|
897
|
+
lookUpChildren(children, meta.className);
|
|
898
|
+
this.andWhere({
|
|
899
|
+
[meta.root.discriminatorColumn]: children.length > 0 ? { $in: [meta.discriminatorValue, ...children.map(c => c.discriminatorValue)] } : meta.discriminatorValue,
|
|
900
|
+
});
|
|
901
|
+
}
|
|
726
902
|
finalize() {
|
|
727
903
|
if (this.finalized) {
|
|
728
904
|
return;
|
|
@@ -731,10 +907,11 @@ class QueryBuilder {
|
|
|
731
907
|
this.select('*');
|
|
732
908
|
}
|
|
733
909
|
const meta = this.mainAlias.metadata;
|
|
910
|
+
this.applyDiscriminatorCondition();
|
|
734
911
|
if (meta && this.flags.has(core_1.QueryFlag.AUTO_JOIN_ONE_TO_ONE_OWNER)) {
|
|
735
912
|
const relationsToPopulate = this._populate.map(({ field }) => field);
|
|
736
913
|
meta.relations
|
|
737
|
-
.filter(prop => prop.
|
|
914
|
+
.filter(prop => prop.kind === core_1.ReferenceKind.ONE_TO_ONE && !prop.owner && !relationsToPopulate.includes(prop.name))
|
|
738
915
|
.map(prop => ({ field: prop.name }))
|
|
739
916
|
.forEach(item => this._populate.push(item));
|
|
740
917
|
}
|
|
@@ -743,12 +920,10 @@ class QueryBuilder {
|
|
|
743
920
|
const aliasedField = `${fromAlias}.${fromField}`;
|
|
744
921
|
const join = Object.keys(this._joins).find(k => `${aliasedField}#${this._joins[k].alias}` === k);
|
|
745
922
|
if (join && this._joins[join] && this.helper.isOneToOneInverse(fromField)) {
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
if (this.metadata.find(field)?.pivotTable) { // pivot table entity
|
|
749
|
-
this.autoJoinPivotTable(field);
|
|
923
|
+
this._populateMap[join] = this._joins[join].alias;
|
|
924
|
+
return;
|
|
750
925
|
}
|
|
751
|
-
|
|
926
|
+
if (meta && this.helper.isOneToOneInverse(fromField)) {
|
|
752
927
|
const prop = meta.properties[fromField];
|
|
753
928
|
const alias = this.getNextAlias(prop.pivotEntity ?? prop.type);
|
|
754
929
|
const aliasedName = `${fromAlias}.${prop.name}#${alias}`;
|
|
@@ -764,14 +939,20 @@ class QueryBuilder {
|
|
|
764
939
|
const aliased = this.knex.ref(prop.fieldNames[0]).toString();
|
|
765
940
|
return `${prop.formula(alias)} as ${aliased}`;
|
|
766
941
|
})
|
|
767
|
-
.filter(field => !this._fields.
|
|
768
|
-
|
|
942
|
+
.filter(field => !this._fields.some(f => {
|
|
943
|
+
if (f instanceof core_1.RawQueryFragment) {
|
|
944
|
+
return f.sql === field && f.params.length === 0;
|
|
945
|
+
}
|
|
946
|
+
return f === field;
|
|
947
|
+
}))
|
|
948
|
+
.forEach(field => this._fields.push((0, core_1.raw)(field)));
|
|
769
949
|
}
|
|
950
|
+
this.processPopulateWhere();
|
|
770
951
|
core_1.QueryHelper.processObjectParams(this._data);
|
|
771
952
|
core_1.QueryHelper.processObjectParams(this._cond);
|
|
772
953
|
core_1.QueryHelper.processObjectParams(this._having);
|
|
773
|
-
// automatically enable paginate flag when we detect to-many joins
|
|
774
|
-
if (!this.flags.has(core_1.QueryFlag.DISABLE_PAGINATE) && this.hasToManyJoins()) {
|
|
954
|
+
// automatically enable paginate flag when we detect to-many joins, but only if there is no `group by` clause
|
|
955
|
+
if (!this.flags.has(core_1.QueryFlag.DISABLE_PAGINATE) && this._groupBy.length === 0 && this.hasToManyJoins()) {
|
|
775
956
|
this.flags.add(core_1.QueryFlag.PAGINATE);
|
|
776
957
|
}
|
|
777
958
|
if (meta && this.flags.has(core_1.QueryFlag.PAGINATE) && (this._limit > 0 || this._offset > 0)) {
|
|
@@ -782,17 +963,54 @@ class QueryBuilder {
|
|
|
782
963
|
}
|
|
783
964
|
this.finalized = true;
|
|
784
965
|
}
|
|
966
|
+
processPopulateWhere() {
|
|
967
|
+
if (this._populateWhere == null || this._populateWhere === core_1.PopulateHint.ALL) {
|
|
968
|
+
return;
|
|
969
|
+
}
|
|
970
|
+
const joins = Object.values(this._joins);
|
|
971
|
+
joins.forEach(join => {
|
|
972
|
+
join.cond_ = join.cond;
|
|
973
|
+
join.cond = {};
|
|
974
|
+
});
|
|
975
|
+
const replaceOnConditions = (cond) => {
|
|
976
|
+
Object.keys(cond).forEach(k => {
|
|
977
|
+
if (core_1.Utils.isOperator(k)) {
|
|
978
|
+
if (Array.isArray(cond[k])) {
|
|
979
|
+
return cond[k].forEach((c) => replaceOnConditions(c));
|
|
980
|
+
}
|
|
981
|
+
return replaceOnConditions(cond[k]);
|
|
982
|
+
}
|
|
983
|
+
const [a] = this.helper.splitField(k);
|
|
984
|
+
const join = joins.find(j => j.alias === a);
|
|
985
|
+
if (join) {
|
|
986
|
+
join.cond = { ...join.cond, [k]: cond[k] };
|
|
987
|
+
}
|
|
988
|
+
});
|
|
989
|
+
};
|
|
990
|
+
if (this._populateWhere === core_1.PopulateHint.INFER) {
|
|
991
|
+
replaceOnConditions(this._cond);
|
|
992
|
+
}
|
|
993
|
+
else if (typeof this._populateWhere === 'object') {
|
|
994
|
+
const cond = CriteriaNodeFactory_1.CriteriaNodeFactory
|
|
995
|
+
.createNode(this.metadata, this.mainAlias.entityName, this._populateWhere)
|
|
996
|
+
.process(this);
|
|
997
|
+
replaceOnConditions(cond);
|
|
998
|
+
}
|
|
999
|
+
}
|
|
785
1000
|
hasToManyJoins() {
|
|
786
1001
|
return Object.values(this._joins).some(join => {
|
|
787
|
-
return [core_1.
|
|
1002
|
+
return [core_1.ReferenceKind.ONE_TO_MANY, core_1.ReferenceKind.MANY_TO_MANY].includes(join.prop.kind);
|
|
788
1003
|
});
|
|
789
1004
|
}
|
|
790
1005
|
wrapPaginateSubQuery(meta) {
|
|
791
1006
|
const pks = this.prepareFields(meta.primaryKeys, 'sub-query');
|
|
792
1007
|
const subQuery = this.clone().select(pks).groupBy(pks).limit(this._limit);
|
|
1008
|
+
// revert the on conditions added via populateWhere, we want to apply those only once
|
|
1009
|
+
Object.values(subQuery._joins).forEach(join => join.cond = join.cond_ ?? {});
|
|
793
1010
|
if (this._offset) {
|
|
794
1011
|
subQuery.offset(this._offset);
|
|
795
1012
|
}
|
|
1013
|
+
const addToSelect = [];
|
|
796
1014
|
if (this._orderBy.length > 0) {
|
|
797
1015
|
const orderBy = [];
|
|
798
1016
|
for (const orderMap of this._orderBy) {
|
|
@@ -800,28 +1018,38 @@ class QueryBuilder {
|
|
|
800
1018
|
const [a, f] = this.helper.splitField(field);
|
|
801
1019
|
const prop = this.helper.getProperty(f, a);
|
|
802
1020
|
const type = this.platform.castColumn(prop);
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
1021
|
+
const fieldName = this.helper.mapper(field, this.type, undefined, null);
|
|
1022
|
+
if (!prop?.persist && !prop?.formula) {
|
|
1023
|
+
addToSelect.push(fieldName);
|
|
1024
|
+
}
|
|
1025
|
+
orderBy.push({ [(0, core_1.raw)(`min(${this.knex.ref(fieldName)}${type})`)]: direction });
|
|
806
1026
|
}
|
|
807
1027
|
}
|
|
808
1028
|
subQuery.orderBy(orderBy);
|
|
809
1029
|
}
|
|
810
1030
|
subQuery.finalized = true;
|
|
811
1031
|
const knexQuery = subQuery.as(this.mainAlias.aliasName).clearSelect().select(pks);
|
|
1032
|
+
if (addToSelect.length > 0) {
|
|
1033
|
+
addToSelect.forEach(prop => {
|
|
1034
|
+
const field = this._fields.find(field => {
|
|
1035
|
+
if (typeof field === 'object' && field && '__as' in field) {
|
|
1036
|
+
return field.__as === prop;
|
|
1037
|
+
}
|
|
1038
|
+
// not perfect, but should work most of the time, ideally we should check only the alias (`... as alias`)
|
|
1039
|
+
return field.toString().includes(prop);
|
|
1040
|
+
});
|
|
1041
|
+
if (field) {
|
|
1042
|
+
knexQuery.select(field);
|
|
1043
|
+
}
|
|
1044
|
+
});
|
|
1045
|
+
}
|
|
812
1046
|
// multiple sub-queries are needed to get around mysql limitations with order by + limit + where in + group by (o.O)
|
|
813
1047
|
// https://stackoverflow.com/questions/17892762/mysql-this-version-of-mysql-doesnt-yet-support-limit-in-all-any-some-subqu
|
|
814
1048
|
const subSubQuery = this.getKnex().select(pks).from(knexQuery);
|
|
1049
|
+
subSubQuery.__raw = true; // tag it as there is now way to check via `instanceof`
|
|
815
1050
|
this._limit = undefined;
|
|
816
1051
|
this._offset = undefined;
|
|
817
|
-
const cond = this._cond;
|
|
818
1052
|
this.select(this._fields).where({ [core_1.Utils.getPrimaryKeyHash(meta.primaryKeys)]: { $in: subSubQuery } });
|
|
819
|
-
if (this._populateWhere === core_1.PopulateHint.INFER) {
|
|
820
|
-
this.andWhere(cond);
|
|
821
|
-
}
|
|
822
|
-
else if (typeof this._populateWhere === 'object') {
|
|
823
|
-
this.andWhere(this._populateWhere);
|
|
824
|
-
}
|
|
825
1053
|
}
|
|
826
1054
|
wrapModifySubQuery(meta) {
|
|
827
1055
|
const subQuery = this.clone();
|
|
@@ -835,17 +1063,6 @@ class QueryBuilder {
|
|
|
835
1063
|
[core_1.Utils.getPrimaryKeyHash(meta.primaryKeys)]: { $in: subSubQuery },
|
|
836
1064
|
});
|
|
837
1065
|
}
|
|
838
|
-
autoJoinPivotTable(field) {
|
|
839
|
-
const pivotMeta = this.metadata.find(field);
|
|
840
|
-
const owner = pivotMeta.relations[0];
|
|
841
|
-
const inverse = pivotMeta.relations[1];
|
|
842
|
-
const prop = this._cond[pivotMeta.name + '.' + owner.name] || this._orderBy[pivotMeta.name + '.' + owner.name] ? inverse : owner;
|
|
843
|
-
const pivotAlias = this.getNextAlias(pivotMeta.name);
|
|
844
|
-
this._joins[field] = this.helper.joinPivotTable(field, prop, this.mainAlias.aliasName, pivotAlias, 'leftJoin');
|
|
845
|
-
core_1.Utils.renameKey(this._cond, `${field}.${owner.name}`, core_1.Utils.getPrimaryKeyHash(owner.fieldNames.map(fieldName => `${pivotAlias}.${fieldName}`)));
|
|
846
|
-
core_1.Utils.renameKey(this._cond, `${field}.${inverse.name}`, core_1.Utils.getPrimaryKeyHash(inverse.fieldNames.map(fieldName => `${pivotAlias}.${fieldName}`)));
|
|
847
|
-
this._populateMap[field] = this._joins[field].alias;
|
|
848
|
-
}
|
|
849
1066
|
getSchema(alias) {
|
|
850
1067
|
const { metadata } = alias;
|
|
851
1068
|
const metaSchema = metadata?.schema && metadata.schema !== '*' ? metadata.schema : undefined;
|
|
@@ -865,11 +1082,11 @@ class QueryBuilder {
|
|
|
865
1082
|
fromSubQuery(target, aliasName) {
|
|
866
1083
|
const subQuery = target.getKnexQuery();
|
|
867
1084
|
const { entityName } = target.mainAlias;
|
|
868
|
-
aliasName
|
|
1085
|
+
aliasName ??= this.getNextAlias(entityName);
|
|
869
1086
|
this.createMainAlias(entityName, aliasName, subQuery);
|
|
870
1087
|
}
|
|
871
1088
|
fromEntityName(entityName, aliasName) {
|
|
872
|
-
aliasName
|
|
1089
|
+
aliasName ??= this._mainAlias?.aliasName ?? this.getNextAlias(entityName);
|
|
873
1090
|
this.createMainAlias(entityName, aliasName);
|
|
874
1091
|
}
|
|
875
1092
|
createQueryBuilderHelper() {
|
|
@@ -897,6 +1114,9 @@ class QueryBuilder {
|
|
|
897
1114
|
if (this._data) {
|
|
898
1115
|
object.data = this._data;
|
|
899
1116
|
}
|
|
1117
|
+
if (this._schema) {
|
|
1118
|
+
object.schema = this._schema;
|
|
1119
|
+
}
|
|
900
1120
|
if (!core_1.Utils.isEmpty(this._cond)) {
|
|
901
1121
|
object.where = this._cond;
|
|
902
1122
|
}
|