@mikro-orm/knex 7.0.0-dev.1 → 7.0.0-dev.3
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 -14
- package/query/QueryBuilder.js +163 -187
- 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 +20 -34
- 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 {
|
|
@@ -756,26 +753,6 @@ class QueryBuilder {
|
|
|
756
753
|
await this.clone().getCount(),
|
|
757
754
|
];
|
|
758
755
|
}
|
|
759
|
-
/**
|
|
760
|
-
* Provides promise-like interface so we can await the QB instance.
|
|
761
|
-
*/
|
|
762
|
-
then(onfulfilled, onrejected) {
|
|
763
|
-
let type = this.type;
|
|
764
|
-
if (this.flags.has(core_1.QueryFlag.UPDATE_SUB_QUERY) || this.flags.has(core_1.QueryFlag.DELETE_SUB_QUERY)) {
|
|
765
|
-
type = enums_1.QueryType.UPDATE;
|
|
766
|
-
}
|
|
767
|
-
switch (type) {
|
|
768
|
-
case enums_1.QueryType.INSERT:
|
|
769
|
-
case enums_1.QueryType.UPDATE:
|
|
770
|
-
case enums_1.QueryType.DELETE:
|
|
771
|
-
case enums_1.QueryType.UPSERT:
|
|
772
|
-
case enums_1.QueryType.TRUNCATE:
|
|
773
|
-
return this.execute('run').then(onfulfilled, onrejected);
|
|
774
|
-
case enums_1.QueryType.COUNT:
|
|
775
|
-
return this.getCount().then(onfulfilled, onrejected);
|
|
776
|
-
case enums_1.QueryType.SELECT: return this.getResultList().then(onfulfilled, onrejected);
|
|
777
|
-
}
|
|
778
|
-
}
|
|
779
756
|
/**
|
|
780
757
|
* Returns native query builder instance with sub-query aliased with given alias.
|
|
781
758
|
* You can provide `EntityName.propName` as alias, then the field name will be used based on the metadata
|
|
@@ -785,7 +762,7 @@ class QueryBuilder {
|
|
|
785
762
|
if (alias.includes('.')) {
|
|
786
763
|
const [a, f] = alias.split('.');
|
|
787
764
|
const meta = this.metadata.find(a);
|
|
788
|
-
/*
|
|
765
|
+
/* v8 ignore next */
|
|
789
766
|
alias = meta?.properties[f]?.fieldNames[0] ?? alias;
|
|
790
767
|
}
|
|
791
768
|
qb.as(alias);
|
|
@@ -805,15 +782,15 @@ class QueryBuilder {
|
|
|
805
782
|
'_schema', '_indexHint', '_cache', 'subQueries', 'lockMode', 'lockTables', '_groupBy', '_having', '_returning',
|
|
806
783
|
'_comments', '_hintComments', 'rawFragments', 'aliasCounter',
|
|
807
784
|
];
|
|
808
|
-
|
|
785
|
+
RawQueryFragment.cloneRegistry = this.rawFragments;
|
|
809
786
|
for (const prop of Object.keys(this)) {
|
|
810
787
|
if (reset.includes(prop) || ['_helper', '_query'].includes(prop)) {
|
|
811
788
|
continue;
|
|
812
789
|
}
|
|
813
|
-
qb[prop] = properties.includes(prop) ?
|
|
790
|
+
qb[prop] = properties.includes(prop) ? Utils.copy(this[prop]) : this[prop];
|
|
814
791
|
}
|
|
815
|
-
delete
|
|
816
|
-
/*
|
|
792
|
+
delete RawQueryFragment.cloneRegistry;
|
|
793
|
+
/* v8 ignore next 3 */
|
|
817
794
|
if (this._fields && !reset.includes('_fields')) {
|
|
818
795
|
qb._fields = [...this._fields];
|
|
819
796
|
}
|
|
@@ -846,11 +823,11 @@ class QueryBuilder {
|
|
|
846
823
|
if (res instanceof QueryBuilder) {
|
|
847
824
|
return `(${res.getFormattedQuery()}) as ${this.platform.quoteIdentifier(this.alias)}`;
|
|
848
825
|
}
|
|
849
|
-
if (res instanceof
|
|
826
|
+
if (res instanceof RawQueryFragment) {
|
|
850
827
|
const query = this.platform.formatQuery(res.sql, res.params);
|
|
851
828
|
return `(${query}) as ${this.platform.quoteIdentifier(this.alias)}`;
|
|
852
829
|
}
|
|
853
|
-
/*
|
|
830
|
+
/* v8 ignore next */
|
|
854
831
|
return res;
|
|
855
832
|
}
|
|
856
833
|
joinReference(field, alias, cond, type, path, schema, subquery) {
|
|
@@ -858,14 +835,14 @@ class QueryBuilder {
|
|
|
858
835
|
if (typeof field === 'object') {
|
|
859
836
|
const prop = {
|
|
860
837
|
name: '__subquery__',
|
|
861
|
-
kind:
|
|
838
|
+
kind: ReferenceKind.MANY_TO_ONE,
|
|
862
839
|
};
|
|
863
840
|
if (field instanceof QueryBuilder) {
|
|
864
841
|
prop.type = field.mainAlias.entityName;
|
|
865
842
|
prop.targetMeta = field.mainAlias.metadata;
|
|
866
843
|
field = field.getNativeQuery();
|
|
867
844
|
}
|
|
868
|
-
if (field instanceof
|
|
845
|
+
if (field instanceof RawQueryFragment) {
|
|
869
846
|
field = this.platform.formatQuery(field.sql, field.params);
|
|
870
847
|
}
|
|
871
848
|
this._joins[`${this.alias}.${prop.name}#${alias}`] = {
|
|
@@ -894,22 +871,22 @@ class QueryBuilder {
|
|
|
894
871
|
throw new Error(`Trying to join ${q(field)}, but ${q(fromField)} is not a defined relation on ${meta.className}.`);
|
|
895
872
|
}
|
|
896
873
|
this.createAlias(prop.type, alias);
|
|
897
|
-
cond =
|
|
874
|
+
cond = QueryHelper.processWhere({
|
|
898
875
|
where: cond,
|
|
899
876
|
entityName: this.mainAlias.entityName,
|
|
900
877
|
metadata: this.metadata,
|
|
901
878
|
platform: this.platform,
|
|
902
879
|
aliasMap: this.getAliasMap(),
|
|
903
|
-
aliased: [
|
|
880
|
+
aliased: [QueryType.SELECT, QueryType.COUNT].includes(this.type),
|
|
904
881
|
});
|
|
905
882
|
let aliasedName = `${fromAlias}.${prop.name}#${alias}`;
|
|
906
883
|
path ??= `${(Object.values(this._joins).find(j => j.alias === fromAlias)?.path ?? entityName)}.${prop.name}`;
|
|
907
|
-
if (prop.kind ===
|
|
884
|
+
if (prop.kind === ReferenceKind.ONE_TO_MANY) {
|
|
908
885
|
this._joins[aliasedName] = this.helper.joinOneToReference(prop, fromAlias, alias, type, cond, schema);
|
|
909
886
|
}
|
|
910
|
-
else if (prop.kind ===
|
|
887
|
+
else if (prop.kind === ReferenceKind.MANY_TO_MANY) {
|
|
911
888
|
let pivotAlias = alias;
|
|
912
|
-
if (type !==
|
|
889
|
+
if (type !== JoinType.pivotJoin) {
|
|
913
890
|
const oldPivotAlias = this.getAliasForJoinPath(path + '[pivot]');
|
|
914
891
|
pivotAlias = oldPivotAlias ?? this.getNextAlias(prop.pivotEntity);
|
|
915
892
|
aliasedName = `${fromAlias}.${prop.name}#${pivotAlias}`;
|
|
@@ -918,7 +895,7 @@ class QueryBuilder {
|
|
|
918
895
|
Object.assign(this._joins, joins);
|
|
919
896
|
this.createAlias(prop.pivotEntity, pivotAlias);
|
|
920
897
|
}
|
|
921
|
-
else if (prop.kind ===
|
|
898
|
+
else if (prop.kind === ReferenceKind.ONE_TO_ONE) {
|
|
922
899
|
this._joins[aliasedName] = this.helper.joinOneToReference(prop, fromAlias, alias, type, cond, schema);
|
|
923
900
|
}
|
|
924
901
|
else { // MANY_TO_ONE
|
|
@@ -935,12 +912,12 @@ class QueryBuilder {
|
|
|
935
912
|
return this.helper.mapper(name, this.type, undefined, type === 'groupBy' ? null : undefined);
|
|
936
913
|
};
|
|
937
914
|
fields.forEach(field => {
|
|
938
|
-
const rawField =
|
|
915
|
+
const rawField = RawQueryFragment.getKnownFragment(field, false);
|
|
939
916
|
if (rawField) {
|
|
940
917
|
ret.push(rawField);
|
|
941
918
|
return;
|
|
942
919
|
}
|
|
943
|
-
if (!
|
|
920
|
+
if (!Utils.isString(field)) {
|
|
944
921
|
ret.push(field);
|
|
945
922
|
return;
|
|
946
923
|
}
|
|
@@ -951,23 +928,23 @@ class QueryBuilder {
|
|
|
951
928
|
}
|
|
952
929
|
const [a, f] = this.helper.splitField(field);
|
|
953
930
|
const prop = this.helper.getProperty(f, a);
|
|
954
|
-
/*
|
|
955
|
-
if (prop && [
|
|
931
|
+
/* v8 ignore next 3 */
|
|
932
|
+
if (prop && [ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(prop.kind)) {
|
|
956
933
|
return;
|
|
957
934
|
}
|
|
958
935
|
if (prop?.persist === false && !prop.embedded && !prop.formula && type === 'where') {
|
|
959
936
|
return;
|
|
960
937
|
}
|
|
961
|
-
if (prop?.embedded || (prop?.kind ===
|
|
938
|
+
if (prop?.embedded || (prop?.kind === ReferenceKind.EMBEDDED && prop.object)) {
|
|
962
939
|
const name = prop.embeddedPath?.join('.') ?? prop.fieldNames[0];
|
|
963
940
|
const aliased = this._aliases[a] ? `${a}.${name}` : name;
|
|
964
941
|
ret.push(getFieldName(aliased));
|
|
965
942
|
return;
|
|
966
943
|
}
|
|
967
|
-
if (prop?.kind ===
|
|
944
|
+
if (prop?.kind === ReferenceKind.EMBEDDED) {
|
|
968
945
|
const nest = (prop) => {
|
|
969
946
|
for (const childProp of Object.values(prop.embeddedProps)) {
|
|
970
|
-
if (childProp.fieldNames && (childProp.kind !==
|
|
947
|
+
if (childProp.fieldNames && (childProp.kind !== ReferenceKind.EMBEDDED || childProp.object) && childProp.persist !== false) {
|
|
971
948
|
ret.push(getFieldName(childProp.fieldNames[0]));
|
|
972
949
|
}
|
|
973
950
|
else {
|
|
@@ -985,9 +962,9 @@ class QueryBuilder {
|
|
|
985
962
|
ret.push(getFieldName(field));
|
|
986
963
|
});
|
|
987
964
|
const meta = this.mainAlias.metadata;
|
|
988
|
-
/*
|
|
965
|
+
/* v8 ignore next */
|
|
989
966
|
const requiresSQLConversion = meta?.props.filter(p => p.hasConvertToJSValueSQL && p.persist !== false) ?? [];
|
|
990
|
-
if (this.flags.has(
|
|
967
|
+
if (this.flags.has(QueryFlag.CONVERT_CUSTOM_TYPES) && (fields.includes('*') || fields.includes(`${this.mainAlias.aliasName}.*`)) && requiresSQLConversion.length > 0) {
|
|
991
968
|
for (const p of requiresSQLConversion) {
|
|
992
969
|
ret.push(this.helper.mapper(p.name, this.type));
|
|
993
970
|
}
|
|
@@ -1000,22 +977,22 @@ class QueryBuilder {
|
|
|
1000
977
|
}
|
|
1001
978
|
}
|
|
1002
979
|
}
|
|
1003
|
-
return
|
|
980
|
+
return Utils.unique(ret);
|
|
1004
981
|
}
|
|
1005
982
|
init(type, data, cond) {
|
|
1006
983
|
this.ensureNotFinalized();
|
|
1007
984
|
this._type = type;
|
|
1008
|
-
if ([
|
|
985
|
+
if ([QueryType.UPDATE, QueryType.DELETE].includes(type) && Utils.hasObjectKeys(this._cond)) {
|
|
1009
986
|
throw new Error(`You are trying to call \`qb.where().${type.toLowerCase()}()\`. Calling \`qb.${type.toLowerCase()}()\` before \`qb.where()\` is required.`);
|
|
1010
987
|
}
|
|
1011
988
|
if (!this.helper.isTableNameAliasRequired(type)) {
|
|
1012
989
|
delete this._fields;
|
|
1013
990
|
}
|
|
1014
991
|
if (data) {
|
|
1015
|
-
if (
|
|
1016
|
-
data = this.em?.getComparator().prepareEntity(data) ??
|
|
992
|
+
if (Utils.isEntity(data)) {
|
|
993
|
+
data = this.em?.getComparator().prepareEntity(data) ?? serialize(data);
|
|
1017
994
|
}
|
|
1018
|
-
this._data = this.helper.processData(data, this.flags.has(
|
|
995
|
+
this._data = this.helper.processData(data, this.flags.has(QueryFlag.CONVERT_CUSTOM_TYPES), false);
|
|
1019
996
|
}
|
|
1020
997
|
if (cond) {
|
|
1021
998
|
this.where(cond);
|
|
@@ -1031,7 +1008,7 @@ class QueryBuilder {
|
|
|
1031
1008
|
const tableName = subQuery ? subQuery.as(aliasName) : this.helper.getTableName(entityName);
|
|
1032
1009
|
const joinSchema = this._schema ?? this.em?.schema ?? schema;
|
|
1033
1010
|
if (metadata?.virtual && processVirtualEntity) {
|
|
1034
|
-
qb.from(
|
|
1011
|
+
qb.from(raw(this.fromVirtual(metadata)), { indexHint: this._indexHint });
|
|
1035
1012
|
}
|
|
1036
1013
|
else {
|
|
1037
1014
|
qb.from(tableName, {
|
|
@@ -1041,34 +1018,34 @@ class QueryBuilder {
|
|
|
1041
1018
|
});
|
|
1042
1019
|
}
|
|
1043
1020
|
switch (this.type) {
|
|
1044
|
-
case
|
|
1021
|
+
case QueryType.SELECT:
|
|
1045
1022
|
qb.select(this.prepareFields(this._fields));
|
|
1046
1023
|
if (this._distinctOn) {
|
|
1047
1024
|
qb.distinctOn(this.prepareFields(this._distinctOn));
|
|
1048
1025
|
}
|
|
1049
|
-
else if (this.flags.has(
|
|
1026
|
+
else if (this.flags.has(QueryFlag.DISTINCT)) {
|
|
1050
1027
|
qb.distinct();
|
|
1051
1028
|
}
|
|
1052
1029
|
this.helper.processJoins(qb, this._joins, joinSchema);
|
|
1053
1030
|
break;
|
|
1054
|
-
case
|
|
1031
|
+
case QueryType.COUNT: {
|
|
1055
1032
|
const fields = this._fields.map(f => this.helper.mapper(f, this.type));
|
|
1056
|
-
qb.count(fields, this.flags.has(
|
|
1033
|
+
qb.count(fields, this.flags.has(QueryFlag.DISTINCT));
|
|
1057
1034
|
this.helper.processJoins(qb, this._joins, joinSchema);
|
|
1058
1035
|
break;
|
|
1059
1036
|
}
|
|
1060
|
-
case
|
|
1037
|
+
case QueryType.INSERT:
|
|
1061
1038
|
qb.insert(this._data);
|
|
1062
1039
|
break;
|
|
1063
|
-
case
|
|
1040
|
+
case QueryType.UPDATE:
|
|
1064
1041
|
qb.update(this._data);
|
|
1065
1042
|
this.helper.processJoins(qb, this._joins, joinSchema);
|
|
1066
1043
|
this.helper.updateVersionProperty(qb, this._data);
|
|
1067
1044
|
break;
|
|
1068
|
-
case
|
|
1045
|
+
case QueryType.DELETE:
|
|
1069
1046
|
qb.delete();
|
|
1070
1047
|
break;
|
|
1071
|
-
case
|
|
1048
|
+
case QueryType.TRUNCATE:
|
|
1072
1049
|
qb.truncate();
|
|
1073
1050
|
break;
|
|
1074
1051
|
}
|
|
@@ -1104,31 +1081,31 @@ class QueryBuilder {
|
|
|
1104
1081
|
this.processPopulateHint();
|
|
1105
1082
|
if (meta && (this._fields?.includes('*') || this._fields?.includes(`${this.mainAlias.aliasName}.*`))) {
|
|
1106
1083
|
meta.props
|
|
1107
|
-
.filter(prop => prop.formula && (!prop.lazy || this.flags.has(
|
|
1084
|
+
.filter(prop => prop.formula && (!prop.lazy || this.flags.has(QueryFlag.INCLUDE_LAZY_FORMULAS)))
|
|
1108
1085
|
.map(prop => {
|
|
1109
1086
|
const alias = this.platform.quoteIdentifier(this.mainAlias.aliasName);
|
|
1110
1087
|
const aliased = this.platform.quoteIdentifier(prop.fieldNames[0]);
|
|
1111
1088
|
return `${prop.formula(alias)} as ${aliased}`;
|
|
1112
1089
|
})
|
|
1113
1090
|
.filter(field => !this._fields.some(f => {
|
|
1114
|
-
if (f instanceof
|
|
1091
|
+
if (f instanceof RawQueryFragment) {
|
|
1115
1092
|
return f.sql === field && f.params.length === 0;
|
|
1116
1093
|
}
|
|
1117
1094
|
return f === field;
|
|
1118
1095
|
}))
|
|
1119
|
-
.forEach(field => this._fields.push(
|
|
1096
|
+
.forEach(field => this._fields.push(raw(field)));
|
|
1120
1097
|
}
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1098
|
+
QueryHelper.processObjectParams(this._data);
|
|
1099
|
+
QueryHelper.processObjectParams(this._cond);
|
|
1100
|
+
QueryHelper.processObjectParams(this._having);
|
|
1124
1101
|
// 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(
|
|
1102
|
+
if (!this.flags.has(QueryFlag.DISABLE_PAGINATE) && this._groupBy.length === 0 && this.hasToManyJoins()) {
|
|
1103
|
+
this.flags.add(QueryFlag.PAGINATE);
|
|
1127
1104
|
}
|
|
1128
|
-
if (meta && this.flags.has(
|
|
1105
|
+
if (meta && this.flags.has(QueryFlag.PAGINATE) && (this._limit > 0 || this._offset > 0)) {
|
|
1129
1106
|
this.wrapPaginateSubQuery(meta);
|
|
1130
1107
|
}
|
|
1131
|
-
if (meta && (this.flags.has(
|
|
1108
|
+
if (meta && (this.flags.has(QueryFlag.UPDATE_SUB_QUERY) || this.flags.has(QueryFlag.DELETE_SUB_QUERY))) {
|
|
1132
1109
|
this.wrapModifySubQuery(meta);
|
|
1133
1110
|
}
|
|
1134
1111
|
this.finalized = true;
|
|
@@ -1139,10 +1116,10 @@ class QueryBuilder {
|
|
|
1139
1116
|
return;
|
|
1140
1117
|
}
|
|
1141
1118
|
const meta = this.mainAlias.metadata;
|
|
1142
|
-
if (meta && this.flags.has(
|
|
1119
|
+
if (meta && this.flags.has(QueryFlag.AUTO_JOIN_ONE_TO_ONE_OWNER)) {
|
|
1143
1120
|
const relationsToPopulate = this._populate.map(({ field }) => field);
|
|
1144
1121
|
meta.relations
|
|
1145
|
-
.filter(prop => prop.kind ===
|
|
1122
|
+
.filter(prop => prop.kind === ReferenceKind.ONE_TO_ONE && !prop.owner && !relationsToPopulate.includes(prop.name) && !relationsToPopulate.includes(`${prop.name}:ref`))
|
|
1146
1123
|
.map(prop => ({ field: `${prop.name}:ref` }))
|
|
1147
1124
|
.forEach(item => this._populate.push(item));
|
|
1148
1125
|
}
|
|
@@ -1158,7 +1135,7 @@ class QueryBuilder {
|
|
|
1158
1135
|
const prop = meta.properties[fromField];
|
|
1159
1136
|
const alias = this.getNextAlias(prop.pivotEntity ?? prop.type);
|
|
1160
1137
|
const aliasedName = `${fromAlias}.${prop.name}#${alias}`;
|
|
1161
|
-
this._joins[aliasedName] = this.helper.joinOneToReference(prop, this.mainAlias.aliasName, alias,
|
|
1138
|
+
this._joins[aliasedName] = this.helper.joinOneToReference(prop, this.mainAlias.aliasName, alias, JoinType.leftJoin);
|
|
1162
1139
|
this._joins[aliasedName].path = `${(Object.values(this._joins).find(j => j.alias === fromAlias)?.path ?? meta.className)}.${prop.name}`;
|
|
1163
1140
|
this._populateMap[aliasedName] = this._joins[aliasedName].alias;
|
|
1164
1141
|
}
|
|
@@ -1169,7 +1146,7 @@ class QueryBuilder {
|
|
|
1169
1146
|
}
|
|
1170
1147
|
processPopulateWhere(filter) {
|
|
1171
1148
|
const key = filter ? '_populateFilter' : '_populateWhere';
|
|
1172
|
-
if (this[key] == null || this[key] ===
|
|
1149
|
+
if (this[key] == null || this[key] === PopulateHint.ALL) {
|
|
1173
1150
|
return;
|
|
1174
1151
|
}
|
|
1175
1152
|
let joins = Object.values(this._joins);
|
|
@@ -1178,7 +1155,7 @@ class QueryBuilder {
|
|
|
1178
1155
|
join.cond = filter ? { ...join.cond } : {};
|
|
1179
1156
|
}
|
|
1180
1157
|
if (typeof this[key] === 'object') {
|
|
1181
|
-
const cond =
|
|
1158
|
+
const cond = CriteriaNodeFactory
|
|
1182
1159
|
.createNode(this.metadata, this.mainAlias.entityName, this[key])
|
|
1183
1160
|
.process(this, { matchPopulateJoins: true, ignoreBranching: true, preferNoBranch: true });
|
|
1184
1161
|
// there might be new joins created by processing the `populateWhere` object
|
|
@@ -1188,11 +1165,11 @@ class QueryBuilder {
|
|
|
1188
1165
|
}
|
|
1189
1166
|
mergeOnConditions(joins, cond, filter, op) {
|
|
1190
1167
|
for (const k of Object.keys(cond)) {
|
|
1191
|
-
if (
|
|
1168
|
+
if (Utils.isOperator(k)) {
|
|
1192
1169
|
if (Array.isArray(cond[k])) {
|
|
1193
1170
|
cond[k].forEach((c) => this.mergeOnConditions(joins, c, filter, k));
|
|
1194
1171
|
}
|
|
1195
|
-
/*
|
|
1172
|
+
/* v8 ignore next */
|
|
1196
1173
|
this.mergeOnConditions(joins, cond[k], filter, k);
|
|
1197
1174
|
}
|
|
1198
1175
|
const [alias] = this.helper.splitField(k);
|
|
@@ -1202,13 +1179,13 @@ class QueryBuilder {
|
|
|
1202
1179
|
// https://stackoverflow.com/a/56815807/3665878
|
|
1203
1180
|
if (parentJoin && !filter) {
|
|
1204
1181
|
const nested = (parentJoin.nested ??= new Set());
|
|
1205
|
-
join.type = join.type ===
|
|
1206
|
-
?
|
|
1207
|
-
:
|
|
1182
|
+
join.type = join.type === JoinType.innerJoin || ([ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(parentJoin.prop.kind))
|
|
1183
|
+
? JoinType.nestedInnerJoin
|
|
1184
|
+
: JoinType.nestedLeftJoin;
|
|
1208
1185
|
nested.add(join);
|
|
1209
1186
|
}
|
|
1210
1187
|
if (join.cond[k]) {
|
|
1211
|
-
/*
|
|
1188
|
+
/* v8 ignore next */
|
|
1212
1189
|
join.cond = { [op ?? '$and']: [join.cond, { [k]: cond[k] }] };
|
|
1213
1190
|
}
|
|
1214
1191
|
else if (op === '$or') {
|
|
@@ -1225,7 +1202,7 @@ class QueryBuilder {
|
|
|
1225
1202
|
// console.log(this._joins);
|
|
1226
1203
|
return Object.values(this._joins).some(join => {
|
|
1227
1204
|
// console.log(join.prop.name, join.prop.kind, [ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(join.prop.kind));
|
|
1228
|
-
return [
|
|
1205
|
+
return [ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(join.prop.kind);
|
|
1229
1206
|
});
|
|
1230
1207
|
}
|
|
1231
1208
|
wrapPaginateSubQuery(meta) {
|
|
@@ -1245,8 +1222,8 @@ class QueryBuilder {
|
|
|
1245
1222
|
const orderBy = [];
|
|
1246
1223
|
for (const orderMap of this._orderBy) {
|
|
1247
1224
|
for (const [field, direction] of Object.entries(orderMap)) {
|
|
1248
|
-
if (
|
|
1249
|
-
const rawField =
|
|
1225
|
+
if (RawQueryFragment.isKnownFragment(field)) {
|
|
1226
|
+
const rawField = RawQueryFragment.getKnownFragment(field, false);
|
|
1250
1227
|
this.rawFragments.add(field);
|
|
1251
1228
|
orderBy.push({ [rawField.clone()]: direction });
|
|
1252
1229
|
continue;
|
|
@@ -1259,7 +1236,7 @@ class QueryBuilder {
|
|
|
1259
1236
|
addToSelect.push(fieldName);
|
|
1260
1237
|
}
|
|
1261
1238
|
const quoted = this.platform.quoteIdentifier(fieldName);
|
|
1262
|
-
const key =
|
|
1239
|
+
const key = raw(`min(${quoted}${type})`);
|
|
1263
1240
|
orderBy.push({ [key]: direction });
|
|
1264
1241
|
}
|
|
1265
1242
|
}
|
|
@@ -1273,17 +1250,17 @@ class QueryBuilder {
|
|
|
1273
1250
|
if (typeof field === 'object' && field && '__as' in field) {
|
|
1274
1251
|
return field.__as === prop;
|
|
1275
1252
|
}
|
|
1276
|
-
if (field instanceof
|
|
1253
|
+
if (field instanceof RawQueryFragment) {
|
|
1277
1254
|
// not perfect, but should work most of the time, ideally we should check only the alias (`... as alias`)
|
|
1278
1255
|
return field.sql.includes(prop);
|
|
1279
1256
|
}
|
|
1280
1257
|
return false;
|
|
1281
1258
|
});
|
|
1282
|
-
/*
|
|
1283
|
-
if (field instanceof
|
|
1259
|
+
/* v8 ignore next 3 */
|
|
1260
|
+
if (field instanceof RawQueryFragment) {
|
|
1284
1261
|
innerQuery.select(field);
|
|
1285
1262
|
}
|
|
1286
|
-
else if (field instanceof
|
|
1263
|
+
else if (field instanceof NativeQueryBuilder) {
|
|
1287
1264
|
innerQuery.select(field.toRaw());
|
|
1288
1265
|
}
|
|
1289
1266
|
else if (field) {
|
|
@@ -1297,11 +1274,11 @@ class QueryBuilder {
|
|
|
1297
1274
|
subSubQuery.select(pks).from(innerQuery);
|
|
1298
1275
|
this._limit = undefined;
|
|
1299
1276
|
this._offset = undefined;
|
|
1300
|
-
if (!this._fields.some(f =>
|
|
1277
|
+
if (!this._fields.some(f => RawQueryFragment.isKnownFragment(f))) {
|
|
1301
1278
|
this.pruneExtraJoins(meta);
|
|
1302
1279
|
}
|
|
1303
1280
|
const { sql, params } = subSubQuery.compile();
|
|
1304
|
-
this.select(this._fields).where({ [
|
|
1281
|
+
this.select(this._fields).where({ [Utils.getPrimaryKeyHash(meta.primaryKeys)]: { $in: raw(sql, params) } });
|
|
1305
1282
|
}
|
|
1306
1283
|
pruneExtraJoins(meta) {
|
|
1307
1284
|
// remove joins that are not used for population or ordering to improve performance
|
|
@@ -1344,14 +1321,14 @@ class QueryBuilder {
|
|
|
1344
1321
|
// wrap one more time to get around MySQL limitations
|
|
1345
1322
|
// https://stackoverflow.com/questions/45494/mysql-error-1093-cant-specify-target-table-for-update-in-from-clause
|
|
1346
1323
|
const subSubQuery = this.platform.createNativeQueryBuilder();
|
|
1347
|
-
const method = this.flags.has(
|
|
1324
|
+
const method = this.flags.has(QueryFlag.UPDATE_SUB_QUERY) ? 'update' : 'delete';
|
|
1348
1325
|
const pks = this.prepareFields(meta.primaryKeys, 'sub-query');
|
|
1349
1326
|
this._cond = {}; // otherwise we would trigger validation error
|
|
1350
1327
|
this._joins = {}; // included in the subquery
|
|
1351
1328
|
subSubQuery.select(pks).from(subQuery.as(this.mainAlias.aliasName));
|
|
1352
1329
|
const { sql, params } = subSubQuery.compile();
|
|
1353
1330
|
this[method](this._data).where({
|
|
1354
|
-
[
|
|
1331
|
+
[Utils.getPrimaryKeyHash(meta.primaryKeys)]: { $in: raw(sql, params) },
|
|
1355
1332
|
});
|
|
1356
1333
|
}
|
|
1357
1334
|
getSchema(alias) {
|
|
@@ -1385,10 +1362,10 @@ class QueryBuilder {
|
|
|
1385
1362
|
this.createMainAlias(entityName, aliasName);
|
|
1386
1363
|
}
|
|
1387
1364
|
createQueryBuilderHelper() {
|
|
1388
|
-
return new
|
|
1365
|
+
return new QueryBuilderHelper(this.mainAlias.entityName, this.mainAlias.aliasName, this._aliases, this.subQueries, this.driver);
|
|
1389
1366
|
}
|
|
1390
1367
|
ensureFromClause() {
|
|
1391
|
-
/*
|
|
1368
|
+
/* v8 ignore next 3 */
|
|
1392
1369
|
if (!this._mainAlias) {
|
|
1393
1370
|
throw new Error(`Cannot proceed to build a query because the main alias is not set.`);
|
|
1394
1371
|
}
|
|
@@ -1398,9 +1375,9 @@ class QueryBuilder {
|
|
|
1398
1375
|
throw new Error('This QueryBuilder instance is already finalized, clone it first if you want to modify it.');
|
|
1399
1376
|
}
|
|
1400
1377
|
}
|
|
1401
|
-
/*
|
|
1378
|
+
/* v8 ignore start */
|
|
1402
1379
|
/** @ignore */
|
|
1403
|
-
[
|
|
1380
|
+
[inspect.custom](depth = 2) {
|
|
1404
1381
|
const object = { ...this };
|
|
1405
1382
|
const hidden = ['metadata', 'driver', 'context', 'platform', 'type'];
|
|
1406
1383
|
Object.keys(object).filter(k => k.startsWith('_')).forEach(k => delete object[k]);
|
|
@@ -1413,19 +1390,18 @@ class QueryBuilder {
|
|
|
1413
1390
|
if (this._schema) {
|
|
1414
1391
|
object.schema = this._schema;
|
|
1415
1392
|
}
|
|
1416
|
-
if (!
|
|
1393
|
+
if (!Utils.isEmpty(this._cond)) {
|
|
1417
1394
|
object.where = this._cond;
|
|
1418
1395
|
}
|
|
1419
1396
|
if (this._onConflict?.[0]) {
|
|
1420
1397
|
prefix = 'Upsert';
|
|
1421
1398
|
object.onConflict = this._onConflict[0];
|
|
1422
1399
|
}
|
|
1423
|
-
if (!
|
|
1400
|
+
if (!Utils.isEmpty(this._orderBy)) {
|
|
1424
1401
|
object.orderBy = this._orderBy;
|
|
1425
1402
|
}
|
|
1426
1403
|
const name = this._mainAlias ? `${prefix}QueryBuilder<${this._mainAlias?.entityName}>` : 'QueryBuilder';
|
|
1427
|
-
const ret =
|
|
1404
|
+
const ret = inspect(object, { depth });
|
|
1428
1405
|
return ret === '[Object]' ? `[${name}]` : name + ' ' + ret;
|
|
1429
1406
|
}
|
|
1430
1407
|
}
|
|
1431
|
-
exports.QueryBuilder = QueryBuilder;
|