@mikro-orm/knex 7.0.0-dev.1 → 7.0.0-dev.2
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 +2 -2
- package/AbstractSqlConnection.js +22 -25
- package/AbstractSqlDriver.d.ts +9 -7
- package/AbstractSqlDriver.js +175 -180
- package/AbstractSqlPlatform.d.ts +4 -4
- package/AbstractSqlPlatform.js +17 -21
- package/PivotCollectionPersister.d.ts +1 -1
- package/PivotCollectionPersister.js +5 -8
- package/SqlEntityManager.d.ts +4 -3
- package/SqlEntityManager.js +2 -6
- package/SqlEntityRepository.d.ts +2 -2
- package/SqlEntityRepository.js +2 -6
- package/dialects/index.d.ts +4 -4
- package/dialects/index.js +4 -20
- package/dialects/mssql/MsSqlNativeQueryBuilder.d.ts +1 -1
- package/dialects/mssql/MsSqlNativeQueryBuilder.js +21 -25
- package/dialects/mssql/index.d.ts +1 -1
- package/dialects/mssql/index.js +1 -17
- package/dialects/mysql/MySqlExceptionConverter.js +16 -19
- package/dialects/mysql/MySqlNativeQueryBuilder.d.ts +1 -1
- package/dialects/mysql/MySqlNativeQueryBuilder.js +13 -17
- package/dialects/mysql/MySqlPlatform.d.ts +5 -5
- package/dialects/mysql/MySqlPlatform.js +16 -20
- package/dialects/mysql/MySqlSchemaHelper.d.ts +5 -5
- package/dialects/mysql/MySqlSchemaHelper.js +8 -12
- package/dialects/mysql/index.d.ts +4 -4
- package/dialects/mysql/index.js +4 -20
- package/dialects/postgresql/PostgreSqlNativeQueryBuilder.d.ts +1 -1
- package/dialects/postgresql/PostgreSqlNativeQueryBuilder.js +2 -6
- package/dialects/postgresql/index.d.ts +1 -1
- package/dialects/postgresql/index.js +1 -17
- package/dialects/sqlite/BaseSqliteConnection.d.ts +1 -1
- package/dialects/sqlite/BaseSqliteConnection.js +7 -11
- package/dialects/sqlite/BaseSqlitePlatform.d.ts +4 -4
- package/dialects/sqlite/BaseSqlitePlatform.js +11 -15
- package/dialects/sqlite/SqliteExceptionConverter.js +16 -19
- package/dialects/sqlite/SqliteNativeQueryBuilder.d.ts +1 -1
- package/dialects/sqlite/SqliteNativeQueryBuilder.js +2 -6
- package/dialects/sqlite/SqliteSchemaHelper.d.ts +5 -5
- package/dialects/sqlite/SqliteSchemaHelper.js +22 -26
- package/dialects/sqlite/index.d.ts +5 -5
- package/dialects/sqlite/index.js +5 -21
- package/index.d.ts +11 -11
- package/index.js +13 -34
- package/package.json +5 -14
- package/query/ArrayCriteriaNode.d.ts +2 -2
- package/query/ArrayCriteriaNode.js +2 -6
- package/query/CriteriaNode.d.ts +1 -1
- package/query/CriteriaNode.js +26 -30
- package/query/CriteriaNodeFactory.d.ts +1 -1
- package/query/CriteriaNodeFactory.js +17 -21
- package/query/NativeQueryBuilder.d.ts +2 -2
- package/query/NativeQueryBuilder.js +33 -37
- package/query/ObjectCriteriaNode.d.ts +2 -2
- package/query/ObjectCriteriaNode.js +37 -41
- package/query/QueryBuilder.d.ts +7 -7
- package/query/QueryBuilder.js +172 -176
- package/query/QueryBuilderHelper.d.ts +4 -4
- package/query/QueryBuilderHelper.js +84 -88
- package/query/ScalarCriteriaNode.d.ts +2 -2
- package/query/ScalarCriteriaNode.js +12 -16
- package/query/enums.js +4 -7
- package/query/index.d.ts +9 -9
- package/query/index.js +9 -25
- package/schema/DatabaseSchema.d.ts +3 -3
- package/schema/DatabaseSchema.js +7 -11
- package/schema/DatabaseTable.d.ts +3 -3
- package/schema/DatabaseTable.js +26 -30
- package/schema/SchemaComparator.d.ts +4 -4
- package/schema/SchemaComparator.js +15 -19
- package/schema/SchemaHelper.d.ts +5 -5
- package/schema/SchemaHelper.js +22 -26
- package/schema/SqlSchemaGenerator.d.ts +4 -4
- package/schema/SqlSchemaGenerator.js +18 -21
- package/schema/index.d.ts +5 -5
- package/schema/index.js +5 -21
- package/typings.d.ts +5 -4
- package/typings.js +1 -2
- package/index.mjs +0 -232
package/query/QueryBuilder.js
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const QueryBuilderHelper_1 = require("./QueryBuilderHelper");
|
|
8
|
-
const CriteriaNodeFactory_1 = require("./CriteriaNodeFactory");
|
|
9
|
-
const NativeQueryBuilder_1 = require("./NativeQueryBuilder");
|
|
1
|
+
import { inspect } from 'node:util';
|
|
2
|
+
import { helper, isRaw, LoadStrategy, LockMode, PopulateHint, QueryFlag, QueryHelper, raw, RawQueryFragment, Reference, ReferenceKind, serialize, Utils, ValidationError, } from '@mikro-orm/core';
|
|
3
|
+
import { JoinType, QueryType } from './enums.js';
|
|
4
|
+
import { QueryBuilderHelper } from './QueryBuilderHelper.js';
|
|
5
|
+
import { CriteriaNodeFactory } from './CriteriaNodeFactory.js';
|
|
6
|
+
import { NativeQueryBuilder } from './NativeQueryBuilder.js';
|
|
10
7
|
/**
|
|
11
8
|
* SQL query builder with fluent interface.
|
|
12
9
|
*
|
|
@@ -26,7 +23,7 @@ const NativeQueryBuilder_1 = require("./NativeQueryBuilder");
|
|
|
26
23
|
* const publisher = await qb.getSingleResult();
|
|
27
24
|
* ```
|
|
28
25
|
*/
|
|
29
|
-
class QueryBuilder {
|
|
26
|
+
export class QueryBuilder {
|
|
30
27
|
metadata;
|
|
31
28
|
driver;
|
|
32
29
|
context;
|
|
@@ -45,7 +42,7 @@ class QueryBuilder {
|
|
|
45
42
|
return this._helper;
|
|
46
43
|
}
|
|
47
44
|
get type() {
|
|
48
|
-
return this._type ??
|
|
45
|
+
return this._type ?? QueryType.SELECT;
|
|
49
46
|
}
|
|
50
47
|
/** @internal */
|
|
51
48
|
_populate = [];
|
|
@@ -54,7 +51,7 @@ class QueryBuilder {
|
|
|
54
51
|
/** @internal */
|
|
55
52
|
rawFragments = new Set();
|
|
56
53
|
aliasCounter = 0;
|
|
57
|
-
flags = new Set([
|
|
54
|
+
flags = new Set([QueryFlag.CONVERT_CUSTOM_TYPES]);
|
|
58
55
|
finalized = false;
|
|
59
56
|
populateHintFinalized = false;
|
|
60
57
|
_joins = {};
|
|
@@ -104,75 +101,75 @@ class QueryBuilder {
|
|
|
104
101
|
}
|
|
105
102
|
select(fields, distinct = false) {
|
|
106
103
|
this.ensureNotFinalized();
|
|
107
|
-
this._fields =
|
|
104
|
+
this._fields = Utils.asArray(fields);
|
|
108
105
|
if (distinct) {
|
|
109
|
-
this.flags.add(
|
|
106
|
+
this.flags.add(QueryFlag.DISTINCT);
|
|
110
107
|
}
|
|
111
|
-
return this.init(
|
|
108
|
+
return this.init(QueryType.SELECT);
|
|
112
109
|
}
|
|
113
110
|
addSelect(fields) {
|
|
114
111
|
this.ensureNotFinalized();
|
|
115
|
-
if (this._type && this._type !==
|
|
112
|
+
if (this._type && this._type !== QueryType.SELECT) {
|
|
116
113
|
return this;
|
|
117
114
|
}
|
|
118
|
-
return this.select([...
|
|
115
|
+
return this.select([...Utils.asArray(this._fields), ...Utils.asArray(fields)]);
|
|
119
116
|
}
|
|
120
117
|
distinct() {
|
|
121
118
|
this.ensureNotFinalized();
|
|
122
|
-
return this.setFlag(
|
|
119
|
+
return this.setFlag(QueryFlag.DISTINCT);
|
|
123
120
|
}
|
|
124
121
|
/** postgres only */
|
|
125
122
|
distinctOn(fields) {
|
|
126
123
|
this.ensureNotFinalized();
|
|
127
|
-
this._distinctOn =
|
|
124
|
+
this._distinctOn = Utils.asArray(fields);
|
|
128
125
|
return this;
|
|
129
126
|
}
|
|
130
127
|
insert(data) {
|
|
131
|
-
return this.init(
|
|
128
|
+
return this.init(QueryType.INSERT, data);
|
|
132
129
|
}
|
|
133
130
|
update(data) {
|
|
134
|
-
return this.init(
|
|
131
|
+
return this.init(QueryType.UPDATE, data);
|
|
135
132
|
}
|
|
136
133
|
delete(cond) {
|
|
137
|
-
return this.init(
|
|
134
|
+
return this.init(QueryType.DELETE, undefined, cond);
|
|
138
135
|
}
|
|
139
136
|
truncate() {
|
|
140
|
-
return this.init(
|
|
137
|
+
return this.init(QueryType.TRUNCATE);
|
|
141
138
|
}
|
|
142
139
|
count(field, distinct = false) {
|
|
143
140
|
if (field) {
|
|
144
|
-
this._fields =
|
|
141
|
+
this._fields = Utils.asArray(field);
|
|
145
142
|
}
|
|
146
143
|
else if (distinct || this.hasToManyJoins()) {
|
|
147
144
|
this._fields = this.mainAlias.metadata.primaryKeys;
|
|
148
145
|
}
|
|
149
146
|
else {
|
|
150
|
-
this._fields = [
|
|
147
|
+
this._fields = [raw('*')];
|
|
151
148
|
}
|
|
152
149
|
if (distinct) {
|
|
153
|
-
this.flags.add(
|
|
150
|
+
this.flags.add(QueryFlag.DISTINCT);
|
|
154
151
|
}
|
|
155
|
-
return this.init(
|
|
152
|
+
return this.init(QueryType.COUNT);
|
|
156
153
|
}
|
|
157
|
-
join(field, alias, cond = {}, type =
|
|
154
|
+
join(field, alias, cond = {}, type = JoinType.innerJoin, path, schema) {
|
|
158
155
|
this.joinReference(field, alias, cond, type, path, schema);
|
|
159
156
|
return this;
|
|
160
157
|
}
|
|
161
158
|
innerJoin(field, alias, cond = {}, schema) {
|
|
162
|
-
this.join(field, alias, cond,
|
|
159
|
+
this.join(field, alias, cond, JoinType.innerJoin, undefined, schema);
|
|
163
160
|
return this;
|
|
164
161
|
}
|
|
165
162
|
innerJoinLateral(field, alias, cond, schema) {
|
|
166
|
-
this.join(field, alias, cond,
|
|
163
|
+
this.join(field, alias, cond, JoinType.innerJoinLateral, undefined, schema);
|
|
167
164
|
return this;
|
|
168
165
|
}
|
|
169
166
|
leftJoin(field, alias, cond = {}, schema) {
|
|
170
|
-
return this.join(field, alias, cond,
|
|
167
|
+
return this.join(field, alias, cond, JoinType.leftJoin, undefined, schema);
|
|
171
168
|
}
|
|
172
169
|
leftJoinLateral(field, alias, cond, schema) {
|
|
173
|
-
return this.join(field, alias, cond,
|
|
170
|
+
return this.join(field, alias, cond, JoinType.leftJoinLateral, undefined, schema);
|
|
174
171
|
}
|
|
175
|
-
joinAndSelect(field, alias, cond = {}, type =
|
|
172
|
+
joinAndSelect(field, alias, cond = {}, type = JoinType.innerJoin, path, fields, schema) {
|
|
176
173
|
if (!this._type) {
|
|
177
174
|
this.select('*');
|
|
178
175
|
}
|
|
@@ -188,7 +185,7 @@ class QueryBuilder {
|
|
|
188
185
|
this._joins[`${fromAlias}.${prop.name}#${alias}`].subquery = subquery;
|
|
189
186
|
}
|
|
190
187
|
const populate = this._joinedProps.get(fromAlias);
|
|
191
|
-
const item = { field: prop.name, strategy:
|
|
188
|
+
const item = { field: prop.name, strategy: LoadStrategy.JOINED, children: [] };
|
|
192
189
|
if (populate) {
|
|
193
190
|
populate.children.push(item);
|
|
194
191
|
}
|
|
@@ -200,16 +197,16 @@ class QueryBuilder {
|
|
|
200
197
|
return this;
|
|
201
198
|
}
|
|
202
199
|
leftJoinAndSelect(field, alias, cond = {}, fields, schema) {
|
|
203
|
-
return this.joinAndSelect(field, alias, cond,
|
|
200
|
+
return this.joinAndSelect(field, alias, cond, JoinType.leftJoin, undefined, fields, schema);
|
|
204
201
|
}
|
|
205
202
|
leftJoinLateralAndSelect(field, alias, cond = {}, fields, schema) {
|
|
206
|
-
return this.joinAndSelect(field, alias, cond,
|
|
203
|
+
return this.joinAndSelect(field, alias, cond, JoinType.leftJoinLateral, undefined, fields, schema);
|
|
207
204
|
}
|
|
208
205
|
innerJoinAndSelect(field, alias, cond = {}, fields, schema) {
|
|
209
|
-
return this.joinAndSelect(field, alias, cond,
|
|
206
|
+
return this.joinAndSelect(field, alias, cond, JoinType.innerJoin, undefined, fields, schema);
|
|
210
207
|
}
|
|
211
208
|
innerJoinLateralAndSelect(field, alias, cond = {}, fields, schema) {
|
|
212
|
-
return this.joinAndSelect(field, alias, cond,
|
|
209
|
+
return this.joinAndSelect(field, alias, cond, JoinType.innerJoinLateral, undefined, fields, schema);
|
|
213
210
|
}
|
|
214
211
|
getFieldsForJoinedLoad(prop, alias, explicitFields) {
|
|
215
212
|
const fields = [];
|
|
@@ -253,7 +250,7 @@ class QueryBuilder {
|
|
|
253
250
|
* Apply filters to the QB where condition.
|
|
254
251
|
*/
|
|
255
252
|
async applyFilters(filterOptions = {}) {
|
|
256
|
-
/*
|
|
253
|
+
/* v8 ignore next 3 */
|
|
257
254
|
if (!this.em) {
|
|
258
255
|
throw new Error('Cannot apply filters, this QueryBuilder is not attached to an EntityManager');
|
|
259
256
|
}
|
|
@@ -262,7 +259,7 @@ class QueryBuilder {
|
|
|
262
259
|
}
|
|
263
260
|
withSubQuery(subQuery, alias) {
|
|
264
261
|
this.ensureNotFinalized();
|
|
265
|
-
if (subQuery instanceof
|
|
262
|
+
if (subQuery instanceof RawQueryFragment) {
|
|
266
263
|
this.subQueries[alias] = this.platform.formatQuery(subQuery.sql, subQuery.params);
|
|
267
264
|
}
|
|
268
265
|
else {
|
|
@@ -272,34 +269,34 @@ class QueryBuilder {
|
|
|
272
269
|
}
|
|
273
270
|
where(cond, params, operator) {
|
|
274
271
|
this.ensureNotFinalized();
|
|
275
|
-
const rawField =
|
|
272
|
+
const rawField = RawQueryFragment.getKnownFragment(cond);
|
|
276
273
|
if (rawField) {
|
|
277
274
|
const sql = this.platform.formatQuery(rawField.sql, rawField.params);
|
|
278
|
-
cond = { [
|
|
275
|
+
cond = { [raw(`(${sql})`)]: Utils.asArray(params) };
|
|
279
276
|
operator ??= '$and';
|
|
280
277
|
}
|
|
281
|
-
else if (
|
|
282
|
-
cond = { [
|
|
278
|
+
else if (Utils.isString(cond)) {
|
|
279
|
+
cond = { [raw(`(${cond})`, Utils.asArray(params))]: [] };
|
|
283
280
|
operator ??= '$and';
|
|
284
281
|
}
|
|
285
282
|
else {
|
|
286
|
-
cond =
|
|
283
|
+
cond = QueryHelper.processWhere({
|
|
287
284
|
where: cond,
|
|
288
285
|
entityName: this.mainAlias.entityName,
|
|
289
286
|
metadata: this.metadata,
|
|
290
287
|
platform: this.platform,
|
|
291
288
|
aliasMap: this.getAliasMap(),
|
|
292
|
-
aliased: [
|
|
293
|
-
convertCustomTypes: this.flags.has(
|
|
289
|
+
aliased: [QueryType.SELECT, QueryType.COUNT].includes(this.type),
|
|
290
|
+
convertCustomTypes: this.flags.has(QueryFlag.CONVERT_CUSTOM_TYPES),
|
|
294
291
|
});
|
|
295
292
|
}
|
|
296
293
|
const op = operator || params;
|
|
297
|
-
const topLevel = !op || !
|
|
298
|
-
const criteriaNode =
|
|
294
|
+
const topLevel = !op || !Utils.hasObjectKeys(this._cond);
|
|
295
|
+
const criteriaNode = CriteriaNodeFactory.createNode(this.metadata, this.mainAlias.entityName, cond);
|
|
299
296
|
const ignoreBranching = this.__populateWhere === 'infer';
|
|
300
|
-
if ([
|
|
297
|
+
if ([QueryType.UPDATE, QueryType.DELETE].includes(this.type) && criteriaNode.willAutoJoin(this, undefined, { ignoreBranching })) {
|
|
301
298
|
// use sub-query to support joining
|
|
302
|
-
this.setFlag(this.type ===
|
|
299
|
+
this.setFlag(this.type === QueryType.UPDATE ? QueryFlag.UPDATE_SUB_QUERY : QueryFlag.DELETE_SUB_QUERY);
|
|
303
300
|
this.select(this.mainAlias.metadata.primaryKeys, true);
|
|
304
301
|
}
|
|
305
302
|
if (topLevel) {
|
|
@@ -327,32 +324,32 @@ class QueryBuilder {
|
|
|
327
324
|
orderBy(orderBy) {
|
|
328
325
|
this.ensureNotFinalized();
|
|
329
326
|
this._orderBy = [];
|
|
330
|
-
|
|
331
|
-
const processed =
|
|
327
|
+
Utils.asArray(orderBy).forEach(o => {
|
|
328
|
+
const processed = QueryHelper.processWhere({
|
|
332
329
|
where: o,
|
|
333
330
|
entityName: this.mainAlias.entityName,
|
|
334
331
|
metadata: this.metadata,
|
|
335
332
|
platform: this.platform,
|
|
336
333
|
aliasMap: this.getAliasMap(),
|
|
337
|
-
aliased: [
|
|
334
|
+
aliased: [QueryType.SELECT, QueryType.COUNT].includes(this.type),
|
|
338
335
|
convertCustomTypes: false,
|
|
339
336
|
type: 'orderBy',
|
|
340
337
|
});
|
|
341
|
-
this._orderBy.push(
|
|
338
|
+
this._orderBy.push(CriteriaNodeFactory.createNode(this.metadata, this.mainAlias.entityName, processed).process(this, { matchPopulateJoins: true }));
|
|
342
339
|
});
|
|
343
340
|
return this;
|
|
344
341
|
}
|
|
345
342
|
groupBy(fields) {
|
|
346
343
|
this.ensureNotFinalized();
|
|
347
|
-
this._groupBy =
|
|
344
|
+
this._groupBy = Utils.asArray(fields);
|
|
348
345
|
return this;
|
|
349
346
|
}
|
|
350
347
|
having(cond = {}, params, operator) {
|
|
351
348
|
this.ensureNotFinalized();
|
|
352
|
-
if (
|
|
353
|
-
cond = { [
|
|
349
|
+
if (Utils.isString(cond)) {
|
|
350
|
+
cond = { [raw(`(${cond})`, params)]: [] };
|
|
354
351
|
}
|
|
355
|
-
cond =
|
|
352
|
+
cond = CriteriaNodeFactory.createNode(this.metadata, this.mainAlias.entityName, cond).process(this);
|
|
356
353
|
if (!this._having || !operator) {
|
|
357
354
|
this._having = cond;
|
|
358
355
|
}
|
|
@@ -373,11 +370,11 @@ class QueryBuilder {
|
|
|
373
370
|
this.ensureNotFinalized();
|
|
374
371
|
this._onConflict ??= [];
|
|
375
372
|
this._onConflict.push({
|
|
376
|
-
fields:
|
|
373
|
+
fields: isRaw(fields)
|
|
377
374
|
? fields
|
|
378
|
-
:
|
|
375
|
+
: Utils.asArray(fields).flatMap(f => {
|
|
379
376
|
const key = f.toString();
|
|
380
|
-
/*
|
|
377
|
+
/* v8 ignore next */
|
|
381
378
|
return meta.properties[key]?.fieldNames ?? [key];
|
|
382
379
|
}),
|
|
383
380
|
});
|
|
@@ -401,7 +398,7 @@ class QueryBuilder {
|
|
|
401
398
|
return this;
|
|
402
399
|
}
|
|
403
400
|
returning(fields) {
|
|
404
|
-
this._returning =
|
|
401
|
+
this._returning = Utils.asArray(fields);
|
|
405
402
|
return this;
|
|
406
403
|
}
|
|
407
404
|
/**
|
|
@@ -434,8 +431,8 @@ class QueryBuilder {
|
|
|
434
431
|
}
|
|
435
432
|
setLockMode(mode, tables) {
|
|
436
433
|
this.ensureNotFinalized();
|
|
437
|
-
if (mode != null && mode !==
|
|
438
|
-
throw
|
|
434
|
+
if (mode != null && mode !== LockMode.OPTIMISTIC && !this.context) {
|
|
435
|
+
throw ValidationError.transactionRequired();
|
|
439
436
|
}
|
|
440
437
|
this.lockMode = mode;
|
|
441
438
|
this.lockTables = tables;
|
|
@@ -477,7 +474,7 @@ class QueryBuilder {
|
|
|
477
474
|
*/
|
|
478
475
|
comment(comment) {
|
|
479
476
|
this.ensureNotFinalized();
|
|
480
|
-
this._comments.push(...
|
|
477
|
+
this._comments.push(...Utils.asArray(comment));
|
|
481
478
|
return this;
|
|
482
479
|
}
|
|
483
480
|
/**
|
|
@@ -487,7 +484,7 @@ class QueryBuilder {
|
|
|
487
484
|
*/
|
|
488
485
|
hintComment(comment) {
|
|
489
486
|
this.ensureNotFinalized();
|
|
490
|
-
this._hintComments.push(...
|
|
487
|
+
this._hintComments.push(...Utils.asArray(comment));
|
|
491
488
|
return this;
|
|
492
489
|
}
|
|
493
490
|
from(target, aliasName) {
|
|
@@ -496,7 +493,7 @@ class QueryBuilder {
|
|
|
496
493
|
this.fromSubQuery(target, aliasName);
|
|
497
494
|
}
|
|
498
495
|
else {
|
|
499
|
-
const entityName =
|
|
496
|
+
const entityName = Utils.className(target);
|
|
500
497
|
if (aliasName && this._mainAlias && entityName !== this._mainAlias.aliasName) {
|
|
501
498
|
throw new Error(`Cannot override the alias to '${aliasName}' since a query already contains references to '${this._mainAlias.aliasName}'`);
|
|
502
499
|
}
|
|
@@ -511,22 +508,22 @@ class QueryBuilder {
|
|
|
511
508
|
this._query = {};
|
|
512
509
|
this.finalize();
|
|
513
510
|
const qb = this.getQueryBase(processVirtualEntity);
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
511
|
+
Utils.runIfNotEmpty(() => this.helper.appendQueryCondition(this.type, this._cond, qb), this._cond && !this._onConflict);
|
|
512
|
+
Utils.runIfNotEmpty(() => qb.groupBy(this.prepareFields(this._groupBy, 'groupBy')), this._groupBy);
|
|
513
|
+
Utils.runIfNotEmpty(() => this.helper.appendQueryCondition(this.type, this._having, qb, undefined, 'having'), this._having);
|
|
514
|
+
Utils.runIfNotEmpty(() => {
|
|
518
515
|
const queryOrder = this.helper.getQueryOrder(this.type, this._orderBy, this._populateMap);
|
|
519
516
|
if (queryOrder.length > 0) {
|
|
520
|
-
const sql =
|
|
517
|
+
const sql = Utils.unique(queryOrder).join(', ');
|
|
521
518
|
qb.orderBy(sql);
|
|
522
519
|
return;
|
|
523
520
|
}
|
|
524
521
|
}, this._orderBy);
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
522
|
+
Utils.runIfNotEmpty(() => qb.limit(this._limit), this._limit != null);
|
|
523
|
+
Utils.runIfNotEmpty(() => qb.offset(this._offset), this._offset);
|
|
524
|
+
Utils.runIfNotEmpty(() => qb.comment(this._comments), this._comments);
|
|
525
|
+
Utils.runIfNotEmpty(() => qb.hintComment(this._hintComments), this._hintComments);
|
|
526
|
+
Utils.runIfNotEmpty(() => this.helper.appendOnConflictClause(QueryType.UPSERT, this._onConflict, qb), this._onConflict);
|
|
530
527
|
if (this.lockMode) {
|
|
531
528
|
this.helper.getLockSQL(qb, this.lockMode, this.lockTables);
|
|
532
529
|
}
|
|
@@ -538,7 +535,7 @@ class QueryBuilder {
|
|
|
538
535
|
* @internal
|
|
539
536
|
*/
|
|
540
537
|
clearRawFragmentsCache() {
|
|
541
|
-
this.rawFragments.forEach(key =>
|
|
538
|
+
this.rawFragments.forEach(key => RawQueryFragment.remove(key));
|
|
542
539
|
this.rawFragments.clear();
|
|
543
540
|
}
|
|
544
541
|
/**
|
|
@@ -552,7 +549,7 @@ class QueryBuilder {
|
|
|
552
549
|
*/
|
|
553
550
|
toRaw() {
|
|
554
551
|
const { sql, params } = this.toQuery();
|
|
555
|
-
return
|
|
552
|
+
return raw(sql, params);
|
|
556
553
|
}
|
|
557
554
|
toQuery() {
|
|
558
555
|
if (this._query?.sql) {
|
|
@@ -640,12 +637,12 @@ class QueryBuilder {
|
|
|
640
637
|
options = typeof options === 'boolean' ? { mapResults: options } : (options ?? {});
|
|
641
638
|
options.mergeResults ??= true;
|
|
642
639
|
options.mapResults ??= true;
|
|
643
|
-
const isRunType = [
|
|
640
|
+
const isRunType = [QueryType.INSERT, QueryType.UPDATE, QueryType.DELETE, QueryType.TRUNCATE].includes(this.type);
|
|
644
641
|
method ??= isRunType ? 'run' : 'all';
|
|
645
642
|
if (!this.connectionType && isRunType) {
|
|
646
643
|
this.connectionType = 'write';
|
|
647
644
|
}
|
|
648
|
-
if (!this.finalized && method === 'get' && this.type ===
|
|
645
|
+
if (!this.finalized && method === 'get' && this.type === QueryType.SELECT) {
|
|
649
646
|
this.limit(1);
|
|
650
647
|
}
|
|
651
648
|
const query = this.toQuery();
|
|
@@ -698,14 +695,14 @@ class QueryBuilder {
|
|
|
698
695
|
const res = await this.execute('all', true);
|
|
699
696
|
const entities = [];
|
|
700
697
|
function propagatePopulateHint(entity, hint) {
|
|
701
|
-
|
|
698
|
+
helper(entity).__serializationContext.populate = hint.concat(helper(entity).__serializationContext.populate ?? []);
|
|
702
699
|
hint.forEach(hint => {
|
|
703
700
|
const [propName] = hint.field.split(':', 2);
|
|
704
|
-
const value =
|
|
705
|
-
if (
|
|
701
|
+
const value = Reference.unwrapReference(entity[propName]);
|
|
702
|
+
if (Utils.isEntity(value)) {
|
|
706
703
|
propagatePopulateHint(value, hint.children ?? []);
|
|
707
704
|
}
|
|
708
|
-
else if (
|
|
705
|
+
else if (Utils.isCollection(value)) {
|
|
709
706
|
value.populated();
|
|
710
707
|
value.getItems(false).forEach(item => propagatePopulateHint(item, hint.children ?? []));
|
|
711
708
|
}
|
|
@@ -719,7 +716,7 @@ class QueryBuilder {
|
|
|
719
716
|
break;
|
|
720
717
|
}
|
|
721
718
|
}
|
|
722
|
-
return
|
|
719
|
+
return Utils.unique(entities);
|
|
723
720
|
}
|
|
724
721
|
/**
|
|
725
722
|
* Executes the query, returning the first result or null
|
|
@@ -736,7 +733,7 @@ class QueryBuilder {
|
|
|
736
733
|
*/
|
|
737
734
|
async getCount(field, distinct) {
|
|
738
735
|
let res;
|
|
739
|
-
if (this.type ===
|
|
736
|
+
if (this.type === QueryType.COUNT) {
|
|
740
737
|
res = await this.execute('get', false);
|
|
741
738
|
}
|
|
742
739
|
else {
|
|
@@ -761,19 +758,19 @@ class QueryBuilder {
|
|
|
761
758
|
*/
|
|
762
759
|
then(onfulfilled, onrejected) {
|
|
763
760
|
let type = this.type;
|
|
764
|
-
if (this.flags.has(
|
|
765
|
-
type =
|
|
761
|
+
if (this.flags.has(QueryFlag.UPDATE_SUB_QUERY) || this.flags.has(QueryFlag.DELETE_SUB_QUERY)) {
|
|
762
|
+
type = QueryType.UPDATE;
|
|
766
763
|
}
|
|
767
764
|
switch (type) {
|
|
768
|
-
case
|
|
769
|
-
case
|
|
770
|
-
case
|
|
771
|
-
case
|
|
772
|
-
case
|
|
765
|
+
case QueryType.INSERT:
|
|
766
|
+
case QueryType.UPDATE:
|
|
767
|
+
case QueryType.DELETE:
|
|
768
|
+
case QueryType.UPSERT:
|
|
769
|
+
case QueryType.TRUNCATE:
|
|
773
770
|
return this.execute('run').then(onfulfilled, onrejected);
|
|
774
|
-
case
|
|
771
|
+
case QueryType.COUNT:
|
|
775
772
|
return this.getCount().then(onfulfilled, onrejected);
|
|
776
|
-
case
|
|
773
|
+
case QueryType.SELECT: return this.getResultList().then(onfulfilled, onrejected);
|
|
777
774
|
}
|
|
778
775
|
}
|
|
779
776
|
/**
|
|
@@ -785,7 +782,7 @@ class QueryBuilder {
|
|
|
785
782
|
if (alias.includes('.')) {
|
|
786
783
|
const [a, f] = alias.split('.');
|
|
787
784
|
const meta = this.metadata.find(a);
|
|
788
|
-
/*
|
|
785
|
+
/* v8 ignore next */
|
|
789
786
|
alias = meta?.properties[f]?.fieldNames[0] ?? alias;
|
|
790
787
|
}
|
|
791
788
|
qb.as(alias);
|
|
@@ -805,15 +802,15 @@ class QueryBuilder {
|
|
|
805
802
|
'_schema', '_indexHint', '_cache', 'subQueries', 'lockMode', 'lockTables', '_groupBy', '_having', '_returning',
|
|
806
803
|
'_comments', '_hintComments', 'rawFragments', 'aliasCounter',
|
|
807
804
|
];
|
|
808
|
-
|
|
805
|
+
RawQueryFragment.cloneRegistry = this.rawFragments;
|
|
809
806
|
for (const prop of Object.keys(this)) {
|
|
810
807
|
if (reset.includes(prop) || ['_helper', '_query'].includes(prop)) {
|
|
811
808
|
continue;
|
|
812
809
|
}
|
|
813
|
-
qb[prop] = properties.includes(prop) ?
|
|
810
|
+
qb[prop] = properties.includes(prop) ? Utils.copy(this[prop]) : this[prop];
|
|
814
811
|
}
|
|
815
|
-
delete
|
|
816
|
-
/*
|
|
812
|
+
delete RawQueryFragment.cloneRegistry;
|
|
813
|
+
/* v8 ignore next 3 */
|
|
817
814
|
if (this._fields && !reset.includes('_fields')) {
|
|
818
815
|
qb._fields = [...this._fields];
|
|
819
816
|
}
|
|
@@ -846,11 +843,11 @@ class QueryBuilder {
|
|
|
846
843
|
if (res instanceof QueryBuilder) {
|
|
847
844
|
return `(${res.getFormattedQuery()}) as ${this.platform.quoteIdentifier(this.alias)}`;
|
|
848
845
|
}
|
|
849
|
-
if (res instanceof
|
|
846
|
+
if (res instanceof RawQueryFragment) {
|
|
850
847
|
const query = this.platform.formatQuery(res.sql, res.params);
|
|
851
848
|
return `(${query}) as ${this.platform.quoteIdentifier(this.alias)}`;
|
|
852
849
|
}
|
|
853
|
-
/*
|
|
850
|
+
/* v8 ignore next */
|
|
854
851
|
return res;
|
|
855
852
|
}
|
|
856
853
|
joinReference(field, alias, cond, type, path, schema, subquery) {
|
|
@@ -858,14 +855,14 @@ class QueryBuilder {
|
|
|
858
855
|
if (typeof field === 'object') {
|
|
859
856
|
const prop = {
|
|
860
857
|
name: '__subquery__',
|
|
861
|
-
kind:
|
|
858
|
+
kind: ReferenceKind.MANY_TO_ONE,
|
|
862
859
|
};
|
|
863
860
|
if (field instanceof QueryBuilder) {
|
|
864
861
|
prop.type = field.mainAlias.entityName;
|
|
865
862
|
prop.targetMeta = field.mainAlias.metadata;
|
|
866
863
|
field = field.getNativeQuery();
|
|
867
864
|
}
|
|
868
|
-
if (field instanceof
|
|
865
|
+
if (field instanceof RawQueryFragment) {
|
|
869
866
|
field = this.platform.formatQuery(field.sql, field.params);
|
|
870
867
|
}
|
|
871
868
|
this._joins[`${this.alias}.${prop.name}#${alias}`] = {
|
|
@@ -894,22 +891,22 @@ class QueryBuilder {
|
|
|
894
891
|
throw new Error(`Trying to join ${q(field)}, but ${q(fromField)} is not a defined relation on ${meta.className}.`);
|
|
895
892
|
}
|
|
896
893
|
this.createAlias(prop.type, alias);
|
|
897
|
-
cond =
|
|
894
|
+
cond = QueryHelper.processWhere({
|
|
898
895
|
where: cond,
|
|
899
896
|
entityName: this.mainAlias.entityName,
|
|
900
897
|
metadata: this.metadata,
|
|
901
898
|
platform: this.platform,
|
|
902
899
|
aliasMap: this.getAliasMap(),
|
|
903
|
-
aliased: [
|
|
900
|
+
aliased: [QueryType.SELECT, QueryType.COUNT].includes(this.type),
|
|
904
901
|
});
|
|
905
902
|
let aliasedName = `${fromAlias}.${prop.name}#${alias}`;
|
|
906
903
|
path ??= `${(Object.values(this._joins).find(j => j.alias === fromAlias)?.path ?? entityName)}.${prop.name}`;
|
|
907
|
-
if (prop.kind ===
|
|
904
|
+
if (prop.kind === ReferenceKind.ONE_TO_MANY) {
|
|
908
905
|
this._joins[aliasedName] = this.helper.joinOneToReference(prop, fromAlias, alias, type, cond, schema);
|
|
909
906
|
}
|
|
910
|
-
else if (prop.kind ===
|
|
907
|
+
else if (prop.kind === ReferenceKind.MANY_TO_MANY) {
|
|
911
908
|
let pivotAlias = alias;
|
|
912
|
-
if (type !==
|
|
909
|
+
if (type !== JoinType.pivotJoin) {
|
|
913
910
|
const oldPivotAlias = this.getAliasForJoinPath(path + '[pivot]');
|
|
914
911
|
pivotAlias = oldPivotAlias ?? this.getNextAlias(prop.pivotEntity);
|
|
915
912
|
aliasedName = `${fromAlias}.${prop.name}#${pivotAlias}`;
|
|
@@ -918,7 +915,7 @@ class QueryBuilder {
|
|
|
918
915
|
Object.assign(this._joins, joins);
|
|
919
916
|
this.createAlias(prop.pivotEntity, pivotAlias);
|
|
920
917
|
}
|
|
921
|
-
else if (prop.kind ===
|
|
918
|
+
else if (prop.kind === ReferenceKind.ONE_TO_ONE) {
|
|
922
919
|
this._joins[aliasedName] = this.helper.joinOneToReference(prop, fromAlias, alias, type, cond, schema);
|
|
923
920
|
}
|
|
924
921
|
else { // MANY_TO_ONE
|
|
@@ -935,12 +932,12 @@ class QueryBuilder {
|
|
|
935
932
|
return this.helper.mapper(name, this.type, undefined, type === 'groupBy' ? null : undefined);
|
|
936
933
|
};
|
|
937
934
|
fields.forEach(field => {
|
|
938
|
-
const rawField =
|
|
935
|
+
const rawField = RawQueryFragment.getKnownFragment(field, false);
|
|
939
936
|
if (rawField) {
|
|
940
937
|
ret.push(rawField);
|
|
941
938
|
return;
|
|
942
939
|
}
|
|
943
|
-
if (!
|
|
940
|
+
if (!Utils.isString(field)) {
|
|
944
941
|
ret.push(field);
|
|
945
942
|
return;
|
|
946
943
|
}
|
|
@@ -951,23 +948,23 @@ class QueryBuilder {
|
|
|
951
948
|
}
|
|
952
949
|
const [a, f] = this.helper.splitField(field);
|
|
953
950
|
const prop = this.helper.getProperty(f, a);
|
|
954
|
-
/*
|
|
955
|
-
if (prop && [
|
|
951
|
+
/* v8 ignore next 3 */
|
|
952
|
+
if (prop && [ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(prop.kind)) {
|
|
956
953
|
return;
|
|
957
954
|
}
|
|
958
955
|
if (prop?.persist === false && !prop.embedded && !prop.formula && type === 'where') {
|
|
959
956
|
return;
|
|
960
957
|
}
|
|
961
|
-
if (prop?.embedded || (prop?.kind ===
|
|
958
|
+
if (prop?.embedded || (prop?.kind === ReferenceKind.EMBEDDED && prop.object)) {
|
|
962
959
|
const name = prop.embeddedPath?.join('.') ?? prop.fieldNames[0];
|
|
963
960
|
const aliased = this._aliases[a] ? `${a}.${name}` : name;
|
|
964
961
|
ret.push(getFieldName(aliased));
|
|
965
962
|
return;
|
|
966
963
|
}
|
|
967
|
-
if (prop?.kind ===
|
|
964
|
+
if (prop?.kind === ReferenceKind.EMBEDDED) {
|
|
968
965
|
const nest = (prop) => {
|
|
969
966
|
for (const childProp of Object.values(prop.embeddedProps)) {
|
|
970
|
-
if (childProp.fieldNames && (childProp.kind !==
|
|
967
|
+
if (childProp.fieldNames && (childProp.kind !== ReferenceKind.EMBEDDED || childProp.object) && childProp.persist !== false) {
|
|
971
968
|
ret.push(getFieldName(childProp.fieldNames[0]));
|
|
972
969
|
}
|
|
973
970
|
else {
|
|
@@ -985,9 +982,9 @@ class QueryBuilder {
|
|
|
985
982
|
ret.push(getFieldName(field));
|
|
986
983
|
});
|
|
987
984
|
const meta = this.mainAlias.metadata;
|
|
988
|
-
/*
|
|
985
|
+
/* v8 ignore next */
|
|
989
986
|
const requiresSQLConversion = meta?.props.filter(p => p.hasConvertToJSValueSQL && p.persist !== false) ?? [];
|
|
990
|
-
if (this.flags.has(
|
|
987
|
+
if (this.flags.has(QueryFlag.CONVERT_CUSTOM_TYPES) && (fields.includes('*') || fields.includes(`${this.mainAlias.aliasName}.*`)) && requiresSQLConversion.length > 0) {
|
|
991
988
|
for (const p of requiresSQLConversion) {
|
|
992
989
|
ret.push(this.helper.mapper(p.name, this.type));
|
|
993
990
|
}
|
|
@@ -1000,22 +997,22 @@ class QueryBuilder {
|
|
|
1000
997
|
}
|
|
1001
998
|
}
|
|
1002
999
|
}
|
|
1003
|
-
return
|
|
1000
|
+
return Utils.unique(ret);
|
|
1004
1001
|
}
|
|
1005
1002
|
init(type, data, cond) {
|
|
1006
1003
|
this.ensureNotFinalized();
|
|
1007
1004
|
this._type = type;
|
|
1008
|
-
if ([
|
|
1005
|
+
if ([QueryType.UPDATE, QueryType.DELETE].includes(type) && Utils.hasObjectKeys(this._cond)) {
|
|
1009
1006
|
throw new Error(`You are trying to call \`qb.where().${type.toLowerCase()}()\`. Calling \`qb.${type.toLowerCase()}()\` before \`qb.where()\` is required.`);
|
|
1010
1007
|
}
|
|
1011
1008
|
if (!this.helper.isTableNameAliasRequired(type)) {
|
|
1012
1009
|
delete this._fields;
|
|
1013
1010
|
}
|
|
1014
1011
|
if (data) {
|
|
1015
|
-
if (
|
|
1016
|
-
data = this.em?.getComparator().prepareEntity(data) ??
|
|
1012
|
+
if (Utils.isEntity(data)) {
|
|
1013
|
+
data = this.em?.getComparator().prepareEntity(data) ?? serialize(data);
|
|
1017
1014
|
}
|
|
1018
|
-
this._data = this.helper.processData(data, this.flags.has(
|
|
1015
|
+
this._data = this.helper.processData(data, this.flags.has(QueryFlag.CONVERT_CUSTOM_TYPES), false);
|
|
1019
1016
|
}
|
|
1020
1017
|
if (cond) {
|
|
1021
1018
|
this.where(cond);
|
|
@@ -1031,7 +1028,7 @@ class QueryBuilder {
|
|
|
1031
1028
|
const tableName = subQuery ? subQuery.as(aliasName) : this.helper.getTableName(entityName);
|
|
1032
1029
|
const joinSchema = this._schema ?? this.em?.schema ?? schema;
|
|
1033
1030
|
if (metadata?.virtual && processVirtualEntity) {
|
|
1034
|
-
qb.from(
|
|
1031
|
+
qb.from(raw(this.fromVirtual(metadata)), { indexHint: this._indexHint });
|
|
1035
1032
|
}
|
|
1036
1033
|
else {
|
|
1037
1034
|
qb.from(tableName, {
|
|
@@ -1041,34 +1038,34 @@ class QueryBuilder {
|
|
|
1041
1038
|
});
|
|
1042
1039
|
}
|
|
1043
1040
|
switch (this.type) {
|
|
1044
|
-
case
|
|
1041
|
+
case QueryType.SELECT:
|
|
1045
1042
|
qb.select(this.prepareFields(this._fields));
|
|
1046
1043
|
if (this._distinctOn) {
|
|
1047
1044
|
qb.distinctOn(this.prepareFields(this._distinctOn));
|
|
1048
1045
|
}
|
|
1049
|
-
else if (this.flags.has(
|
|
1046
|
+
else if (this.flags.has(QueryFlag.DISTINCT)) {
|
|
1050
1047
|
qb.distinct();
|
|
1051
1048
|
}
|
|
1052
1049
|
this.helper.processJoins(qb, this._joins, joinSchema);
|
|
1053
1050
|
break;
|
|
1054
|
-
case
|
|
1051
|
+
case QueryType.COUNT: {
|
|
1055
1052
|
const fields = this._fields.map(f => this.helper.mapper(f, this.type));
|
|
1056
|
-
qb.count(fields, this.flags.has(
|
|
1053
|
+
qb.count(fields, this.flags.has(QueryFlag.DISTINCT));
|
|
1057
1054
|
this.helper.processJoins(qb, this._joins, joinSchema);
|
|
1058
1055
|
break;
|
|
1059
1056
|
}
|
|
1060
|
-
case
|
|
1057
|
+
case QueryType.INSERT:
|
|
1061
1058
|
qb.insert(this._data);
|
|
1062
1059
|
break;
|
|
1063
|
-
case
|
|
1060
|
+
case QueryType.UPDATE:
|
|
1064
1061
|
qb.update(this._data);
|
|
1065
1062
|
this.helper.processJoins(qb, this._joins, joinSchema);
|
|
1066
1063
|
this.helper.updateVersionProperty(qb, this._data);
|
|
1067
1064
|
break;
|
|
1068
|
-
case
|
|
1065
|
+
case QueryType.DELETE:
|
|
1069
1066
|
qb.delete();
|
|
1070
1067
|
break;
|
|
1071
|
-
case
|
|
1068
|
+
case QueryType.TRUNCATE:
|
|
1072
1069
|
qb.truncate();
|
|
1073
1070
|
break;
|
|
1074
1071
|
}
|
|
@@ -1104,31 +1101,31 @@ class QueryBuilder {
|
|
|
1104
1101
|
this.processPopulateHint();
|
|
1105
1102
|
if (meta && (this._fields?.includes('*') || this._fields?.includes(`${this.mainAlias.aliasName}.*`))) {
|
|
1106
1103
|
meta.props
|
|
1107
|
-
.filter(prop => prop.formula && (!prop.lazy || this.flags.has(
|
|
1104
|
+
.filter(prop => prop.formula && (!prop.lazy || this.flags.has(QueryFlag.INCLUDE_LAZY_FORMULAS)))
|
|
1108
1105
|
.map(prop => {
|
|
1109
1106
|
const alias = this.platform.quoteIdentifier(this.mainAlias.aliasName);
|
|
1110
1107
|
const aliased = this.platform.quoteIdentifier(prop.fieldNames[0]);
|
|
1111
1108
|
return `${prop.formula(alias)} as ${aliased}`;
|
|
1112
1109
|
})
|
|
1113
1110
|
.filter(field => !this._fields.some(f => {
|
|
1114
|
-
if (f instanceof
|
|
1111
|
+
if (f instanceof RawQueryFragment) {
|
|
1115
1112
|
return f.sql === field && f.params.length === 0;
|
|
1116
1113
|
}
|
|
1117
1114
|
return f === field;
|
|
1118
1115
|
}))
|
|
1119
|
-
.forEach(field => this._fields.push(
|
|
1116
|
+
.forEach(field => this._fields.push(raw(field)));
|
|
1120
1117
|
}
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1118
|
+
QueryHelper.processObjectParams(this._data);
|
|
1119
|
+
QueryHelper.processObjectParams(this._cond);
|
|
1120
|
+
QueryHelper.processObjectParams(this._having);
|
|
1124
1121
|
// automatically enable paginate flag when we detect to-many joins, but only if there is no `group by` clause
|
|
1125
|
-
if (!this.flags.has(
|
|
1126
|
-
this.flags.add(
|
|
1122
|
+
if (!this.flags.has(QueryFlag.DISABLE_PAGINATE) && this._groupBy.length === 0 && this.hasToManyJoins()) {
|
|
1123
|
+
this.flags.add(QueryFlag.PAGINATE);
|
|
1127
1124
|
}
|
|
1128
|
-
if (meta && this.flags.has(
|
|
1125
|
+
if (meta && this.flags.has(QueryFlag.PAGINATE) && (this._limit > 0 || this._offset > 0)) {
|
|
1129
1126
|
this.wrapPaginateSubQuery(meta);
|
|
1130
1127
|
}
|
|
1131
|
-
if (meta && (this.flags.has(
|
|
1128
|
+
if (meta && (this.flags.has(QueryFlag.UPDATE_SUB_QUERY) || this.flags.has(QueryFlag.DELETE_SUB_QUERY))) {
|
|
1132
1129
|
this.wrapModifySubQuery(meta);
|
|
1133
1130
|
}
|
|
1134
1131
|
this.finalized = true;
|
|
@@ -1139,10 +1136,10 @@ class QueryBuilder {
|
|
|
1139
1136
|
return;
|
|
1140
1137
|
}
|
|
1141
1138
|
const meta = this.mainAlias.metadata;
|
|
1142
|
-
if (meta && this.flags.has(
|
|
1139
|
+
if (meta && this.flags.has(QueryFlag.AUTO_JOIN_ONE_TO_ONE_OWNER)) {
|
|
1143
1140
|
const relationsToPopulate = this._populate.map(({ field }) => field);
|
|
1144
1141
|
meta.relations
|
|
1145
|
-
.filter(prop => prop.kind ===
|
|
1142
|
+
.filter(prop => prop.kind === ReferenceKind.ONE_TO_ONE && !prop.owner && !relationsToPopulate.includes(prop.name) && !relationsToPopulate.includes(`${prop.name}:ref`))
|
|
1146
1143
|
.map(prop => ({ field: `${prop.name}:ref` }))
|
|
1147
1144
|
.forEach(item => this._populate.push(item));
|
|
1148
1145
|
}
|
|
@@ -1158,7 +1155,7 @@ class QueryBuilder {
|
|
|
1158
1155
|
const prop = meta.properties[fromField];
|
|
1159
1156
|
const alias = this.getNextAlias(prop.pivotEntity ?? prop.type);
|
|
1160
1157
|
const aliasedName = `${fromAlias}.${prop.name}#${alias}`;
|
|
1161
|
-
this._joins[aliasedName] = this.helper.joinOneToReference(prop, this.mainAlias.aliasName, alias,
|
|
1158
|
+
this._joins[aliasedName] = this.helper.joinOneToReference(prop, this.mainAlias.aliasName, alias, JoinType.leftJoin);
|
|
1162
1159
|
this._joins[aliasedName].path = `${(Object.values(this._joins).find(j => j.alias === fromAlias)?.path ?? meta.className)}.${prop.name}`;
|
|
1163
1160
|
this._populateMap[aliasedName] = this._joins[aliasedName].alias;
|
|
1164
1161
|
}
|
|
@@ -1169,7 +1166,7 @@ class QueryBuilder {
|
|
|
1169
1166
|
}
|
|
1170
1167
|
processPopulateWhere(filter) {
|
|
1171
1168
|
const key = filter ? '_populateFilter' : '_populateWhere';
|
|
1172
|
-
if (this[key] == null || this[key] ===
|
|
1169
|
+
if (this[key] == null || this[key] === PopulateHint.ALL) {
|
|
1173
1170
|
return;
|
|
1174
1171
|
}
|
|
1175
1172
|
let joins = Object.values(this._joins);
|
|
@@ -1178,7 +1175,7 @@ class QueryBuilder {
|
|
|
1178
1175
|
join.cond = filter ? { ...join.cond } : {};
|
|
1179
1176
|
}
|
|
1180
1177
|
if (typeof this[key] === 'object') {
|
|
1181
|
-
const cond =
|
|
1178
|
+
const cond = CriteriaNodeFactory
|
|
1182
1179
|
.createNode(this.metadata, this.mainAlias.entityName, this[key])
|
|
1183
1180
|
.process(this, { matchPopulateJoins: true, ignoreBranching: true, preferNoBranch: true });
|
|
1184
1181
|
// there might be new joins created by processing the `populateWhere` object
|
|
@@ -1188,11 +1185,11 @@ class QueryBuilder {
|
|
|
1188
1185
|
}
|
|
1189
1186
|
mergeOnConditions(joins, cond, filter, op) {
|
|
1190
1187
|
for (const k of Object.keys(cond)) {
|
|
1191
|
-
if (
|
|
1188
|
+
if (Utils.isOperator(k)) {
|
|
1192
1189
|
if (Array.isArray(cond[k])) {
|
|
1193
1190
|
cond[k].forEach((c) => this.mergeOnConditions(joins, c, filter, k));
|
|
1194
1191
|
}
|
|
1195
|
-
/*
|
|
1192
|
+
/* v8 ignore next */
|
|
1196
1193
|
this.mergeOnConditions(joins, cond[k], filter, k);
|
|
1197
1194
|
}
|
|
1198
1195
|
const [alias] = this.helper.splitField(k);
|
|
@@ -1202,13 +1199,13 @@ class QueryBuilder {
|
|
|
1202
1199
|
// https://stackoverflow.com/a/56815807/3665878
|
|
1203
1200
|
if (parentJoin && !filter) {
|
|
1204
1201
|
const nested = (parentJoin.nested ??= new Set());
|
|
1205
|
-
join.type = join.type ===
|
|
1206
|
-
?
|
|
1207
|
-
:
|
|
1202
|
+
join.type = join.type === JoinType.innerJoin || ([ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(parentJoin.prop.kind))
|
|
1203
|
+
? JoinType.nestedInnerJoin
|
|
1204
|
+
: JoinType.nestedLeftJoin;
|
|
1208
1205
|
nested.add(join);
|
|
1209
1206
|
}
|
|
1210
1207
|
if (join.cond[k]) {
|
|
1211
|
-
/*
|
|
1208
|
+
/* v8 ignore next */
|
|
1212
1209
|
join.cond = { [op ?? '$and']: [join.cond, { [k]: cond[k] }] };
|
|
1213
1210
|
}
|
|
1214
1211
|
else if (op === '$or') {
|
|
@@ -1225,7 +1222,7 @@ class QueryBuilder {
|
|
|
1225
1222
|
// console.log(this._joins);
|
|
1226
1223
|
return Object.values(this._joins).some(join => {
|
|
1227
1224
|
// console.log(join.prop.name, join.prop.kind, [ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(join.prop.kind));
|
|
1228
|
-
return [
|
|
1225
|
+
return [ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(join.prop.kind);
|
|
1229
1226
|
});
|
|
1230
1227
|
}
|
|
1231
1228
|
wrapPaginateSubQuery(meta) {
|
|
@@ -1245,8 +1242,8 @@ class QueryBuilder {
|
|
|
1245
1242
|
const orderBy = [];
|
|
1246
1243
|
for (const orderMap of this._orderBy) {
|
|
1247
1244
|
for (const [field, direction] of Object.entries(orderMap)) {
|
|
1248
|
-
if (
|
|
1249
|
-
const rawField =
|
|
1245
|
+
if (RawQueryFragment.isKnownFragment(field)) {
|
|
1246
|
+
const rawField = RawQueryFragment.getKnownFragment(field, false);
|
|
1250
1247
|
this.rawFragments.add(field);
|
|
1251
1248
|
orderBy.push({ [rawField.clone()]: direction });
|
|
1252
1249
|
continue;
|
|
@@ -1259,7 +1256,7 @@ class QueryBuilder {
|
|
|
1259
1256
|
addToSelect.push(fieldName);
|
|
1260
1257
|
}
|
|
1261
1258
|
const quoted = this.platform.quoteIdentifier(fieldName);
|
|
1262
|
-
const key =
|
|
1259
|
+
const key = raw(`min(${quoted}${type})`);
|
|
1263
1260
|
orderBy.push({ [key]: direction });
|
|
1264
1261
|
}
|
|
1265
1262
|
}
|
|
@@ -1273,17 +1270,17 @@ class QueryBuilder {
|
|
|
1273
1270
|
if (typeof field === 'object' && field && '__as' in field) {
|
|
1274
1271
|
return field.__as === prop;
|
|
1275
1272
|
}
|
|
1276
|
-
if (field instanceof
|
|
1273
|
+
if (field instanceof RawQueryFragment) {
|
|
1277
1274
|
// not perfect, but should work most of the time, ideally we should check only the alias (`... as alias`)
|
|
1278
1275
|
return field.sql.includes(prop);
|
|
1279
1276
|
}
|
|
1280
1277
|
return false;
|
|
1281
1278
|
});
|
|
1282
|
-
/*
|
|
1283
|
-
if (field instanceof
|
|
1279
|
+
/* v8 ignore next 3 */
|
|
1280
|
+
if (field instanceof RawQueryFragment) {
|
|
1284
1281
|
innerQuery.select(field);
|
|
1285
1282
|
}
|
|
1286
|
-
else if (field instanceof
|
|
1283
|
+
else if (field instanceof NativeQueryBuilder) {
|
|
1287
1284
|
innerQuery.select(field.toRaw());
|
|
1288
1285
|
}
|
|
1289
1286
|
else if (field) {
|
|
@@ -1297,11 +1294,11 @@ class QueryBuilder {
|
|
|
1297
1294
|
subSubQuery.select(pks).from(innerQuery);
|
|
1298
1295
|
this._limit = undefined;
|
|
1299
1296
|
this._offset = undefined;
|
|
1300
|
-
if (!this._fields.some(f =>
|
|
1297
|
+
if (!this._fields.some(f => RawQueryFragment.isKnownFragment(f))) {
|
|
1301
1298
|
this.pruneExtraJoins(meta);
|
|
1302
1299
|
}
|
|
1303
1300
|
const { sql, params } = subSubQuery.compile();
|
|
1304
|
-
this.select(this._fields).where({ [
|
|
1301
|
+
this.select(this._fields).where({ [Utils.getPrimaryKeyHash(meta.primaryKeys)]: { $in: raw(sql, params) } });
|
|
1305
1302
|
}
|
|
1306
1303
|
pruneExtraJoins(meta) {
|
|
1307
1304
|
// remove joins that are not used for population or ordering to improve performance
|
|
@@ -1344,14 +1341,14 @@ class QueryBuilder {
|
|
|
1344
1341
|
// wrap one more time to get around MySQL limitations
|
|
1345
1342
|
// https://stackoverflow.com/questions/45494/mysql-error-1093-cant-specify-target-table-for-update-in-from-clause
|
|
1346
1343
|
const subSubQuery = this.platform.createNativeQueryBuilder();
|
|
1347
|
-
const method = this.flags.has(
|
|
1344
|
+
const method = this.flags.has(QueryFlag.UPDATE_SUB_QUERY) ? 'update' : 'delete';
|
|
1348
1345
|
const pks = this.prepareFields(meta.primaryKeys, 'sub-query');
|
|
1349
1346
|
this._cond = {}; // otherwise we would trigger validation error
|
|
1350
1347
|
this._joins = {}; // included in the subquery
|
|
1351
1348
|
subSubQuery.select(pks).from(subQuery.as(this.mainAlias.aliasName));
|
|
1352
1349
|
const { sql, params } = subSubQuery.compile();
|
|
1353
1350
|
this[method](this._data).where({
|
|
1354
|
-
[
|
|
1351
|
+
[Utils.getPrimaryKeyHash(meta.primaryKeys)]: { $in: raw(sql, params) },
|
|
1355
1352
|
});
|
|
1356
1353
|
}
|
|
1357
1354
|
getSchema(alias) {
|
|
@@ -1385,10 +1382,10 @@ class QueryBuilder {
|
|
|
1385
1382
|
this.createMainAlias(entityName, aliasName);
|
|
1386
1383
|
}
|
|
1387
1384
|
createQueryBuilderHelper() {
|
|
1388
|
-
return new
|
|
1385
|
+
return new QueryBuilderHelper(this.mainAlias.entityName, this.mainAlias.aliasName, this._aliases, this.subQueries, this.driver);
|
|
1389
1386
|
}
|
|
1390
1387
|
ensureFromClause() {
|
|
1391
|
-
/*
|
|
1388
|
+
/* v8 ignore next 3 */
|
|
1392
1389
|
if (!this._mainAlias) {
|
|
1393
1390
|
throw new Error(`Cannot proceed to build a query because the main alias is not set.`);
|
|
1394
1391
|
}
|
|
@@ -1398,9 +1395,9 @@ class QueryBuilder {
|
|
|
1398
1395
|
throw new Error('This QueryBuilder instance is already finalized, clone it first if you want to modify it.');
|
|
1399
1396
|
}
|
|
1400
1397
|
}
|
|
1401
|
-
/*
|
|
1398
|
+
/* v8 ignore start */
|
|
1402
1399
|
/** @ignore */
|
|
1403
|
-
[
|
|
1400
|
+
[inspect.custom](depth = 2) {
|
|
1404
1401
|
const object = { ...this };
|
|
1405
1402
|
const hidden = ['metadata', 'driver', 'context', 'platform', 'type'];
|
|
1406
1403
|
Object.keys(object).filter(k => k.startsWith('_')).forEach(k => delete object[k]);
|
|
@@ -1413,19 +1410,18 @@ class QueryBuilder {
|
|
|
1413
1410
|
if (this._schema) {
|
|
1414
1411
|
object.schema = this._schema;
|
|
1415
1412
|
}
|
|
1416
|
-
if (!
|
|
1413
|
+
if (!Utils.isEmpty(this._cond)) {
|
|
1417
1414
|
object.where = this._cond;
|
|
1418
1415
|
}
|
|
1419
1416
|
if (this._onConflict?.[0]) {
|
|
1420
1417
|
prefix = 'Upsert';
|
|
1421
1418
|
object.onConflict = this._onConflict[0];
|
|
1422
1419
|
}
|
|
1423
|
-
if (!
|
|
1420
|
+
if (!Utils.isEmpty(this._orderBy)) {
|
|
1424
1421
|
object.orderBy = this._orderBy;
|
|
1425
1422
|
}
|
|
1426
1423
|
const name = this._mainAlias ? `${prefix}QueryBuilder<${this._mainAlias?.entityName}>` : 'QueryBuilder';
|
|
1427
|
-
const ret =
|
|
1424
|
+
const ret = inspect(object, { depth });
|
|
1428
1425
|
return ret === '[Object]' ? `[${name}]` : name + ' ' + ret;
|
|
1429
1426
|
}
|
|
1430
1427
|
}
|
|
1431
|
-
exports.QueryBuilder = QueryBuilder;
|