@mikro-orm/knex 6.0.0-dev.2 → 6.0.0-dev.20
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} +230 -71
- 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} +1 -2
- 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 +65 -24
- package/{dist/query → query}/QueryBuilder.js +318 -84
- package/{dist/query → query}/QueryBuilderHelper.d.ts +19 -11
- package/{dist/query → query}/QueryBuilderHelper.js +224 -113
- 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 +60 -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,41 @@ 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
|
}
|
|
492
|
+
/**
|
|
493
|
+
* Executes the query, returning both array of results and total count query (without offset and limit).
|
|
494
|
+
*/
|
|
495
|
+
async getResultAndCount() {
|
|
496
|
+
return Promise.all([
|
|
497
|
+
this.getResultList(),
|
|
498
|
+
this.getCount(),
|
|
499
|
+
]);
|
|
500
|
+
}
|
|
389
501
|
/**
|
|
390
502
|
* Provides promise-like interface so we can await the QB instance.
|
|
391
503
|
*/
|
|
392
504
|
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
|
-
})();
|
|
505
|
+
switch (this.type ?? enums_1.QueryType.SELECT) {
|
|
506
|
+
case enums_1.QueryType.INSERT:
|
|
507
|
+
case enums_1.QueryType.UPDATE:
|
|
508
|
+
case enums_1.QueryType.DELETE:
|
|
509
|
+
case enums_1.QueryType.TRUNCATE:
|
|
510
|
+
return this.execute('run').then(onfulfilled, onrejected);
|
|
511
|
+
case enums_1.QueryType.COUNT:
|
|
512
|
+
return this.getCount().then(onfulfilled, onrejected);
|
|
513
|
+
case enums_1.QueryType.SELECT: return this.getResultList().then(onfulfilled, onrejected);
|
|
410
514
|
}
|
|
411
|
-
return this.innerPromise;
|
|
412
515
|
}
|
|
413
516
|
/**
|
|
414
517
|
* Returns knex instance with sub-query aliased with given alias.
|
|
@@ -425,11 +528,11 @@ class QueryBuilder {
|
|
|
425
528
|
return qb.as(alias);
|
|
426
529
|
}
|
|
427
530
|
clone() {
|
|
428
|
-
const qb = new QueryBuilder(this.entityName, this.metadata, this.driver, this.context, this.
|
|
531
|
+
const qb = new QueryBuilder(this.mainAlias.entityName, this.metadata, this.driver, this.context, this.mainAlias.aliasName, this.connectionType, this.em);
|
|
429
532
|
Object.assign(qb, this);
|
|
430
533
|
// clone array/object properties
|
|
431
534
|
const properties = [
|
|
432
|
-
'flags', '_populate', '
|
|
535
|
+
'flags', '_populate', '_populateWhere', '_populateMap', '_joins', '_joinedProps', '_cond', '_data', '_orderBy',
|
|
433
536
|
'_schema', '_indexHint', '_cache', 'subQueries', 'lockMode', 'lockTables',
|
|
434
537
|
];
|
|
435
538
|
properties.forEach(prop => qb[prop] = core_1.Utils.copy(this[prop]));
|
|
@@ -437,27 +540,45 @@ class QueryBuilder {
|
|
|
437
540
|
if (this._fields) {
|
|
438
541
|
qb._fields = [...this._fields];
|
|
439
542
|
}
|
|
543
|
+
qb._aliases = { ...this._aliases };
|
|
440
544
|
qb.finalized = false;
|
|
441
545
|
return qb;
|
|
442
546
|
}
|
|
443
547
|
getKnex() {
|
|
444
|
-
const
|
|
445
|
-
const
|
|
548
|
+
const qb = this.knex.queryBuilder();
|
|
549
|
+
const { subQuery, aliasName, entityName } = this.mainAlias;
|
|
550
|
+
const ref = subQuery ? subQuery : this.knex.ref(this.helper.getTableName(entityName));
|
|
551
|
+
if (this.finalized && (this._explicitAlias || this.helper.isTableNameAliasRequired(this.type))) {
|
|
552
|
+
ref.as(aliasName);
|
|
553
|
+
}
|
|
554
|
+
const schema = this.getSchema(this.mainAlias);
|
|
555
|
+
if (schema) {
|
|
556
|
+
ref.withSchema(schema);
|
|
557
|
+
}
|
|
558
|
+
qb.from(ref);
|
|
446
559
|
if (this.context) {
|
|
447
560
|
qb.transacting(this.context);
|
|
448
561
|
}
|
|
449
562
|
return qb;
|
|
450
563
|
}
|
|
451
564
|
joinReference(field, alias, cond, type, path) {
|
|
565
|
+
this.ensureNotFinalized();
|
|
452
566
|
const [fromAlias, fromField] = this.helper.splitField(field);
|
|
453
|
-
const entityName = this.
|
|
567
|
+
const entityName = this._aliases[fromAlias]?.entityName;
|
|
454
568
|
const meta = this.metadata.get(entityName);
|
|
455
569
|
const prop = meta.properties[fromField];
|
|
456
570
|
if (!prop) {
|
|
457
571
|
throw new Error(`Trying to join ${field}, but ${fromField} is not a defined relation on ${meta.className}`);
|
|
458
572
|
}
|
|
459
|
-
this.
|
|
460
|
-
cond = core_1.QueryHelper.processWhere(
|
|
573
|
+
this.createAlias(prop.type, alias);
|
|
574
|
+
cond = core_1.QueryHelper.processWhere({
|
|
575
|
+
where: cond,
|
|
576
|
+
entityName: this.mainAlias.entityName,
|
|
577
|
+
metadata: this.metadata,
|
|
578
|
+
platform: this.platform,
|
|
579
|
+
aliasMap: this.getAliasMap(),
|
|
580
|
+
aliased: !this.type || [enums_1.QueryType.SELECT, enums_1.QueryType.COUNT].includes(this.type),
|
|
581
|
+
});
|
|
461
582
|
let aliasedName = `${fromAlias}.${prop.name}#${alias}`;
|
|
462
583
|
path ?? (path = `${(Object.values(this._joins).find(j => j.alias === fromAlias)?.path ?? entityName)}.${prop.name}`);
|
|
463
584
|
if (prop.reference === core_1.ReferenceType.ONE_TO_MANY) {
|
|
@@ -467,12 +588,12 @@ class QueryBuilder {
|
|
|
467
588
|
let pivotAlias = alias;
|
|
468
589
|
if (type !== 'pivotJoin') {
|
|
469
590
|
const oldPivotAlias = this.getAliasForJoinPath(path + '[pivot]');
|
|
470
|
-
pivotAlias = oldPivotAlias ?? this.getNextAlias(prop.
|
|
591
|
+
pivotAlias = oldPivotAlias ?? this.getNextAlias(prop.pivotEntity);
|
|
471
592
|
aliasedName = `${fromAlias}.${prop.name}#${pivotAlias}`;
|
|
472
593
|
}
|
|
473
594
|
const joins = this.helper.joinManyToManyReference(prop, fromAlias, alias, pivotAlias, type, cond, path);
|
|
474
595
|
Object.assign(this._joins, joins);
|
|
475
|
-
this.
|
|
596
|
+
this.createAlias(prop.pivotEntity, pivotAlias);
|
|
476
597
|
}
|
|
477
598
|
else if (prop.reference === core_1.ReferenceType.ONE_TO_ONE) {
|
|
478
599
|
this._joins[aliasedName] = this.helper.joinOneToReference(prop, fromAlias, alias, type, cond);
|
|
@@ -493,24 +614,50 @@ class QueryBuilder {
|
|
|
493
614
|
}
|
|
494
615
|
const join = Object.keys(this._joins).find(k => field === k.substring(0, k.indexOf('#')));
|
|
495
616
|
if (join && type === 'where') {
|
|
496
|
-
return ret.push(...this.helper.mapJoinColumns(this.type, this._joins[join]));
|
|
617
|
+
return ret.push(...this.helper.mapJoinColumns(this.type ?? enums_1.QueryType.SELECT, this._joins[join]));
|
|
497
618
|
}
|
|
498
619
|
const [a, f] = this.helper.splitField(field);
|
|
499
620
|
const prop = this.helper.getProperty(f, a);
|
|
621
|
+
/* istanbul ignore next */
|
|
500
622
|
if (prop && [core_1.ReferenceType.ONE_TO_MANY, core_1.ReferenceType.MANY_TO_MANY].includes(prop.reference)) {
|
|
501
623
|
return;
|
|
502
624
|
}
|
|
625
|
+
if (prop?.embedded) {
|
|
626
|
+
const fieldName = this.helper.mapper(prop.fieldNames[0], this.type);
|
|
627
|
+
ret.push(fieldName);
|
|
628
|
+
return;
|
|
629
|
+
}
|
|
630
|
+
if (prop?.reference === core_1.ReferenceType.EMBEDDED) {
|
|
631
|
+
if (prop.object) {
|
|
632
|
+
ret.push(this.helper.mapper(prop.fieldNames[0], this.type));
|
|
633
|
+
}
|
|
634
|
+
else {
|
|
635
|
+
const nest = (prop) => {
|
|
636
|
+
for (const childProp of Object.values(prop.embeddedProps)) {
|
|
637
|
+
if (childProp.fieldNames) {
|
|
638
|
+
ret.push(this.helper.mapper(childProp.fieldNames[0], this.type));
|
|
639
|
+
}
|
|
640
|
+
else {
|
|
641
|
+
nest(childProp);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
};
|
|
645
|
+
nest(prop);
|
|
646
|
+
}
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
503
649
|
ret.push(this.helper.mapper(field, this.type));
|
|
504
650
|
});
|
|
505
|
-
const meta = this.metadata
|
|
651
|
+
const meta = this.mainAlias.metadata;
|
|
506
652
|
/* istanbul ignore next */
|
|
507
653
|
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.
|
|
654
|
+
if (this.flags.has(core_1.QueryFlag.CONVERT_CUSTOM_TYPES) && (fields.includes('*') || fields.includes(`${this.mainAlias.aliasName}.*`)) && requiresSQLConversion.length > 0) {
|
|
509
655
|
requiresSQLConversion.forEach(p => ret.push(this.helper.mapper(p.name, this.type)));
|
|
510
656
|
}
|
|
511
657
|
Object.keys(this._populateMap).forEach(f => {
|
|
512
658
|
if (!fields.includes(f.replace(/#\w+$/, '')) && type === 'where') {
|
|
513
|
-
|
|
659
|
+
const cols = this.helper.mapJoinColumns(this.type ?? enums_1.QueryType.SELECT, this._joins[f]);
|
|
660
|
+
ret.push(...cols);
|
|
514
661
|
}
|
|
515
662
|
if (this._joins[f].prop.reference !== core_1.ReferenceType.ONE_TO_ONE && this._joins[f].inverseJoinColumns) {
|
|
516
663
|
this._joins[f].inverseJoinColumns.forEach(inverseJoinColumn => {
|
|
@@ -521,8 +668,8 @@ class QueryBuilder {
|
|
|
521
668
|
return ret;
|
|
522
669
|
}
|
|
523
670
|
init(type, data, cond) {
|
|
671
|
+
this.ensureNotFinalized();
|
|
524
672
|
this.type = type;
|
|
525
|
-
this._aliasMap[this.alias] = this.entityName;
|
|
526
673
|
if ([enums_1.QueryType.UPDATE, enums_1.QueryType.DELETE].includes(type) && core_1.Utils.hasObjectKeys(this._cond)) {
|
|
527
674
|
throw new Error(`You are trying to call \`qb.where().${type.toLowerCase()}()\`. Calling \`qb.${type.toLowerCase()}()\` before \`qb.where()\` is required.`);
|
|
528
675
|
}
|
|
@@ -530,6 +677,10 @@ class QueryBuilder {
|
|
|
530
677
|
delete this._fields;
|
|
531
678
|
}
|
|
532
679
|
if (data) {
|
|
680
|
+
if (core_1.Utils.isEntity(data)) {
|
|
681
|
+
// data = helper(data).toJSON();
|
|
682
|
+
data = this.em?.getComparator().prepareEntity(data) ?? (0, core_1.serialize)(data);
|
|
683
|
+
}
|
|
533
684
|
this._data = this.helper.processData(data, this.flags.has(core_1.QueryFlag.CONVERT_CUSTOM_TYPES));
|
|
534
685
|
}
|
|
535
686
|
if (cond) {
|
|
@@ -539,22 +690,23 @@ class QueryBuilder {
|
|
|
539
690
|
}
|
|
540
691
|
getQueryBase() {
|
|
541
692
|
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');
|
|
693
|
+
const schema = this.getSchema(this.mainAlias);
|
|
545
694
|
if (schema) {
|
|
546
695
|
qb.withSchema(schema);
|
|
547
696
|
}
|
|
548
697
|
if (this._indexHint) {
|
|
549
|
-
const alias = this.helper.isTableNameAliasRequired(this.type) ? ` as ${this.platform.quoteIdentifier(this.
|
|
698
|
+
const alias = this.helper.isTableNameAliasRequired(this.type) ? ` as ${this.platform.quoteIdentifier(this.mainAlias.aliasName)}` : '';
|
|
550
699
|
const schemaQuoted = schema ? this.platform.quoteIdentifier(schema) + '.' : '';
|
|
551
|
-
const tableName = schemaQuoted + this.platform.quoteIdentifier(this.helper.getTableName(this.entityName)) + alias;
|
|
700
|
+
const tableName = schemaQuoted + this.platform.quoteIdentifier(this.helper.getTableName(this.mainAlias.entityName)) + alias;
|
|
552
701
|
qb.from(this.knex.raw(`${tableName} ${this._indexHint}`));
|
|
553
702
|
}
|
|
554
703
|
switch (this.type) {
|
|
555
704
|
case enums_1.QueryType.SELECT:
|
|
556
705
|
qb.select(this.prepareFields(this._fields));
|
|
557
|
-
if (this.
|
|
706
|
+
if (this._distinctOn) {
|
|
707
|
+
qb.distinctOn(this._distinctOn);
|
|
708
|
+
}
|
|
709
|
+
else if (this.flags.has(core_1.QueryFlag.DISTINCT)) {
|
|
558
710
|
qb.distinct();
|
|
559
711
|
}
|
|
560
712
|
this.helper.processJoins(qb, this._joins, schema);
|
|
@@ -588,7 +740,7 @@ class QueryBuilder {
|
|
|
588
740
|
if (!this.type) {
|
|
589
741
|
this.select('*');
|
|
590
742
|
}
|
|
591
|
-
const meta = this.metadata
|
|
743
|
+
const meta = this.mainAlias.metadata;
|
|
592
744
|
if (meta && this.flags.has(core_1.QueryFlag.AUTO_JOIN_ONE_TO_ONE_OWNER)) {
|
|
593
745
|
const relationsToPopulate = this._populate.map(({ field }) => field);
|
|
594
746
|
meta.relations
|
|
@@ -600,7 +752,7 @@ class QueryBuilder {
|
|
|
600
752
|
const [fromAlias, fromField] = this.helper.splitField(field);
|
|
601
753
|
const aliasedField = `${fromAlias}.${fromField}`;
|
|
602
754
|
const join = Object.keys(this._joins).find(k => `${aliasedField}#${this._joins[k].alias}` === k);
|
|
603
|
-
if (this._joins[join] && this.helper.isOneToOneInverse(fromField)) {
|
|
755
|
+
if (join && this._joins[join] && this.helper.isOneToOneInverse(fromField)) {
|
|
604
756
|
return this._populateMap[join] = this._joins[join].alias;
|
|
605
757
|
}
|
|
606
758
|
if (this.metadata.find(field)?.pivotTable) { // pivot table entity
|
|
@@ -608,16 +760,17 @@ class QueryBuilder {
|
|
|
608
760
|
}
|
|
609
761
|
else if (meta && this.helper.isOneToOneInverse(fromField)) {
|
|
610
762
|
const prop = meta.properties[fromField];
|
|
611
|
-
const alias = this.getNextAlias(prop.
|
|
612
|
-
|
|
613
|
-
this.
|
|
763
|
+
const alias = this.getNextAlias(prop.pivotEntity ?? prop.type);
|
|
764
|
+
const aliasedName = `${fromAlias}.${prop.name}#${alias}`;
|
|
765
|
+
this._joins[aliasedName] = this.helper.joinOneToReference(prop, this.mainAlias.aliasName, alias, 'leftJoin');
|
|
766
|
+
this._populateMap[aliasedName] = this._joins[aliasedName].alias;
|
|
614
767
|
}
|
|
615
768
|
});
|
|
616
|
-
if (meta && (this._fields?.includes('*') || this._fields?.includes(`${this.
|
|
769
|
+
if (meta && (this._fields?.includes('*') || this._fields?.includes(`${this.mainAlias.aliasName}.*`))) {
|
|
617
770
|
meta.props
|
|
618
771
|
.filter(prop => prop.formula && (!prop.lazy || this.flags.has(core_1.QueryFlag.INCLUDE_LAZY_FORMULAS)))
|
|
619
772
|
.map(prop => {
|
|
620
|
-
const alias = this.knex.ref(this.
|
|
773
|
+
const alias = this.knex.ref(this.mainAlias.aliasName).toString();
|
|
621
774
|
const aliased = this.knex.ref(prop.fieldNames[0]).toString();
|
|
622
775
|
return `${prop.formula(alias)} as ${aliased}`;
|
|
623
776
|
})
|
|
@@ -627,13 +780,22 @@ class QueryBuilder {
|
|
|
627
780
|
core_1.QueryHelper.processObjectParams(this._data);
|
|
628
781
|
core_1.QueryHelper.processObjectParams(this._cond);
|
|
629
782
|
core_1.QueryHelper.processObjectParams(this._having);
|
|
630
|
-
|
|
631
|
-
if (
|
|
783
|
+
// automatically enable paginate flag when we detect to-many joins
|
|
784
|
+
if (!this.flags.has(core_1.QueryFlag.DISABLE_PAGINATE) && this.hasToManyJoins()) {
|
|
785
|
+
this.flags.add(core_1.QueryFlag.PAGINATE);
|
|
786
|
+
}
|
|
787
|
+
if (meta && this.flags.has(core_1.QueryFlag.PAGINATE) && (this._limit > 0 || this._offset > 0)) {
|
|
632
788
|
this.wrapPaginateSubQuery(meta);
|
|
633
789
|
}
|
|
634
790
|
if (meta && (this.flags.has(core_1.QueryFlag.UPDATE_SUB_QUERY) || this.flags.has(core_1.QueryFlag.DELETE_SUB_QUERY))) {
|
|
635
791
|
this.wrapModifySubQuery(meta);
|
|
636
792
|
}
|
|
793
|
+
this.finalized = true;
|
|
794
|
+
}
|
|
795
|
+
hasToManyJoins() {
|
|
796
|
+
return Object.values(this._joins).some(join => {
|
|
797
|
+
return [core_1.ReferenceType.ONE_TO_MANY, core_1.ReferenceType.MANY_TO_MANY].includes(join.prop.reference);
|
|
798
|
+
});
|
|
637
799
|
}
|
|
638
800
|
wrapPaginateSubQuery(meta) {
|
|
639
801
|
const pks = this.prepareFields(meta.primaryKeys, 'sub-query');
|
|
@@ -645,28 +807,38 @@ class QueryBuilder {
|
|
|
645
807
|
const orderBy = [];
|
|
646
808
|
for (const orderMap of this._orderBy) {
|
|
647
809
|
for (const [field, direction] of Object.entries(orderMap)) {
|
|
810
|
+
const [a, f] = this.helper.splitField(field);
|
|
811
|
+
const prop = this.helper.getProperty(f, a);
|
|
812
|
+
const type = this.platform.castColumn(prop);
|
|
648
813
|
orderBy.push({
|
|
649
|
-
[`min(${this.ref(field)})`]: direction,
|
|
814
|
+
[`min(${this.ref(this.helper.mapper(field, this.type, undefined, null))}${type})`]: direction,
|
|
650
815
|
});
|
|
651
816
|
}
|
|
652
817
|
}
|
|
653
818
|
subQuery.orderBy(orderBy);
|
|
654
819
|
}
|
|
655
820
|
subQuery.finalized = true;
|
|
656
|
-
const knexQuery = subQuery.as(this.
|
|
821
|
+
const knexQuery = subQuery.as(this.mainAlias.aliasName).clearSelect().select(pks);
|
|
657
822
|
// multiple sub-queries are needed to get around mysql limitations with order by + limit + where in + group by (o.O)
|
|
658
823
|
// https://stackoverflow.com/questions/17892762/mysql-this-version-of-mysql-doesnt-yet-support-limit-in-all-any-some-subqu
|
|
659
824
|
const subSubQuery = this.getKnex().select(pks).from(knexQuery);
|
|
660
825
|
this._limit = undefined;
|
|
661
826
|
this._offset = undefined;
|
|
827
|
+
const cond = this._cond;
|
|
662
828
|
this.select(this._fields).where({ [core_1.Utils.getPrimaryKeyHash(meta.primaryKeys)]: { $in: subSubQuery } });
|
|
829
|
+
if (this._populateWhere === core_1.PopulateHint.INFER) {
|
|
830
|
+
this.andWhere(cond);
|
|
831
|
+
}
|
|
832
|
+
else if (typeof this._populateWhere === 'object') {
|
|
833
|
+
this.andWhere(this._populateWhere);
|
|
834
|
+
}
|
|
663
835
|
}
|
|
664
836
|
wrapModifySubQuery(meta) {
|
|
665
837
|
const subQuery = this.clone();
|
|
666
838
|
subQuery.finalized = true;
|
|
667
839
|
// wrap one more time to get around MySQL limitations
|
|
668
840
|
// 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.
|
|
841
|
+
const subSubQuery = this.getKnex().select(this.prepareFields(meta.primaryKeys)).from(subQuery.as(this.mainAlias.aliasName));
|
|
670
842
|
const method = this.flags.has(core_1.QueryFlag.UPDATE_SUB_QUERY) ? 'update' : 'delete';
|
|
671
843
|
this._cond = {}; // otherwise we would trigger validation error
|
|
672
844
|
this[method](this._data).where({
|
|
@@ -675,14 +847,76 @@ class QueryBuilder {
|
|
|
675
847
|
}
|
|
676
848
|
autoJoinPivotTable(field) {
|
|
677
849
|
const pivotMeta = this.metadata.find(field);
|
|
678
|
-
const owner = pivotMeta.
|
|
679
|
-
const inverse = pivotMeta.
|
|
850
|
+
const owner = pivotMeta.relations[0];
|
|
851
|
+
const inverse = pivotMeta.relations[1];
|
|
680
852
|
const prop = this._cond[pivotMeta.name + '.' + owner.name] || this._orderBy[pivotMeta.name + '.' + owner.name] ? inverse : owner;
|
|
681
853
|
const pivotAlias = this.getNextAlias(pivotMeta.name);
|
|
682
|
-
this._joins[field] = this.helper.joinPivotTable(field, prop, this.
|
|
854
|
+
this._joins[field] = this.helper.joinPivotTable(field, prop, this.mainAlias.aliasName, pivotAlias, 'leftJoin');
|
|
683
855
|
core_1.Utils.renameKey(this._cond, `${field}.${owner.name}`, core_1.Utils.getPrimaryKeyHash(owner.fieldNames.map(fieldName => `${pivotAlias}.${fieldName}`)));
|
|
684
856
|
core_1.Utils.renameKey(this._cond, `${field}.${inverse.name}`, core_1.Utils.getPrimaryKeyHash(inverse.fieldNames.map(fieldName => `${pivotAlias}.${fieldName}`)));
|
|
685
857
|
this._populateMap[field] = this._joins[field].alias;
|
|
686
858
|
}
|
|
859
|
+
getSchema(alias) {
|
|
860
|
+
const { metadata } = alias;
|
|
861
|
+
const metaSchema = metadata?.schema && metadata.schema !== '*' ? metadata.schema : undefined;
|
|
862
|
+
return this._schema ?? metaSchema ?? this.em?.config.get('schema');
|
|
863
|
+
}
|
|
864
|
+
createAlias(entityName, aliasName, subQuery) {
|
|
865
|
+
const metadata = this.metadata.find(entityName);
|
|
866
|
+
const alias = { aliasName, entityName, metadata, subQuery };
|
|
867
|
+
this._aliases[aliasName] = alias;
|
|
868
|
+
return alias;
|
|
869
|
+
}
|
|
870
|
+
createMainAlias(entityName, aliasName, subQuery) {
|
|
871
|
+
this._mainAlias = this.createAlias(entityName, aliasName, subQuery);
|
|
872
|
+
this._helper = this.createQueryBuilderHelper();
|
|
873
|
+
return this._mainAlias;
|
|
874
|
+
}
|
|
875
|
+
fromSubQuery(target, aliasName) {
|
|
876
|
+
const subQuery = target.getKnexQuery();
|
|
877
|
+
const { entityName } = target.mainAlias;
|
|
878
|
+
aliasName ?? (aliasName = this.getNextAlias(entityName));
|
|
879
|
+
this.createMainAlias(entityName, aliasName, subQuery);
|
|
880
|
+
}
|
|
881
|
+
fromEntityName(entityName, aliasName) {
|
|
882
|
+
aliasName ?? (aliasName = this._mainAlias?.aliasName ?? this.getNextAlias(entityName));
|
|
883
|
+
this.createMainAlias(entityName, aliasName);
|
|
884
|
+
}
|
|
885
|
+
createQueryBuilderHelper() {
|
|
886
|
+
return new QueryBuilderHelper_1.QueryBuilderHelper(this.mainAlias.entityName, this.mainAlias.aliasName, this._aliases, this.subQueries, this.knex, this.driver);
|
|
887
|
+
}
|
|
888
|
+
ensureFromClause() {
|
|
889
|
+
/* istanbul ignore next */
|
|
890
|
+
if (!this._mainAlias) {
|
|
891
|
+
throw new Error(`Cannot proceed to build a query because the main alias is not set.`);
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
ensureNotFinalized() {
|
|
895
|
+
if (this.finalized) {
|
|
896
|
+
throw new Error('This QueryBuilder instance is already finalized, clone it first if you want to modify it.');
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
/* istanbul ignore next */
|
|
900
|
+
[util_1.inspect.custom](depth) {
|
|
901
|
+
const object = { ...this };
|
|
902
|
+
const hidden = ['metadata', 'driver', 'context', 'platform', 'knex', 'type'];
|
|
903
|
+
Object.keys(object).filter(k => k.startsWith('_')).forEach(k => delete object[k]);
|
|
904
|
+
Object.keys(object).filter(k => object[k] == null).forEach(k => delete object[k]);
|
|
905
|
+
hidden.forEach(k => delete object[k]);
|
|
906
|
+
let prefix = this.type ? this.type.substring(0, 1) + this.type.toLowerCase().substring(1) : '';
|
|
907
|
+
if (this._data) {
|
|
908
|
+
object.data = this._data;
|
|
909
|
+
}
|
|
910
|
+
if (!core_1.Utils.isEmpty(this._cond)) {
|
|
911
|
+
object.where = this._cond;
|
|
912
|
+
}
|
|
913
|
+
if (this._onConflict?.[0]) {
|
|
914
|
+
prefix = 'Upsert';
|
|
915
|
+
object.onConflict = this._onConflict[0];
|
|
916
|
+
}
|
|
917
|
+
const name = this._mainAlias ? `${prefix}QueryBuilder<${this._mainAlias?.entityName}>` : 'QueryBuilder';
|
|
918
|
+
const ret = (0, util_1.inspect)(object, { depth });
|
|
919
|
+
return ret === '[Object]' ? `[${name}]` : name + ' ' + ret;
|
|
920
|
+
}
|
|
687
921
|
}
|
|
688
922
|
exports.QueryBuilder = QueryBuilder;
|