@mikro-orm/knex 6.0.0-dev.1 → 6.0.0-dev.11
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/{dist/AbstractSqlConnection.d.ts → AbstractSqlConnection.d.ts} +0 -0
- package/{dist/AbstractSqlConnection.js → AbstractSqlConnection.js} +5 -0
- package/AbstractSqlDriver.d.ts +66 -0
- package/{dist/AbstractSqlDriver.js → AbstractSqlDriver.js} +226 -70
- package/{dist/AbstractSqlPlatform.d.ts → AbstractSqlPlatform.d.ts} +7 -7
- package/{dist/AbstractSqlPlatform.js → AbstractSqlPlatform.js} +12 -14
- package/{dist/MonkeyPatchable.d.ts → MonkeyPatchable.d.ts} +0 -0
- package/{dist/MonkeyPatchable.js → MonkeyPatchable.js} +0 -0
- package/{dist/README.md → README.md} +2 -2
- package/{dist/SqlEntityManager.d.ts → SqlEntityManager.d.ts} +5 -5
- package/{dist/SqlEntityManager.js → SqlEntityManager.js} +0 -1
- package/{dist/SqlEntityRepository.d.ts → SqlEntityRepository.d.ts} +3 -3
- package/{dist/SqlEntityRepository.js → SqlEntityRepository.js} +1 -1
- package/{dist/index.d.ts → index.d.ts} +1 -0
- package/{dist/index.js → index.js} +6 -1
- package/index.mjs +192 -0
- package/package.json +18 -47
- package/{dist/query → query}/ArrayCriteriaNode.d.ts +0 -0
- package/{dist/query → query}/ArrayCriteriaNode.js +0 -0
- package/{dist/query → query}/CriteriaNode.d.ts +0 -0
- package/{dist/query → query}/CriteriaNode.js +7 -4
- package/{dist/query → query}/CriteriaNodeFactory.d.ts +0 -0
- package/{dist/query → query}/CriteriaNodeFactory.js +0 -0
- package/{dist/query → query}/ObjectCriteriaNode.d.ts +0 -0
- package/{dist/query → query}/ObjectCriteriaNode.js +14 -1
- package/{dist/query → query}/QueryBuilder.d.ts +61 -24
- package/{dist/query → query}/QueryBuilder.js +308 -84
- package/{dist/query → query}/QueryBuilderHelper.d.ts +19 -11
- package/{dist/query → query}/QueryBuilderHelper.js +206 -108
- package/{dist/query → query}/ScalarCriteriaNode.d.ts +0 -0
- package/{dist/query → query}/ScalarCriteriaNode.js +0 -0
- package/{dist/query → query}/enums.d.ts +0 -0
- package/{dist/query → query}/enums.js +0 -0
- package/{dist/query → query}/index.d.ts +0 -0
- package/{dist/query → query}/index.js +5 -1
- package/{dist/schema → schema}/DatabaseSchema.d.ts +1 -1
- package/{dist/schema → schema}/DatabaseSchema.js +8 -16
- package/{dist/schema → schema}/DatabaseTable.d.ts +8 -8
- package/{dist/schema → schema}/DatabaseTable.js +2 -1
- package/{dist/schema → schema}/SchemaComparator.d.ts +7 -5
- package/{dist/schema → schema}/SchemaComparator.js +58 -10
- package/{dist/schema → schema}/SchemaHelper.d.ts +15 -10
- package/{dist/schema → schema}/SchemaHelper.js +46 -8
- package/{dist/schema/SchemaGenerator.d.ts → schema/SqlSchemaGenerator.d.ts} +12 -12
- package/{dist/schema/SchemaGenerator.js → schema/SqlSchemaGenerator.js} +85 -34
- package/{dist/schema → schema}/index.d.ts +1 -1
- package/{dist/schema → schema}/index.js +6 -2
- package/{dist/typings.d.ts → typings.d.ts} +16 -12
- package/{dist/typings.js → typings.js} +0 -0
- package/CHANGELOG.md +0 -661
- package/dist/AbstractSqlDriver.d.ts +0 -55
- package/dist/LICENSE +0 -21
- package/dist/index.mjs +0 -26
- package/dist/package.json +0 -99
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.QueryBuilder = void 0;
|
|
4
|
+
const util_1 = require("util");
|
|
4
5
|
const core_1 = require("@mikro-orm/core");
|
|
5
6
|
const enums_1 = require("./enums");
|
|
6
7
|
const QueryBuilderHelper_1 = require("./QueryBuilderHelper");
|
|
@@ -25,11 +26,21 @@ const CriteriaNodeFactory_1 = require("./CriteriaNodeFactory");
|
|
|
25
26
|
* ```
|
|
26
27
|
*/
|
|
27
28
|
class QueryBuilder {
|
|
29
|
+
get mainAlias() {
|
|
30
|
+
this.ensureFromClause();
|
|
31
|
+
return this._mainAlias;
|
|
32
|
+
}
|
|
33
|
+
get alias() {
|
|
34
|
+
return this.mainAlias.aliasName;
|
|
35
|
+
}
|
|
36
|
+
get helper() {
|
|
37
|
+
this.ensureFromClause();
|
|
38
|
+
return this._helper;
|
|
39
|
+
}
|
|
28
40
|
/**
|
|
29
41
|
* @internal
|
|
30
42
|
*/
|
|
31
43
|
constructor(entityName, metadata, driver, context, alias, connectionType, em) {
|
|
32
|
-
this.entityName = entityName;
|
|
33
44
|
this.metadata = metadata;
|
|
34
45
|
this.driver = driver;
|
|
35
46
|
this.context = context;
|
|
@@ -43,23 +54,25 @@ class QueryBuilder {
|
|
|
43
54
|
this.flags = new Set([core_1.QueryFlag.CONVERT_CUSTOM_TYPES]);
|
|
44
55
|
this.finalized = false;
|
|
45
56
|
this._joins = {};
|
|
46
|
-
this.
|
|
57
|
+
this._explicitAlias = false;
|
|
47
58
|
this._cond = {};
|
|
48
59
|
this._orderBy = [];
|
|
49
60
|
this._groupBy = [];
|
|
50
61
|
this._having = {};
|
|
51
62
|
this._joinedProps = new Map();
|
|
52
63
|
this.subQueries = {};
|
|
64
|
+
this._aliases = {};
|
|
53
65
|
this.platform = this.driver.getPlatform();
|
|
54
66
|
this.knex = this.driver.getConnection(this.connectionType).getKnex();
|
|
55
67
|
if (alias) {
|
|
56
68
|
this.aliasCounter++;
|
|
69
|
+
this._explicitAlias = true;
|
|
57
70
|
}
|
|
58
|
-
|
|
59
|
-
this.
|
|
60
|
-
this.helper = new QueryBuilderHelper_1.QueryBuilderHelper(this.entityName, this.alias, this._aliasMap, this.subQueries, this.metadata, this.knex, this.platform);
|
|
71
|
+
// @ts-expect-error union type does not match the overloaded method signature
|
|
72
|
+
this.from(entityName, alias);
|
|
61
73
|
}
|
|
62
74
|
select(fields, distinct = false) {
|
|
75
|
+
this.ensureNotFinalized();
|
|
63
76
|
this._fields = core_1.Utils.asArray(fields);
|
|
64
77
|
if (distinct) {
|
|
65
78
|
this.flags.add(core_1.QueryFlag.DISTINCT);
|
|
@@ -67,11 +80,22 @@ class QueryBuilder {
|
|
|
67
80
|
return this.init(enums_1.QueryType.SELECT);
|
|
68
81
|
}
|
|
69
82
|
addSelect(fields) {
|
|
83
|
+
this.ensureNotFinalized();
|
|
70
84
|
if (this.type && this.type !== enums_1.QueryType.SELECT) {
|
|
71
85
|
return this;
|
|
72
86
|
}
|
|
73
87
|
return this.select([...core_1.Utils.asArray(this._fields), ...core_1.Utils.asArray(fields)]);
|
|
74
88
|
}
|
|
89
|
+
distinct() {
|
|
90
|
+
this.ensureNotFinalized();
|
|
91
|
+
return this.setFlag(core_1.QueryFlag.DISTINCT);
|
|
92
|
+
}
|
|
93
|
+
/** postgres only */
|
|
94
|
+
distinctOn(fields) {
|
|
95
|
+
this.ensureNotFinalized();
|
|
96
|
+
this._distinctOn = core_1.Utils.asArray(fields);
|
|
97
|
+
return this;
|
|
98
|
+
}
|
|
75
99
|
insert(data) {
|
|
76
100
|
return this.init(enums_1.QueryType.INSERT, data);
|
|
77
101
|
}
|
|
@@ -85,7 +109,15 @@ class QueryBuilder {
|
|
|
85
109
|
return this.init(enums_1.QueryType.TRUNCATE);
|
|
86
110
|
}
|
|
87
111
|
count(field, distinct = false) {
|
|
88
|
-
|
|
112
|
+
if (field) {
|
|
113
|
+
this._fields = core_1.Utils.asArray(field);
|
|
114
|
+
}
|
|
115
|
+
else if (this.hasToManyJoins()) {
|
|
116
|
+
this._fields = this.mainAlias.metadata.primaryKeys;
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
this._fields = [this.raw('*')];
|
|
120
|
+
}
|
|
89
121
|
if (distinct) {
|
|
90
122
|
this.flags.add(core_1.QueryFlag.DISTINCT);
|
|
91
123
|
}
|
|
@@ -99,6 +131,9 @@ class QueryBuilder {
|
|
|
99
131
|
return this.join(field, alias, cond, 'leftJoin');
|
|
100
132
|
}
|
|
101
133
|
joinAndSelect(field, alias, cond = {}, type = 'innerJoin', path) {
|
|
134
|
+
if (!this.type) {
|
|
135
|
+
this.select('*');
|
|
136
|
+
}
|
|
102
137
|
const prop = this.joinReference(field, alias, cond, type, path);
|
|
103
138
|
this.addSelect(this.getFieldsForJoinedLoad(prop, alias));
|
|
104
139
|
const [fromAlias] = this.helper.splitField(field);
|
|
@@ -124,24 +159,34 @@ class QueryBuilder {
|
|
|
124
159
|
return fields;
|
|
125
160
|
}
|
|
126
161
|
withSubQuery(subQuery, alias) {
|
|
162
|
+
this.ensureNotFinalized();
|
|
127
163
|
this.subQueries[alias] = subQuery.toString();
|
|
128
164
|
return this;
|
|
129
165
|
}
|
|
130
166
|
where(cond, params, operator) {
|
|
167
|
+
this.ensureNotFinalized();
|
|
131
168
|
if (core_1.Utils.isString(cond)) {
|
|
132
169
|
cond = { [`(${cond})`]: core_1.Utils.asArray(params) };
|
|
133
170
|
operator = operator || '$and';
|
|
134
171
|
}
|
|
135
172
|
else {
|
|
136
|
-
cond = core_1.QueryHelper.processWhere(
|
|
173
|
+
cond = core_1.QueryHelper.processWhere({
|
|
174
|
+
where: cond,
|
|
175
|
+
entityName: this.mainAlias.entityName,
|
|
176
|
+
metadata: this.metadata,
|
|
177
|
+
platform: this.platform,
|
|
178
|
+
aliasMap: this.getAliasMap(),
|
|
179
|
+
aliased: !this.type || [enums_1.QueryType.SELECT, enums_1.QueryType.COUNT].includes(this.type),
|
|
180
|
+
convertCustomTypes: this.flags.has(core_1.QueryFlag.CONVERT_CUSTOM_TYPES),
|
|
181
|
+
});
|
|
137
182
|
}
|
|
138
183
|
const op = operator || params;
|
|
139
184
|
const topLevel = !op || !core_1.Utils.hasObjectKeys(this._cond);
|
|
140
|
-
const criteriaNode = CriteriaNodeFactory_1.CriteriaNodeFactory.createNode(this.metadata, this.entityName, cond);
|
|
185
|
+
const criteriaNode = CriteriaNodeFactory_1.CriteriaNodeFactory.createNode(this.metadata, this.mainAlias.entityName, cond);
|
|
141
186
|
if ([enums_1.QueryType.UPDATE, enums_1.QueryType.DELETE].includes(this.type) && criteriaNode.willAutoJoin(this)) {
|
|
142
187
|
// use sub-query to support joining
|
|
143
188
|
this.setFlag(this.type === enums_1.QueryType.UPDATE ? core_1.QueryFlag.UPDATE_SUB_QUERY : core_1.QueryFlag.DELETE_SUB_QUERY);
|
|
144
|
-
this.select(this.metadata.
|
|
189
|
+
this.select(this.mainAlias.metadata.primaryKeys, true);
|
|
145
190
|
}
|
|
146
191
|
if (topLevel) {
|
|
147
192
|
this._cond = criteriaNode.process(this);
|
|
@@ -166,27 +211,39 @@ class QueryBuilder {
|
|
|
166
211
|
return this.where(cond, params, '$or');
|
|
167
212
|
}
|
|
168
213
|
orderBy(orderBy) {
|
|
214
|
+
this.ensureNotFinalized();
|
|
169
215
|
this._orderBy = [];
|
|
170
216
|
core_1.Utils.asArray(orderBy).forEach(o => {
|
|
171
|
-
const processed = core_1.QueryHelper.processWhere(
|
|
172
|
-
|
|
217
|
+
const processed = core_1.QueryHelper.processWhere({
|
|
218
|
+
where: o,
|
|
219
|
+
entityName: this.mainAlias.entityName,
|
|
220
|
+
metadata: this.metadata,
|
|
221
|
+
platform: this.platform,
|
|
222
|
+
aliasMap: this.getAliasMap(),
|
|
223
|
+
aliased: !this.type || [enums_1.QueryType.SELECT, enums_1.QueryType.COUNT].includes(this.type),
|
|
224
|
+
convertCustomTypes: false,
|
|
225
|
+
});
|
|
226
|
+
this._orderBy.push(CriteriaNodeFactory_1.CriteriaNodeFactory.createNode(this.metadata, this.mainAlias.entityName, processed).process(this));
|
|
173
227
|
});
|
|
174
228
|
return this;
|
|
175
229
|
}
|
|
176
230
|
groupBy(fields) {
|
|
231
|
+
this.ensureNotFinalized();
|
|
177
232
|
this._groupBy = core_1.Utils.asArray(fields);
|
|
178
233
|
return this;
|
|
179
234
|
}
|
|
180
235
|
having(cond = {}, params) {
|
|
236
|
+
this.ensureNotFinalized();
|
|
181
237
|
if (core_1.Utils.isString(cond)) {
|
|
182
238
|
cond = { [`(${cond})`]: core_1.Utils.asArray(params) };
|
|
183
239
|
}
|
|
184
|
-
this._having = CriteriaNodeFactory_1.CriteriaNodeFactory.createNode(this.metadata, this.entityName, cond).process(this);
|
|
240
|
+
this._having = CriteriaNodeFactory_1.CriteriaNodeFactory.createNode(this.metadata, this.mainAlias.entityName, cond).process(this);
|
|
185
241
|
return this;
|
|
186
242
|
}
|
|
187
243
|
onConflict(fields = []) {
|
|
244
|
+
this.ensureNotFinalized();
|
|
188
245
|
this._onConflict = this._onConflict || [];
|
|
189
|
-
this._onConflict.push({ fields: core_1.Utils.asArray(fields) });
|
|
246
|
+
this._onConflict.push({ fields: core_1.Utils.asArray(fields).map(f => f.toString()) });
|
|
190
247
|
return this;
|
|
191
248
|
}
|
|
192
249
|
ignore() {
|
|
@@ -200,14 +257,19 @@ class QueryBuilder {
|
|
|
200
257
|
if (!this._onConflict) {
|
|
201
258
|
throw new Error('You need to call `qb.onConflict()` first to use `qb.merge()`');
|
|
202
259
|
}
|
|
260
|
+
if (Array.isArray(data) && data.length === 0) {
|
|
261
|
+
return this.ignore();
|
|
262
|
+
}
|
|
203
263
|
this._onConflict[this._onConflict.length - 1].merge = data;
|
|
204
264
|
return this;
|
|
205
265
|
}
|
|
206
266
|
/**
|
|
207
267
|
* @internal
|
|
208
268
|
*/
|
|
209
|
-
populate(populate) {
|
|
269
|
+
populate(populate, populateWhere) {
|
|
270
|
+
this.ensureNotFinalized();
|
|
210
271
|
this._populate = populate;
|
|
272
|
+
this._populateWhere = populateWhere;
|
|
211
273
|
return this;
|
|
212
274
|
}
|
|
213
275
|
/**
|
|
@@ -222,6 +284,7 @@ class QueryBuilder {
|
|
|
222
284
|
return raw;
|
|
223
285
|
}
|
|
224
286
|
limit(limit, offset = 0) {
|
|
287
|
+
this.ensureNotFinalized();
|
|
225
288
|
this._limit = limit;
|
|
226
289
|
if (offset) {
|
|
227
290
|
this.offset(offset);
|
|
@@ -229,14 +292,17 @@ class QueryBuilder {
|
|
|
229
292
|
return this;
|
|
230
293
|
}
|
|
231
294
|
offset(offset) {
|
|
295
|
+
this.ensureNotFinalized();
|
|
232
296
|
this._offset = offset;
|
|
233
297
|
return this;
|
|
234
298
|
}
|
|
235
299
|
withSchema(schema) {
|
|
300
|
+
this.ensureNotFinalized();
|
|
236
301
|
this._schema = schema;
|
|
237
302
|
return this;
|
|
238
303
|
}
|
|
239
304
|
setLockMode(mode, tables) {
|
|
305
|
+
this.ensureNotFinalized();
|
|
240
306
|
if (mode != null && mode !== core_1.LockMode.OPTIMISTIC && !this.context) {
|
|
241
307
|
throw core_1.ValidationError.transactionRequired();
|
|
242
308
|
}
|
|
@@ -245,18 +311,22 @@ class QueryBuilder {
|
|
|
245
311
|
return this;
|
|
246
312
|
}
|
|
247
313
|
setFlushMode(flushMode) {
|
|
314
|
+
this.ensureNotFinalized();
|
|
248
315
|
this.flushMode = flushMode;
|
|
249
316
|
return this;
|
|
250
317
|
}
|
|
251
318
|
setFlag(flag) {
|
|
319
|
+
this.ensureNotFinalized();
|
|
252
320
|
this.flags.add(flag);
|
|
253
321
|
return this;
|
|
254
322
|
}
|
|
255
323
|
unsetFlag(flag) {
|
|
324
|
+
this.ensureNotFinalized();
|
|
256
325
|
this.flags.delete(flag);
|
|
257
326
|
return this;
|
|
258
327
|
}
|
|
259
328
|
cache(config = true) {
|
|
329
|
+
this.ensureNotFinalized();
|
|
260
330
|
this._cache = config;
|
|
261
331
|
return this;
|
|
262
332
|
}
|
|
@@ -264,31 +334,46 @@ class QueryBuilder {
|
|
|
264
334
|
* Adds index hint to the FROM clause.
|
|
265
335
|
*/
|
|
266
336
|
indexHint(sql) {
|
|
337
|
+
this.ensureNotFinalized();
|
|
267
338
|
this._indexHint = sql;
|
|
268
339
|
return this;
|
|
269
340
|
}
|
|
341
|
+
from(target, aliasName) {
|
|
342
|
+
this.ensureNotFinalized();
|
|
343
|
+
if (target instanceof QueryBuilder) {
|
|
344
|
+
this.fromSubQuery(target, aliasName);
|
|
345
|
+
}
|
|
346
|
+
else {
|
|
347
|
+
const entityName = core_1.Utils.className(target);
|
|
348
|
+
if (aliasName && this._mainAlias && entityName !== this._mainAlias.aliasName) {
|
|
349
|
+
throw new Error(`Cannot override the alias to '${aliasName}' since a query already contains references to '${this._mainAlias.aliasName}'`);
|
|
350
|
+
}
|
|
351
|
+
this.fromEntityName(entityName, aliasName);
|
|
352
|
+
}
|
|
353
|
+
return this;
|
|
354
|
+
}
|
|
270
355
|
getKnexQuery() {
|
|
271
356
|
this.finalize();
|
|
272
357
|
const qb = this.getQueryBase();
|
|
273
|
-
core_1.Utils.runIfNotEmpty(() => this.helper.appendQueryCondition(this.type, this._cond, qb), this._cond && !this._onConflict);
|
|
358
|
+
core_1.Utils.runIfNotEmpty(() => this.helper.appendQueryCondition(this.type ?? enums_1.QueryType.SELECT, this._cond, qb), this._cond && !this._onConflict);
|
|
274
359
|
core_1.Utils.runIfNotEmpty(() => qb.groupBy(this.prepareFields(this._groupBy, 'groupBy')), this._groupBy);
|
|
275
|
-
core_1.Utils.runIfNotEmpty(() => this.helper.appendQueryCondition(this.type, this._having, qb, undefined, 'having'), this._having);
|
|
360
|
+
core_1.Utils.runIfNotEmpty(() => this.helper.appendQueryCondition(this.type ?? enums_1.QueryType.SELECT, this._having, qb, undefined, 'having'), this._having);
|
|
276
361
|
core_1.Utils.runIfNotEmpty(() => {
|
|
277
|
-
const queryOrder = this.helper.getQueryOrder(this.type, this._orderBy, this._populateMap);
|
|
362
|
+
const queryOrder = this.helper.getQueryOrder(this.type ?? enums_1.QueryType.SELECT, this._orderBy, this._populateMap);
|
|
278
363
|
if (queryOrder) {
|
|
279
364
|
return qb.orderByRaw(queryOrder);
|
|
280
365
|
}
|
|
281
366
|
}, this._orderBy);
|
|
282
367
|
core_1.Utils.runIfNotEmpty(() => qb.limit(this._limit), this._limit != null);
|
|
283
368
|
core_1.Utils.runIfNotEmpty(() => qb.offset(this._offset), this._offset);
|
|
284
|
-
core_1.Utils.runIfNotEmpty(() => this.helper.appendOnConflictClause(this.type, this._onConflict, qb), this._onConflict);
|
|
369
|
+
core_1.Utils.runIfNotEmpty(() => this.helper.appendOnConflictClause(this.type ?? enums_1.QueryType.SELECT, this._onConflict, qb), this._onConflict);
|
|
285
370
|
if (this.type === enums_1.QueryType.TRUNCATE && this.platform.usesCascadeStatement()) {
|
|
286
371
|
return this.knex.raw(qb.toSQL().toNative().sql + ' cascade');
|
|
287
372
|
}
|
|
288
373
|
if (this.lockMode) {
|
|
289
374
|
this.helper.getLockSQL(qb, this.lockMode, this.lockTables);
|
|
290
375
|
}
|
|
291
|
-
this.helper.finalize(this.type, qb, this.metadata
|
|
376
|
+
this.helper.finalize(this.type ?? enums_1.QueryType.SELECT, qb, this.mainAlias.metadata);
|
|
292
377
|
return qb;
|
|
293
378
|
}
|
|
294
379
|
/**
|
|
@@ -310,9 +395,12 @@ class QueryBuilder {
|
|
|
310
395
|
const query = this.getKnexQuery().toSQL();
|
|
311
396
|
return this.platform.formatQuery(query.sql, query.bindings);
|
|
312
397
|
}
|
|
398
|
+
/**
|
|
399
|
+
* @internal
|
|
400
|
+
*/
|
|
313
401
|
getAliasForJoinPath(path) {
|
|
314
|
-
if (!path || path === this.entityName) {
|
|
315
|
-
return this.
|
|
402
|
+
if (!path || path === this.mainAlias.entityName) {
|
|
403
|
+
return this.mainAlias.aliasName;
|
|
316
404
|
}
|
|
317
405
|
const join = Object.values(this._joins).find(j => j.path === path);
|
|
318
406
|
if (path.endsWith('[pivot]') && join) {
|
|
@@ -320,25 +408,34 @@ class QueryBuilder {
|
|
|
320
408
|
}
|
|
321
409
|
return join?.inverseAlias || join?.alias;
|
|
322
410
|
}
|
|
411
|
+
/**
|
|
412
|
+
* @internal
|
|
413
|
+
*/
|
|
323
414
|
getNextAlias(entityName = 'e') {
|
|
324
415
|
return this.driver.config.getNamingStrategy().aliasName(entityName, this.aliasCounter++);
|
|
325
416
|
}
|
|
417
|
+
/**
|
|
418
|
+
* @internal
|
|
419
|
+
*/
|
|
420
|
+
getAliasMap() {
|
|
421
|
+
return Object.fromEntries(Object.entries(this._aliases).map(([key, value]) => [key, value.entityName]));
|
|
422
|
+
}
|
|
326
423
|
/**
|
|
327
424
|
* Executes this QB and returns the raw results, mapped to the property names (unless disabled via last parameter).
|
|
328
425
|
* Use `method` to specify what kind of result you want to get (array/single/meta).
|
|
329
426
|
*/
|
|
330
427
|
async execute(method = 'all', mapResults = true) {
|
|
331
|
-
if (!this.connectionType && method !== 'run' && [enums_1.QueryType.INSERT, enums_1.QueryType.UPDATE, enums_1.QueryType.DELETE, enums_1.QueryType.TRUNCATE].includes(this.type)) {
|
|
428
|
+
if (!this.connectionType && method !== 'run' && [enums_1.QueryType.INSERT, enums_1.QueryType.UPDATE, enums_1.QueryType.DELETE, enums_1.QueryType.TRUNCATE].includes(this.type ?? enums_1.QueryType.SELECT)) {
|
|
332
429
|
this.connectionType = 'write';
|
|
333
430
|
}
|
|
334
431
|
const query = this.getKnexQuery().toSQL();
|
|
335
|
-
const cached = await this.em?.tryCache(this.entityName, this._cache, ['qb.execute', query.sql, query.bindings, method]);
|
|
432
|
+
const cached = await this.em?.tryCache(this.mainAlias.entityName, this._cache, ['qb.execute', query.sql, query.bindings, method]);
|
|
336
433
|
if (cached?.data) {
|
|
337
434
|
return cached.data;
|
|
338
435
|
}
|
|
339
436
|
const type = this.connectionType || (method === 'run' ? 'write' : 'read');
|
|
340
437
|
const res = await this.driver.getConnection(type).execute(query.sql, query.bindings, method, this.context);
|
|
341
|
-
const meta = this.metadata
|
|
438
|
+
const meta = this.mainAlias.metadata;
|
|
342
439
|
if (!mapResults || !meta) {
|
|
343
440
|
await this.em?.storeCache(this._cache, cached, res);
|
|
344
441
|
return res;
|
|
@@ -363,12 +460,12 @@ class QueryBuilder {
|
|
|
363
460
|
* Executes the query, returning array of results
|
|
364
461
|
*/
|
|
365
462
|
async getResultList() {
|
|
366
|
-
await this.em.tryFlush(this.entityName, { flushMode: this.flushMode });
|
|
463
|
+
await this.em.tryFlush(this.mainAlias.entityName, { flushMode: this.flushMode });
|
|
367
464
|
let res = await this.execute('all', true);
|
|
368
465
|
if (this._joinedProps.size > 0) {
|
|
369
|
-
res = this.driver.mergeJoinedResult(res, this.metadata
|
|
466
|
+
res = this.driver.mergeJoinedResult(res, this.mainAlias.metadata);
|
|
370
467
|
}
|
|
371
|
-
return res.map(r => this.em.map(this.entityName, r, { schema: this._schema }));
|
|
468
|
+
return res.map(r => this.em.map(this.mainAlias.entityName, r, { schema: this._schema }));
|
|
372
469
|
}
|
|
373
470
|
/**
|
|
374
471
|
* Executes the query, returning the first result or null
|
|
@@ -380,35 +477,32 @@ class QueryBuilder {
|
|
|
380
477
|
/**
|
|
381
478
|
* Executes count query (without offset and limit), returning total count of results
|
|
382
479
|
*/
|
|
383
|
-
async getCount(field, distinct
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
480
|
+
async getCount(field, distinct) {
|
|
481
|
+
let res;
|
|
482
|
+
if (this.type === enums_1.QueryType.COUNT) {
|
|
483
|
+
res = await this.execute('get', false);
|
|
484
|
+
}
|
|
485
|
+
else {
|
|
486
|
+
const qb = this.clone();
|
|
487
|
+
qb.count(field, distinct ?? qb.hasToManyJoins()).limit(undefined).offset(undefined).orderBy([]);
|
|
488
|
+
res = await qb.execute('get', false);
|
|
489
|
+
}
|
|
387
490
|
return res ? +res.count : 0;
|
|
388
491
|
}
|
|
389
492
|
/**
|
|
390
493
|
* Provides promise-like interface so we can await the QB instance.
|
|
391
494
|
*/
|
|
392
495
|
then(onfulfilled, onrejected) {
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
case enums_1.QueryType.TRUNCATE:
|
|
403
|
-
return this.execute('run');
|
|
404
|
-
case enums_1.QueryType.SELECT:
|
|
405
|
-
return this.getResultList();
|
|
406
|
-
case enums_1.QueryType.COUNT:
|
|
407
|
-
return this.getCount();
|
|
408
|
-
}
|
|
409
|
-
})();
|
|
496
|
+
switch (this.type ?? enums_1.QueryType.SELECT) {
|
|
497
|
+
case enums_1.QueryType.INSERT:
|
|
498
|
+
case enums_1.QueryType.UPDATE:
|
|
499
|
+
case enums_1.QueryType.DELETE:
|
|
500
|
+
case enums_1.QueryType.TRUNCATE:
|
|
501
|
+
return this.execute('run').then(onfulfilled, onrejected);
|
|
502
|
+
case enums_1.QueryType.COUNT:
|
|
503
|
+
return this.getCount().then(onfulfilled, onrejected);
|
|
504
|
+
case enums_1.QueryType.SELECT: return this.getResultList().then(onfulfilled, onrejected);
|
|
410
505
|
}
|
|
411
|
-
return this.innerPromise;
|
|
412
506
|
}
|
|
413
507
|
/**
|
|
414
508
|
* Returns knex instance with sub-query aliased with given alias.
|
|
@@ -425,11 +519,11 @@ class QueryBuilder {
|
|
|
425
519
|
return qb.as(alias);
|
|
426
520
|
}
|
|
427
521
|
clone() {
|
|
428
|
-
const qb = new QueryBuilder(this.entityName, this.metadata, this.driver, this.context, this.
|
|
522
|
+
const qb = new QueryBuilder(this.mainAlias.entityName, this.metadata, this.driver, this.context, this.mainAlias.aliasName, this.connectionType, this.em);
|
|
429
523
|
Object.assign(qb, this);
|
|
430
524
|
// clone array/object properties
|
|
431
525
|
const properties = [
|
|
432
|
-
'flags', '_populate', '
|
|
526
|
+
'flags', '_populate', '_populateWhere', '_populateMap', '_joins', '_joinedProps', '_cond', '_data', '_orderBy',
|
|
433
527
|
'_schema', '_indexHint', '_cache', 'subQueries', 'lockMode', 'lockTables',
|
|
434
528
|
];
|
|
435
529
|
properties.forEach(prop => qb[prop] = core_1.Utils.copy(this[prop]));
|
|
@@ -437,27 +531,45 @@ class QueryBuilder {
|
|
|
437
531
|
if (this._fields) {
|
|
438
532
|
qb._fields = [...this._fields];
|
|
439
533
|
}
|
|
534
|
+
qb._aliases = { ...this._aliases };
|
|
440
535
|
qb.finalized = false;
|
|
441
536
|
return qb;
|
|
442
537
|
}
|
|
443
538
|
getKnex() {
|
|
444
|
-
const
|
|
445
|
-
const
|
|
539
|
+
const qb = this.knex.queryBuilder();
|
|
540
|
+
const { subQuery, aliasName, entityName } = this.mainAlias;
|
|
541
|
+
const ref = subQuery ? subQuery : this.knex.ref(this.helper.getTableName(entityName));
|
|
542
|
+
if (this.finalized && (this._explicitAlias || this.helper.isTableNameAliasRequired(this.type))) {
|
|
543
|
+
ref.as(aliasName);
|
|
544
|
+
}
|
|
545
|
+
const schema = this.getSchema(this.mainAlias);
|
|
546
|
+
if (schema) {
|
|
547
|
+
ref.withSchema(schema);
|
|
548
|
+
}
|
|
549
|
+
qb.from(ref);
|
|
446
550
|
if (this.context) {
|
|
447
551
|
qb.transacting(this.context);
|
|
448
552
|
}
|
|
449
553
|
return qb;
|
|
450
554
|
}
|
|
451
555
|
joinReference(field, alias, cond, type, path) {
|
|
556
|
+
this.ensureNotFinalized();
|
|
452
557
|
const [fromAlias, fromField] = this.helper.splitField(field);
|
|
453
|
-
const entityName = this.
|
|
558
|
+
const entityName = this._aliases[fromAlias]?.entityName;
|
|
454
559
|
const meta = this.metadata.get(entityName);
|
|
455
560
|
const prop = meta.properties[fromField];
|
|
456
561
|
if (!prop) {
|
|
457
562
|
throw new Error(`Trying to join ${field}, but ${fromField} is not a defined relation on ${meta.className}`);
|
|
458
563
|
}
|
|
459
|
-
this.
|
|
460
|
-
cond = core_1.QueryHelper.processWhere(
|
|
564
|
+
this.createAlias(prop.type, alias);
|
|
565
|
+
cond = core_1.QueryHelper.processWhere({
|
|
566
|
+
where: cond,
|
|
567
|
+
entityName: this.mainAlias.entityName,
|
|
568
|
+
metadata: this.metadata,
|
|
569
|
+
platform: this.platform,
|
|
570
|
+
aliasMap: this.getAliasMap(),
|
|
571
|
+
aliased: !this.type || [enums_1.QueryType.SELECT, enums_1.QueryType.COUNT].includes(this.type),
|
|
572
|
+
});
|
|
461
573
|
let aliasedName = `${fromAlias}.${prop.name}#${alias}`;
|
|
462
574
|
path ?? (path = `${(Object.values(this._joins).find(j => j.alias === fromAlias)?.path ?? entityName)}.${prop.name}`);
|
|
463
575
|
if (prop.reference === core_1.ReferenceType.ONE_TO_MANY) {
|
|
@@ -467,12 +579,12 @@ class QueryBuilder {
|
|
|
467
579
|
let pivotAlias = alias;
|
|
468
580
|
if (type !== 'pivotJoin') {
|
|
469
581
|
const oldPivotAlias = this.getAliasForJoinPath(path + '[pivot]');
|
|
470
|
-
pivotAlias = oldPivotAlias ?? this.getNextAlias(prop.
|
|
582
|
+
pivotAlias = oldPivotAlias ?? this.getNextAlias(prop.pivotEntity);
|
|
471
583
|
aliasedName = `${fromAlias}.${prop.name}#${pivotAlias}`;
|
|
472
584
|
}
|
|
473
585
|
const joins = this.helper.joinManyToManyReference(prop, fromAlias, alias, pivotAlias, type, cond, path);
|
|
474
586
|
Object.assign(this._joins, joins);
|
|
475
|
-
this.
|
|
587
|
+
this.createAlias(prop.pivotEntity, pivotAlias);
|
|
476
588
|
}
|
|
477
589
|
else if (prop.reference === core_1.ReferenceType.ONE_TO_ONE) {
|
|
478
590
|
this._joins[aliasedName] = this.helper.joinOneToReference(prop, fromAlias, alias, type, cond);
|
|
@@ -493,24 +605,50 @@ class QueryBuilder {
|
|
|
493
605
|
}
|
|
494
606
|
const join = Object.keys(this._joins).find(k => field === k.substring(0, k.indexOf('#')));
|
|
495
607
|
if (join && type === 'where') {
|
|
496
|
-
return ret.push(...this.helper.mapJoinColumns(this.type, this._joins[join]));
|
|
608
|
+
return ret.push(...this.helper.mapJoinColumns(this.type ?? enums_1.QueryType.SELECT, this._joins[join]));
|
|
497
609
|
}
|
|
498
610
|
const [a, f] = this.helper.splitField(field);
|
|
499
611
|
const prop = this.helper.getProperty(f, a);
|
|
612
|
+
/* istanbul ignore next */
|
|
500
613
|
if (prop && [core_1.ReferenceType.ONE_TO_MANY, core_1.ReferenceType.MANY_TO_MANY].includes(prop.reference)) {
|
|
501
614
|
return;
|
|
502
615
|
}
|
|
616
|
+
if (prop?.embedded) {
|
|
617
|
+
const fieldName = this.helper.mapper(prop.fieldNames[0], this.type);
|
|
618
|
+
ret.push(fieldName);
|
|
619
|
+
return;
|
|
620
|
+
}
|
|
621
|
+
if (prop?.reference === core_1.ReferenceType.EMBEDDED) {
|
|
622
|
+
if (prop.object) {
|
|
623
|
+
ret.push(this.helper.mapper(prop.fieldNames[0], this.type));
|
|
624
|
+
}
|
|
625
|
+
else {
|
|
626
|
+
const nest = (prop) => {
|
|
627
|
+
for (const childProp of Object.values(prop.embeddedProps)) {
|
|
628
|
+
if (childProp.fieldNames) {
|
|
629
|
+
ret.push(this.helper.mapper(childProp.fieldNames[0], this.type));
|
|
630
|
+
}
|
|
631
|
+
else {
|
|
632
|
+
nest(childProp);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
};
|
|
636
|
+
nest(prop);
|
|
637
|
+
}
|
|
638
|
+
return;
|
|
639
|
+
}
|
|
503
640
|
ret.push(this.helper.mapper(field, this.type));
|
|
504
641
|
});
|
|
505
|
-
const meta = this.metadata
|
|
642
|
+
const meta = this.mainAlias.metadata;
|
|
506
643
|
/* istanbul ignore next */
|
|
507
644
|
const requiresSQLConversion = meta?.props.filter(p => p.customType?.convertToJSValueSQL) ?? [];
|
|
508
|
-
if (this.flags.has(core_1.QueryFlag.CONVERT_CUSTOM_TYPES) && (fields.includes('*') || fields.includes(`${this.
|
|
645
|
+
if (this.flags.has(core_1.QueryFlag.CONVERT_CUSTOM_TYPES) && (fields.includes('*') || fields.includes(`${this.mainAlias.aliasName}.*`)) && requiresSQLConversion.length > 0) {
|
|
509
646
|
requiresSQLConversion.forEach(p => ret.push(this.helper.mapper(p.name, this.type)));
|
|
510
647
|
}
|
|
511
648
|
Object.keys(this._populateMap).forEach(f => {
|
|
512
649
|
if (!fields.includes(f.replace(/#\w+$/, '')) && type === 'where') {
|
|
513
|
-
|
|
650
|
+
const cols = this.helper.mapJoinColumns(this.type ?? enums_1.QueryType.SELECT, this._joins[f]);
|
|
651
|
+
ret.push(...cols);
|
|
514
652
|
}
|
|
515
653
|
if (this._joins[f].prop.reference !== core_1.ReferenceType.ONE_TO_ONE && this._joins[f].inverseJoinColumns) {
|
|
516
654
|
this._joins[f].inverseJoinColumns.forEach(inverseJoinColumn => {
|
|
@@ -521,8 +659,8 @@ class QueryBuilder {
|
|
|
521
659
|
return ret;
|
|
522
660
|
}
|
|
523
661
|
init(type, data, cond) {
|
|
662
|
+
this.ensureNotFinalized();
|
|
524
663
|
this.type = type;
|
|
525
|
-
this._aliasMap[this.alias] = this.entityName;
|
|
526
664
|
if ([enums_1.QueryType.UPDATE, enums_1.QueryType.DELETE].includes(type) && core_1.Utils.hasObjectKeys(this._cond)) {
|
|
527
665
|
throw new Error(`You are trying to call \`qb.where().${type.toLowerCase()}()\`. Calling \`qb.${type.toLowerCase()}()\` before \`qb.where()\` is required.`);
|
|
528
666
|
}
|
|
@@ -530,6 +668,9 @@ class QueryBuilder {
|
|
|
530
668
|
delete this._fields;
|
|
531
669
|
}
|
|
532
670
|
if (data) {
|
|
671
|
+
if (core_1.Utils.isEntity(data)) {
|
|
672
|
+
data = (0, core_1.helper)(data).toJSON();
|
|
673
|
+
}
|
|
533
674
|
this._data = this.helper.processData(data, this.flags.has(core_1.QueryFlag.CONVERT_CUSTOM_TYPES));
|
|
534
675
|
}
|
|
535
676
|
if (cond) {
|
|
@@ -539,22 +680,23 @@ class QueryBuilder {
|
|
|
539
680
|
}
|
|
540
681
|
getQueryBase() {
|
|
541
682
|
const qb = this.getKnex();
|
|
542
|
-
const
|
|
543
|
-
const metaSchema = meta?.schema && meta.schema !== '*' ? meta.schema : undefined;
|
|
544
|
-
const schema = this._schema ?? metaSchema ?? this.em?.config.get('schema');
|
|
683
|
+
const schema = this.getSchema(this.mainAlias);
|
|
545
684
|
if (schema) {
|
|
546
685
|
qb.withSchema(schema);
|
|
547
686
|
}
|
|
548
687
|
if (this._indexHint) {
|
|
549
|
-
const alias = this.helper.isTableNameAliasRequired(this.type) ? ` as ${this.platform.quoteIdentifier(this.
|
|
688
|
+
const alias = this.helper.isTableNameAliasRequired(this.type) ? ` as ${this.platform.quoteIdentifier(this.mainAlias.aliasName)}` : '';
|
|
550
689
|
const schemaQuoted = schema ? this.platform.quoteIdentifier(schema) + '.' : '';
|
|
551
|
-
const tableName = schemaQuoted + this.platform.quoteIdentifier(this.helper.getTableName(this.entityName)) + alias;
|
|
690
|
+
const tableName = schemaQuoted + this.platform.quoteIdentifier(this.helper.getTableName(this.mainAlias.entityName)) + alias;
|
|
552
691
|
qb.from(this.knex.raw(`${tableName} ${this._indexHint}`));
|
|
553
692
|
}
|
|
554
693
|
switch (this.type) {
|
|
555
694
|
case enums_1.QueryType.SELECT:
|
|
556
695
|
qb.select(this.prepareFields(this._fields));
|
|
557
|
-
if (this.
|
|
696
|
+
if (this._distinctOn) {
|
|
697
|
+
qb.distinctOn(this._distinctOn);
|
|
698
|
+
}
|
|
699
|
+
else if (this.flags.has(core_1.QueryFlag.DISTINCT)) {
|
|
558
700
|
qb.distinct();
|
|
559
701
|
}
|
|
560
702
|
this.helper.processJoins(qb, this._joins, schema);
|
|
@@ -588,7 +730,7 @@ class QueryBuilder {
|
|
|
588
730
|
if (!this.type) {
|
|
589
731
|
this.select('*');
|
|
590
732
|
}
|
|
591
|
-
const meta = this.metadata
|
|
733
|
+
const meta = this.mainAlias.metadata;
|
|
592
734
|
if (meta && this.flags.has(core_1.QueryFlag.AUTO_JOIN_ONE_TO_ONE_OWNER)) {
|
|
593
735
|
const relationsToPopulate = this._populate.map(({ field }) => field);
|
|
594
736
|
meta.relations
|
|
@@ -600,7 +742,7 @@ class QueryBuilder {
|
|
|
600
742
|
const [fromAlias, fromField] = this.helper.splitField(field);
|
|
601
743
|
const aliasedField = `${fromAlias}.${fromField}`;
|
|
602
744
|
const join = Object.keys(this._joins).find(k => `${aliasedField}#${this._joins[k].alias}` === k);
|
|
603
|
-
if (this._joins[join] && this.helper.isOneToOneInverse(fromField)) {
|
|
745
|
+
if (join && this._joins[join] && this.helper.isOneToOneInverse(fromField)) {
|
|
604
746
|
return this._populateMap[join] = this._joins[join].alias;
|
|
605
747
|
}
|
|
606
748
|
if (this.metadata.find(field)?.pivotTable) { // pivot table entity
|
|
@@ -608,16 +750,17 @@ class QueryBuilder {
|
|
|
608
750
|
}
|
|
609
751
|
else if (meta && this.helper.isOneToOneInverse(fromField)) {
|
|
610
752
|
const prop = meta.properties[fromField];
|
|
611
|
-
const alias = this.getNextAlias(prop.
|
|
612
|
-
|
|
613
|
-
this.
|
|
753
|
+
const alias = this.getNextAlias(prop.pivotEntity ?? prop.type);
|
|
754
|
+
const aliasedName = `${fromAlias}.${prop.name}#${alias}`;
|
|
755
|
+
this._joins[aliasedName] = this.helper.joinOneToReference(prop, this.mainAlias.aliasName, alias, 'leftJoin');
|
|
756
|
+
this._populateMap[aliasedName] = this._joins[aliasedName].alias;
|
|
614
757
|
}
|
|
615
758
|
});
|
|
616
|
-
if (meta && (this._fields?.includes('*') || this._fields?.includes(`${this.
|
|
759
|
+
if (meta && (this._fields?.includes('*') || this._fields?.includes(`${this.mainAlias.aliasName}.*`))) {
|
|
617
760
|
meta.props
|
|
618
761
|
.filter(prop => prop.formula && (!prop.lazy || this.flags.has(core_1.QueryFlag.INCLUDE_LAZY_FORMULAS)))
|
|
619
762
|
.map(prop => {
|
|
620
|
-
const alias = this.knex.ref(this.
|
|
763
|
+
const alias = this.knex.ref(this.mainAlias.aliasName).toString();
|
|
621
764
|
const aliased = this.knex.ref(prop.fieldNames[0]).toString();
|
|
622
765
|
return `${prop.formula(alias)} as ${aliased}`;
|
|
623
766
|
})
|
|
@@ -627,13 +770,22 @@ class QueryBuilder {
|
|
|
627
770
|
core_1.QueryHelper.processObjectParams(this._data);
|
|
628
771
|
core_1.QueryHelper.processObjectParams(this._cond);
|
|
629
772
|
core_1.QueryHelper.processObjectParams(this._having);
|
|
630
|
-
|
|
631
|
-
if (
|
|
773
|
+
// automatically enable paginate flag when we detect to-many joins
|
|
774
|
+
if (!this.flags.has(core_1.QueryFlag.DISABLE_PAGINATE) && this.hasToManyJoins()) {
|
|
775
|
+
this.flags.add(core_1.QueryFlag.PAGINATE);
|
|
776
|
+
}
|
|
777
|
+
if (meta && this.flags.has(core_1.QueryFlag.PAGINATE) && (this._limit > 0 || this._offset > 0)) {
|
|
632
778
|
this.wrapPaginateSubQuery(meta);
|
|
633
779
|
}
|
|
634
780
|
if (meta && (this.flags.has(core_1.QueryFlag.UPDATE_SUB_QUERY) || this.flags.has(core_1.QueryFlag.DELETE_SUB_QUERY))) {
|
|
635
781
|
this.wrapModifySubQuery(meta);
|
|
636
782
|
}
|
|
783
|
+
this.finalized = true;
|
|
784
|
+
}
|
|
785
|
+
hasToManyJoins() {
|
|
786
|
+
return Object.values(this._joins).some(join => {
|
|
787
|
+
return [core_1.ReferenceType.ONE_TO_MANY, core_1.ReferenceType.MANY_TO_MANY].includes(join.prop.reference);
|
|
788
|
+
});
|
|
637
789
|
}
|
|
638
790
|
wrapPaginateSubQuery(meta) {
|
|
639
791
|
const pks = this.prepareFields(meta.primaryKeys, 'sub-query');
|
|
@@ -645,28 +797,38 @@ class QueryBuilder {
|
|
|
645
797
|
const orderBy = [];
|
|
646
798
|
for (const orderMap of this._orderBy) {
|
|
647
799
|
for (const [field, direction] of Object.entries(orderMap)) {
|
|
800
|
+
const [a, f] = this.helper.splitField(field);
|
|
801
|
+
const prop = this.helper.getProperty(f, a);
|
|
802
|
+
const type = this.platform.castColumn(prop);
|
|
648
803
|
orderBy.push({
|
|
649
|
-
[`min(${this.ref(field)})`]: direction,
|
|
804
|
+
[`min(${this.ref(this.helper.mapper(field, this.type, undefined, null))}${type})`]: direction,
|
|
650
805
|
});
|
|
651
806
|
}
|
|
652
807
|
}
|
|
653
808
|
subQuery.orderBy(orderBy);
|
|
654
809
|
}
|
|
655
810
|
subQuery.finalized = true;
|
|
656
|
-
const knexQuery = subQuery.as(this.
|
|
811
|
+
const knexQuery = subQuery.as(this.mainAlias.aliasName).clearSelect().select(pks);
|
|
657
812
|
// multiple sub-queries are needed to get around mysql limitations with order by + limit + where in + group by (o.O)
|
|
658
813
|
// https://stackoverflow.com/questions/17892762/mysql-this-version-of-mysql-doesnt-yet-support-limit-in-all-any-some-subqu
|
|
659
814
|
const subSubQuery = this.getKnex().select(pks).from(knexQuery);
|
|
660
815
|
this._limit = undefined;
|
|
661
816
|
this._offset = undefined;
|
|
817
|
+
const cond = this._cond;
|
|
662
818
|
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
|
+
}
|
|
663
825
|
}
|
|
664
826
|
wrapModifySubQuery(meta) {
|
|
665
827
|
const subQuery = this.clone();
|
|
666
828
|
subQuery.finalized = true;
|
|
667
829
|
// wrap one more time to get around MySQL limitations
|
|
668
830
|
// https://stackoverflow.com/questions/45494/mysql-error-1093-cant-specify-target-table-for-update-in-from-clause
|
|
669
|
-
const subSubQuery = this.getKnex().select(this.prepareFields(meta.primaryKeys)).from(subQuery.as(this.
|
|
831
|
+
const subSubQuery = this.getKnex().select(this.prepareFields(meta.primaryKeys)).from(subQuery.as(this.mainAlias.aliasName));
|
|
670
832
|
const method = this.flags.has(core_1.QueryFlag.UPDATE_SUB_QUERY) ? 'update' : 'delete';
|
|
671
833
|
this._cond = {}; // otherwise we would trigger validation error
|
|
672
834
|
this[method](this._data).where({
|
|
@@ -675,14 +837,76 @@ class QueryBuilder {
|
|
|
675
837
|
}
|
|
676
838
|
autoJoinPivotTable(field) {
|
|
677
839
|
const pivotMeta = this.metadata.find(field);
|
|
678
|
-
const owner = pivotMeta.
|
|
679
|
-
const inverse = pivotMeta.
|
|
840
|
+
const owner = pivotMeta.relations[0];
|
|
841
|
+
const inverse = pivotMeta.relations[1];
|
|
680
842
|
const prop = this._cond[pivotMeta.name + '.' + owner.name] || this._orderBy[pivotMeta.name + '.' + owner.name] ? inverse : owner;
|
|
681
843
|
const pivotAlias = this.getNextAlias(pivotMeta.name);
|
|
682
|
-
this._joins[field] = this.helper.joinPivotTable(field, prop, this.
|
|
844
|
+
this._joins[field] = this.helper.joinPivotTable(field, prop, this.mainAlias.aliasName, pivotAlias, 'leftJoin');
|
|
683
845
|
core_1.Utils.renameKey(this._cond, `${field}.${owner.name}`, core_1.Utils.getPrimaryKeyHash(owner.fieldNames.map(fieldName => `${pivotAlias}.${fieldName}`)));
|
|
684
846
|
core_1.Utils.renameKey(this._cond, `${field}.${inverse.name}`, core_1.Utils.getPrimaryKeyHash(inverse.fieldNames.map(fieldName => `${pivotAlias}.${fieldName}`)));
|
|
685
847
|
this._populateMap[field] = this._joins[field].alias;
|
|
686
848
|
}
|
|
849
|
+
getSchema(alias) {
|
|
850
|
+
const { metadata } = alias;
|
|
851
|
+
const metaSchema = metadata?.schema && metadata.schema !== '*' ? metadata.schema : undefined;
|
|
852
|
+
return this._schema ?? metaSchema ?? this.em?.config.get('schema');
|
|
853
|
+
}
|
|
854
|
+
createAlias(entityName, aliasName, subQuery) {
|
|
855
|
+
const metadata = this.metadata.find(entityName);
|
|
856
|
+
const alias = { aliasName, entityName, metadata, subQuery };
|
|
857
|
+
this._aliases[aliasName] = alias;
|
|
858
|
+
return alias;
|
|
859
|
+
}
|
|
860
|
+
createMainAlias(entityName, aliasName, subQuery) {
|
|
861
|
+
this._mainAlias = this.createAlias(entityName, aliasName, subQuery);
|
|
862
|
+
this._helper = this.createQueryBuilderHelper();
|
|
863
|
+
return this._mainAlias;
|
|
864
|
+
}
|
|
865
|
+
fromSubQuery(target, aliasName) {
|
|
866
|
+
const subQuery = target.getKnexQuery();
|
|
867
|
+
const { entityName } = target.mainAlias;
|
|
868
|
+
aliasName ?? (aliasName = this.getNextAlias(entityName));
|
|
869
|
+
this.createMainAlias(entityName, aliasName, subQuery);
|
|
870
|
+
}
|
|
871
|
+
fromEntityName(entityName, aliasName) {
|
|
872
|
+
aliasName ?? (aliasName = this._mainAlias?.aliasName ?? this.getNextAlias(entityName));
|
|
873
|
+
this.createMainAlias(entityName, aliasName);
|
|
874
|
+
}
|
|
875
|
+
createQueryBuilderHelper() {
|
|
876
|
+
return new QueryBuilderHelper_1.QueryBuilderHelper(this.mainAlias.entityName, this.mainAlias.aliasName, this._aliases, this.subQueries, this.knex, this.driver);
|
|
877
|
+
}
|
|
878
|
+
ensureFromClause() {
|
|
879
|
+
/* istanbul ignore next */
|
|
880
|
+
if (!this._mainAlias) {
|
|
881
|
+
throw new Error(`Cannot proceed to build a query because the main alias is not set.`);
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
ensureNotFinalized() {
|
|
885
|
+
if (this.finalized) {
|
|
886
|
+
throw new Error('This QueryBuilder instance is already finalized, clone it first if you want to modify it.');
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
/* istanbul ignore next */
|
|
890
|
+
[util_1.inspect.custom](depth) {
|
|
891
|
+
const object = { ...this };
|
|
892
|
+
const hidden = ['metadata', 'driver', 'context', 'platform', 'knex', 'type'];
|
|
893
|
+
Object.keys(object).filter(k => k.startsWith('_')).forEach(k => delete object[k]);
|
|
894
|
+
Object.keys(object).filter(k => object[k] == null).forEach(k => delete object[k]);
|
|
895
|
+
hidden.forEach(k => delete object[k]);
|
|
896
|
+
let prefix = this.type ? this.type.substring(0, 1) + this.type.toLowerCase().substring(1) : '';
|
|
897
|
+
if (this._data) {
|
|
898
|
+
object.data = this._data;
|
|
899
|
+
}
|
|
900
|
+
if (!core_1.Utils.isEmpty(this._cond)) {
|
|
901
|
+
object.where = this._cond;
|
|
902
|
+
}
|
|
903
|
+
if (this._onConflict?.[0]) {
|
|
904
|
+
prefix = 'Upsert';
|
|
905
|
+
object.onConflict = this._onConflict[0];
|
|
906
|
+
}
|
|
907
|
+
const name = this._mainAlias ? `${prefix}QueryBuilder<${this._mainAlias?.entityName}>` : 'QueryBuilder';
|
|
908
|
+
const ret = (0, util_1.inspect)(object, { depth });
|
|
909
|
+
return ret === '[Object]' ? `[${name}]` : name + ' ' + ret;
|
|
910
|
+
}
|
|
687
911
|
}
|
|
688
912
|
exports.QueryBuilder = QueryBuilder;
|