@mikro-orm/knex 6.0.0-dev.6 → 6.0.0-dev.61
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 +5 -2
- package/AbstractSqlConnection.js +18 -10
- package/AbstractSqlDriver.d.ts +17 -17
- package/AbstractSqlDriver.js +110 -47
- package/AbstractSqlPlatform.d.ts +2 -2
- package/AbstractSqlPlatform.js +14 -7
- package/MonkeyPatchable.d.ts +1 -0
- package/MonkeyPatchable.js +3 -0
- package/README.md +64 -107
- package/SqlEntityManager.d.ts +0 -4
- package/SqlEntityManager.js +1 -9
- package/SqlEntityRepository.d.ts +0 -1
- package/SqlEntityRepository.js +0 -1
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/index.mjs +176 -0
- package/package.json +5 -5
- package/query/ArrayCriteriaNode.d.ts +3 -3
- package/query/CriteriaNode.d.ts +8 -8
- package/query/CriteriaNode.js +8 -8
- package/query/CriteriaNodeFactory.d.ts +6 -6
- package/query/CriteriaNodeFactory.js +11 -11
- package/query/ObjectCriteriaNode.d.ts +3 -3
- package/query/ObjectCriteriaNode.js +12 -8
- package/query/QueryBuilder.d.ts +19 -5
- package/query/QueryBuilder.js +191 -47
- package/query/QueryBuilderHelper.d.ts +3 -5
- package/query/QueryBuilderHelper.js +85 -71
- package/query/ScalarCriteriaNode.d.ts +3 -2
- package/query/ScalarCriteriaNode.js +9 -6
- package/schema/DatabaseSchema.js +3 -3
- package/schema/DatabaseTable.d.ts +9 -9
- package/schema/DatabaseTable.js +21 -22
- package/schema/SchemaComparator.d.ts +4 -4
- package/schema/SchemaComparator.js +4 -2
- package/schema/SchemaHelper.d.ts +11 -11
- package/schema/SchemaHelper.js +3 -3
- package/schema/{SchemaGenerator.d.ts → SqlSchemaGenerator.d.ts} +3 -7
- package/schema/{SchemaGenerator.js → SqlSchemaGenerator.js} +17 -24
- package/schema/index.d.ts +1 -1
- package/schema/index.js +1 -1
- package/typings.d.ts +14 -13
package/query/QueryBuilder.js
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
3
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
4
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
5
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
6
|
+
};
|
|
7
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
8
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
9
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
10
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
11
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
12
|
+
};
|
|
13
|
+
var _QueryBuilder_query;
|
|
2
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
15
|
exports.QueryBuilder = void 0;
|
|
16
|
+
const util_1 = require("util");
|
|
4
17
|
const core_1 = require("@mikro-orm/core");
|
|
5
18
|
const enums_1 = require("./enums");
|
|
6
19
|
const QueryBuilderHelper_1 = require("./QueryBuilderHelper");
|
|
@@ -39,12 +52,13 @@ class QueryBuilder {
|
|
|
39
52
|
/**
|
|
40
53
|
* @internal
|
|
41
54
|
*/
|
|
42
|
-
constructor(entityName, metadata, driver, context, alias, connectionType, em) {
|
|
55
|
+
constructor(entityName, metadata, driver, context, alias, connectionType, em, loggerContext) {
|
|
43
56
|
this.metadata = metadata;
|
|
44
57
|
this.driver = driver;
|
|
45
58
|
this.context = context;
|
|
46
59
|
this.connectionType = connectionType;
|
|
47
60
|
this.em = em;
|
|
61
|
+
this.loggerContext = loggerContext;
|
|
48
62
|
/** @internal */
|
|
49
63
|
this._populate = [];
|
|
50
64
|
/** @internal */
|
|
@@ -63,6 +77,7 @@ class QueryBuilder {
|
|
|
63
77
|
this._aliases = {};
|
|
64
78
|
this.platform = this.driver.getPlatform();
|
|
65
79
|
this.knex = this.driver.getConnection(this.connectionType).getKnex();
|
|
80
|
+
_QueryBuilder_query.set(this, void 0);
|
|
66
81
|
if (alias) {
|
|
67
82
|
this.aliasCounter++;
|
|
68
83
|
this._explicitAlias = true;
|
|
@@ -115,7 +130,7 @@ class QueryBuilder {
|
|
|
115
130
|
this._fields = this.mainAlias.metadata.primaryKeys;
|
|
116
131
|
}
|
|
117
132
|
else {
|
|
118
|
-
this._fields = [
|
|
133
|
+
this._fields = [(0, core_1.raw)('*')];
|
|
119
134
|
}
|
|
120
135
|
if (distinct) {
|
|
121
136
|
this.flags.add(core_1.QueryFlag.DISTINCT);
|
|
@@ -164,9 +179,15 @@ class QueryBuilder {
|
|
|
164
179
|
}
|
|
165
180
|
where(cond, params, operator) {
|
|
166
181
|
this.ensureNotFinalized();
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
182
|
+
const rawField = core_1.RawQueryFragment.getKnownFragment(cond);
|
|
183
|
+
if (rawField) {
|
|
184
|
+
const sql = this.platform.formatQuery(rawField.sql, rawField.params);
|
|
185
|
+
cond = { [(0, core_1.raw)(`(${sql})`)]: core_1.Utils.asArray(params) };
|
|
186
|
+
operator ??= '$and';
|
|
187
|
+
}
|
|
188
|
+
else if (core_1.Utils.isString(cond)) {
|
|
189
|
+
cond = { [(0, core_1.raw)(`(${cond})`, core_1.Utils.asArray(params))]: [] };
|
|
190
|
+
operator ??= '$and';
|
|
170
191
|
}
|
|
171
192
|
else {
|
|
172
193
|
cond = core_1.QueryHelper.processWhere({
|
|
@@ -234,7 +255,7 @@ class QueryBuilder {
|
|
|
234
255
|
having(cond = {}, params) {
|
|
235
256
|
this.ensureNotFinalized();
|
|
236
257
|
if (core_1.Utils.isString(cond)) {
|
|
237
|
-
cond = { [`(${cond})
|
|
258
|
+
cond = { [(0, core_1.raw)(`(${cond})`, params)]: [] };
|
|
238
259
|
}
|
|
239
260
|
this._having = CriteriaNodeFactory_1.CriteriaNodeFactory.createNode(this.metadata, this.mainAlias.entityName, cond).process(this);
|
|
240
261
|
return this;
|
|
@@ -277,11 +298,6 @@ class QueryBuilder {
|
|
|
277
298
|
ref(field) {
|
|
278
299
|
return this.knex.ref(field);
|
|
279
300
|
}
|
|
280
|
-
raw(sql, bindings = []) {
|
|
281
|
-
const raw = this.knex.raw(sql, bindings);
|
|
282
|
-
raw.__raw = true; // tag it as there is now way to check via `instanceof`
|
|
283
|
-
return raw;
|
|
284
|
-
}
|
|
285
301
|
limit(limit, offset = 0) {
|
|
286
302
|
this.ensureNotFinalized();
|
|
287
303
|
this._limit = limit;
|
|
@@ -360,7 +376,8 @@ class QueryBuilder {
|
|
|
360
376
|
core_1.Utils.runIfNotEmpty(() => {
|
|
361
377
|
const queryOrder = this.helper.getQueryOrder(this.type ?? enums_1.QueryType.SELECT, this._orderBy, this._populateMap);
|
|
362
378
|
if (queryOrder) {
|
|
363
|
-
|
|
379
|
+
qb.orderByRaw(queryOrder);
|
|
380
|
+
return;
|
|
364
381
|
}
|
|
365
382
|
}, this._orderBy);
|
|
366
383
|
core_1.Utils.runIfNotEmpty(() => qb.limit(this._limit), this._limit != null);
|
|
@@ -372,26 +389,34 @@ class QueryBuilder {
|
|
|
372
389
|
if (this.lockMode) {
|
|
373
390
|
this.helper.getLockSQL(qb, this.lockMode, this.lockTables);
|
|
374
391
|
}
|
|
375
|
-
this.helper.finalize(this.type ?? enums_1.QueryType.SELECT, qb, this.mainAlias.metadata);
|
|
392
|
+
this.helper.finalize(this.type ?? enums_1.QueryType.SELECT, qb, this.mainAlias.metadata, this._data);
|
|
376
393
|
return qb;
|
|
377
394
|
}
|
|
378
395
|
/**
|
|
379
396
|
* Returns the query with parameters as wildcards.
|
|
380
397
|
*/
|
|
381
398
|
getQuery() {
|
|
382
|
-
return this.
|
|
399
|
+
return this.toQuery().sql;
|
|
400
|
+
}
|
|
401
|
+
toQuery() {
|
|
402
|
+
if (__classPrivateFieldGet(this, _QueryBuilder_query, "f")) {
|
|
403
|
+
return __classPrivateFieldGet(this, _QueryBuilder_query, "f");
|
|
404
|
+
}
|
|
405
|
+
const sql = this.getKnexQuery().toSQL();
|
|
406
|
+
const query = sql.toNative();
|
|
407
|
+
return __classPrivateFieldSet(this, _QueryBuilder_query, { sql: query.sql, params: query.bindings ?? [], _sql: sql }, "f");
|
|
383
408
|
}
|
|
384
409
|
/**
|
|
385
410
|
* Returns the list of all parameters for this query.
|
|
386
411
|
*/
|
|
387
412
|
getParams() {
|
|
388
|
-
return this.
|
|
413
|
+
return this.toQuery().params;
|
|
389
414
|
}
|
|
390
415
|
/**
|
|
391
416
|
* Returns raw interpolated query string with all the parameters inlined.
|
|
392
417
|
*/
|
|
393
418
|
getFormattedQuery() {
|
|
394
|
-
const query = this.
|
|
419
|
+
const query = this.toQuery()._sql;
|
|
395
420
|
return this.platform.formatQuery(query.sql, query.bindings);
|
|
396
421
|
}
|
|
397
422
|
/**
|
|
@@ -433,7 +458,7 @@ class QueryBuilder {
|
|
|
433
458
|
return cached.data;
|
|
434
459
|
}
|
|
435
460
|
const type = this.connectionType || (method === 'run' ? 'write' : 'read');
|
|
436
|
-
const res = await this.driver.getConnection(type).execute(query.sql, query.bindings, method, this.context);
|
|
461
|
+
const res = await this.driver.getConnection(type).execute(query.sql, query.bindings, method, this.context, this.loggerContext);
|
|
437
462
|
const meta = this.mainAlias.metadata;
|
|
438
463
|
if (!mapResults || !meta) {
|
|
439
464
|
await this.em?.storeCache(this._cache, cached, res);
|
|
@@ -464,7 +489,27 @@ class QueryBuilder {
|
|
|
464
489
|
if (this._joinedProps.size > 0) {
|
|
465
490
|
res = this.driver.mergeJoinedResult(res, this.mainAlias.metadata);
|
|
466
491
|
}
|
|
467
|
-
|
|
492
|
+
const entities = [];
|
|
493
|
+
function propagatePopulateHint(entity, hint) {
|
|
494
|
+
(0, core_1.helper)(entity).__serializationContext.populate ??= hint;
|
|
495
|
+
hint.forEach(pop => {
|
|
496
|
+
const value = entity[pop.field];
|
|
497
|
+
if (core_1.Utils.isEntity(value, true)) {
|
|
498
|
+
(0, core_1.helper)(value).populated();
|
|
499
|
+
propagatePopulateHint(value, pop.children ?? []);
|
|
500
|
+
}
|
|
501
|
+
else if (core_1.Utils.isCollection(value)) {
|
|
502
|
+
value.populated();
|
|
503
|
+
value.getItems(false).forEach(item => propagatePopulateHint(item, pop.children ?? []));
|
|
504
|
+
}
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
for (const r of res) {
|
|
508
|
+
const entity = this.em.map(this.mainAlias.entityName, r, { schema: this._schema });
|
|
509
|
+
propagatePopulateHint(entity, this._populate);
|
|
510
|
+
entities.push(entity);
|
|
511
|
+
}
|
|
512
|
+
return entities;
|
|
468
513
|
}
|
|
469
514
|
/**
|
|
470
515
|
* Executes the query, returning the first result or null
|
|
@@ -488,11 +533,24 @@ class QueryBuilder {
|
|
|
488
533
|
}
|
|
489
534
|
return res ? +res.count : 0;
|
|
490
535
|
}
|
|
536
|
+
/**
|
|
537
|
+
* Executes the query, returning both array of results and total count query (without offset and limit).
|
|
538
|
+
*/
|
|
539
|
+
async getResultAndCount() {
|
|
540
|
+
return Promise.all([
|
|
541
|
+
this.getResultList(),
|
|
542
|
+
this.getCount(),
|
|
543
|
+
]);
|
|
544
|
+
}
|
|
491
545
|
/**
|
|
492
546
|
* Provides promise-like interface so we can await the QB instance.
|
|
493
547
|
*/
|
|
494
548
|
then(onfulfilled, onrejected) {
|
|
495
|
-
|
|
549
|
+
let type = this.type ?? enums_1.QueryType.SELECT;
|
|
550
|
+
if (this.flags.has(core_1.QueryFlag.UPDATE_SUB_QUERY) || this.flags.has(core_1.QueryFlag.DELETE_SUB_QUERY)) {
|
|
551
|
+
type = enums_1.QueryType.UPDATE;
|
|
552
|
+
}
|
|
553
|
+
switch (type) {
|
|
496
554
|
case enums_1.QueryType.INSERT:
|
|
497
555
|
case enums_1.QueryType.UPDATE:
|
|
498
556
|
case enums_1.QueryType.DELETE:
|
|
@@ -515,7 +573,10 @@ class QueryBuilder {
|
|
|
515
573
|
/* istanbul ignore next */
|
|
516
574
|
alias = meta?.properties[f]?.fieldNames[0] ?? alias;
|
|
517
575
|
}
|
|
518
|
-
|
|
576
|
+
const ret = qb.as(alias);
|
|
577
|
+
// tag the instance, so it is possible to detect it easily
|
|
578
|
+
Object.defineProperty(ret, '__as', { enumerable: false, value: alias });
|
|
579
|
+
return ret;
|
|
519
580
|
}
|
|
520
581
|
clone() {
|
|
521
582
|
const qb = new QueryBuilder(this.mainAlias.entityName, this.metadata, this.driver, this.context, this.mainAlias.aliasName, this.connectionType, this.em);
|
|
@@ -570,11 +631,11 @@ class QueryBuilder {
|
|
|
570
631
|
aliased: !this.type || [enums_1.QueryType.SELECT, enums_1.QueryType.COUNT].includes(this.type),
|
|
571
632
|
});
|
|
572
633
|
let aliasedName = `${fromAlias}.${prop.name}#${alias}`;
|
|
573
|
-
path
|
|
574
|
-
if (prop.
|
|
634
|
+
path ??= `${(Object.values(this._joins).find(j => j.alias === fromAlias)?.path ?? entityName)}.${prop.name}`;
|
|
635
|
+
if (prop.kind === core_1.ReferenceKind.ONE_TO_MANY) {
|
|
575
636
|
this._joins[aliasedName] = this.helper.joinOneToReference(prop, fromAlias, alias, type, cond);
|
|
576
637
|
}
|
|
577
|
-
else if (prop.
|
|
638
|
+
else if (prop.kind === core_1.ReferenceKind.MANY_TO_MANY) {
|
|
578
639
|
let pivotAlias = alias;
|
|
579
640
|
if (type !== 'pivotJoin') {
|
|
580
641
|
const oldPivotAlias = this.getAliasForJoinPath(path + '[pivot]');
|
|
@@ -585,7 +646,7 @@ class QueryBuilder {
|
|
|
585
646
|
Object.assign(this._joins, joins);
|
|
586
647
|
this.createAlias(prop.pivotEntity, pivotAlias);
|
|
587
648
|
}
|
|
588
|
-
else if (prop.
|
|
649
|
+
else if (prop.kind === core_1.ReferenceKind.ONE_TO_ONE) {
|
|
589
650
|
this._joins[aliasedName] = this.helper.joinOneToReference(prop, fromAlias, alias, type, cond);
|
|
590
651
|
}
|
|
591
652
|
else { // MANY_TO_ONE
|
|
@@ -599,17 +660,25 @@ class QueryBuilder {
|
|
|
599
660
|
prepareFields(fields, type = 'where') {
|
|
600
661
|
const ret = [];
|
|
601
662
|
fields.forEach(field => {
|
|
663
|
+
const rawField = core_1.RawQueryFragment.getKnownFragment(field);
|
|
664
|
+
if (rawField) {
|
|
665
|
+
const sql = this.platform.formatQuery(rawField.sql, rawField.params);
|
|
666
|
+
ret.push(this.knex.raw(sql));
|
|
667
|
+
return;
|
|
668
|
+
}
|
|
602
669
|
if (!core_1.Utils.isString(field)) {
|
|
603
|
-
|
|
670
|
+
ret.push(field);
|
|
671
|
+
return;
|
|
604
672
|
}
|
|
605
673
|
const join = Object.keys(this._joins).find(k => field === k.substring(0, k.indexOf('#')));
|
|
606
674
|
if (join && type === 'where') {
|
|
607
|
-
|
|
675
|
+
ret.push(...this.helper.mapJoinColumns(this.type ?? enums_1.QueryType.SELECT, this._joins[join]));
|
|
676
|
+
return;
|
|
608
677
|
}
|
|
609
678
|
const [a, f] = this.helper.splitField(field);
|
|
610
679
|
const prop = this.helper.getProperty(f, a);
|
|
611
680
|
/* istanbul ignore next */
|
|
612
|
-
if (prop && [core_1.
|
|
681
|
+
if (prop && [core_1.ReferenceKind.ONE_TO_MANY, core_1.ReferenceKind.MANY_TO_MANY].includes(prop.kind)) {
|
|
613
682
|
return;
|
|
614
683
|
}
|
|
615
684
|
if (prop?.embedded) {
|
|
@@ -617,7 +686,7 @@ class QueryBuilder {
|
|
|
617
686
|
ret.push(fieldName);
|
|
618
687
|
return;
|
|
619
688
|
}
|
|
620
|
-
if (prop?.
|
|
689
|
+
if (prop?.kind === core_1.ReferenceKind.EMBEDDED) {
|
|
621
690
|
if (prop.object) {
|
|
622
691
|
ret.push(this.helper.mapper(prop.fieldNames[0], this.type));
|
|
623
692
|
}
|
|
@@ -649,7 +718,7 @@ class QueryBuilder {
|
|
|
649
718
|
const cols = this.helper.mapJoinColumns(this.type ?? enums_1.QueryType.SELECT, this._joins[f]);
|
|
650
719
|
ret.push(...cols);
|
|
651
720
|
}
|
|
652
|
-
if (this._joins[f].prop.
|
|
721
|
+
if (this._joins[f].prop.kind !== core_1.ReferenceKind.ONE_TO_ONE && this._joins[f].inverseJoinColumns) {
|
|
653
722
|
this._joins[f].inverseJoinColumns.forEach(inverseJoinColumn => {
|
|
654
723
|
core_1.Utils.renameKey(this._cond, inverseJoinColumn, `${this._joins[f].alias}.${inverseJoinColumn}`);
|
|
655
724
|
});
|
|
@@ -668,7 +737,7 @@ class QueryBuilder {
|
|
|
668
737
|
}
|
|
669
738
|
if (data) {
|
|
670
739
|
if (core_1.Utils.isEntity(data)) {
|
|
671
|
-
data = (0, core_1.
|
|
740
|
+
data = this.em?.getComparator().prepareEntity(data) ?? (0, core_1.serialize)(data);
|
|
672
741
|
}
|
|
673
742
|
this._data = this.helper.processData(data, this.flags.has(core_1.QueryFlag.CONVERT_CUSTOM_TYPES));
|
|
674
743
|
}
|
|
@@ -733,7 +802,7 @@ class QueryBuilder {
|
|
|
733
802
|
if (meta && this.flags.has(core_1.QueryFlag.AUTO_JOIN_ONE_TO_ONE_OWNER)) {
|
|
734
803
|
const relationsToPopulate = this._populate.map(({ field }) => field);
|
|
735
804
|
meta.relations
|
|
736
|
-
.filter(prop => prop.
|
|
805
|
+
.filter(prop => prop.kind === core_1.ReferenceKind.ONE_TO_ONE && !prop.owner && !relationsToPopulate.includes(prop.name))
|
|
737
806
|
.map(prop => ({ field: prop.name }))
|
|
738
807
|
.forEach(item => this._populate.push(item));
|
|
739
808
|
}
|
|
@@ -742,7 +811,8 @@ class QueryBuilder {
|
|
|
742
811
|
const aliasedField = `${fromAlias}.${fromField}`;
|
|
743
812
|
const join = Object.keys(this._joins).find(k => `${aliasedField}#${this._joins[k].alias}` === k);
|
|
744
813
|
if (join && this._joins[join] && this.helper.isOneToOneInverse(fromField)) {
|
|
745
|
-
|
|
814
|
+
this._populateMap[join] = this._joins[join].alias;
|
|
815
|
+
return;
|
|
746
816
|
}
|
|
747
817
|
if (this.metadata.find(field)?.pivotTable) { // pivot table entity
|
|
748
818
|
this.autoJoinPivotTable(field);
|
|
@@ -763,9 +833,15 @@ class QueryBuilder {
|
|
|
763
833
|
const aliased = this.knex.ref(prop.fieldNames[0]).toString();
|
|
764
834
|
return `${prop.formula(alias)} as ${aliased}`;
|
|
765
835
|
})
|
|
766
|
-
.filter(field => !this._fields.
|
|
767
|
-
|
|
836
|
+
.filter(field => !this._fields.some(f => {
|
|
837
|
+
if (f instanceof core_1.RawQueryFragment) {
|
|
838
|
+
return f.sql === field && f.params.length === 0;
|
|
839
|
+
}
|
|
840
|
+
return f === field;
|
|
841
|
+
}))
|
|
842
|
+
.forEach(field => this._fields.push((0, core_1.raw)(field)));
|
|
768
843
|
}
|
|
844
|
+
this.processPopulateWhere();
|
|
769
845
|
core_1.QueryHelper.processObjectParams(this._data);
|
|
770
846
|
core_1.QueryHelper.processObjectParams(this._cond);
|
|
771
847
|
core_1.QueryHelper.processObjectParams(this._having);
|
|
@@ -781,17 +857,54 @@ class QueryBuilder {
|
|
|
781
857
|
}
|
|
782
858
|
this.finalized = true;
|
|
783
859
|
}
|
|
860
|
+
processPopulateWhere() {
|
|
861
|
+
if (this._populateWhere == null || this._populateWhere === core_1.PopulateHint.ALL) {
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
864
|
+
const joins = Object.values(this._joins);
|
|
865
|
+
joins.forEach(join => {
|
|
866
|
+
join.cond_ = join.cond;
|
|
867
|
+
join.cond = {};
|
|
868
|
+
});
|
|
869
|
+
const replaceOnConditions = (cond) => {
|
|
870
|
+
Object.keys(cond).forEach(k => {
|
|
871
|
+
if (core_1.Utils.isOperator(k)) {
|
|
872
|
+
if (Array.isArray(cond[k])) {
|
|
873
|
+
return cond[k].forEach((c) => replaceOnConditions(c));
|
|
874
|
+
}
|
|
875
|
+
return replaceOnConditions(cond[k]);
|
|
876
|
+
}
|
|
877
|
+
const [a] = this.helper.splitField(k);
|
|
878
|
+
const join = joins.find(j => j.alias === a);
|
|
879
|
+
if (join) {
|
|
880
|
+
join.cond = { ...join.cond, [k]: cond[k] };
|
|
881
|
+
}
|
|
882
|
+
});
|
|
883
|
+
};
|
|
884
|
+
if (this._populateWhere === core_1.PopulateHint.INFER) {
|
|
885
|
+
replaceOnConditions(this._cond);
|
|
886
|
+
}
|
|
887
|
+
else if (typeof this._populateWhere === 'object') {
|
|
888
|
+
const cond = CriteriaNodeFactory_1.CriteriaNodeFactory
|
|
889
|
+
.createNode(this.metadata, this.mainAlias.entityName, this._populateWhere)
|
|
890
|
+
.process(this);
|
|
891
|
+
replaceOnConditions(cond);
|
|
892
|
+
}
|
|
893
|
+
}
|
|
784
894
|
hasToManyJoins() {
|
|
785
895
|
return Object.values(this._joins).some(join => {
|
|
786
|
-
return [core_1.
|
|
896
|
+
return [core_1.ReferenceKind.ONE_TO_MANY, core_1.ReferenceKind.MANY_TO_MANY].includes(join.prop.kind);
|
|
787
897
|
});
|
|
788
898
|
}
|
|
789
899
|
wrapPaginateSubQuery(meta) {
|
|
790
900
|
const pks = this.prepareFields(meta.primaryKeys, 'sub-query');
|
|
791
901
|
const subQuery = this.clone().select(pks).groupBy(pks).limit(this._limit);
|
|
902
|
+
// revert the on conditions added via populateWhere, we want to apply those only once
|
|
903
|
+
Object.values(subQuery._joins).forEach(join => join.cond = join.cond_ ?? {});
|
|
792
904
|
if (this._offset) {
|
|
793
905
|
subQuery.offset(this._offset);
|
|
794
906
|
}
|
|
907
|
+
const addToSelect = [];
|
|
795
908
|
if (this._orderBy.length > 0) {
|
|
796
909
|
const orderBy = [];
|
|
797
910
|
for (const orderMap of this._orderBy) {
|
|
@@ -799,28 +912,37 @@ class QueryBuilder {
|
|
|
799
912
|
const [a, f] = this.helper.splitField(field);
|
|
800
913
|
const prop = this.helper.getProperty(f, a);
|
|
801
914
|
const type = this.platform.castColumn(prop);
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
915
|
+
const fieldName = this.helper.mapper(field, this.type, undefined, null);
|
|
916
|
+
if (!prop?.persist && !prop?.formula) {
|
|
917
|
+
addToSelect.push(fieldName);
|
|
918
|
+
}
|
|
919
|
+
orderBy.push({ [(0, core_1.raw)(`min(${this.ref(fieldName)}${type})`)]: direction });
|
|
805
920
|
}
|
|
806
921
|
}
|
|
807
922
|
subQuery.orderBy(orderBy);
|
|
808
923
|
}
|
|
809
924
|
subQuery.finalized = true;
|
|
810
925
|
const knexQuery = subQuery.as(this.mainAlias.aliasName).clearSelect().select(pks);
|
|
926
|
+
if (addToSelect.length > 0) {
|
|
927
|
+
addToSelect.forEach(prop => {
|
|
928
|
+
const field = this._fields.find(field => {
|
|
929
|
+
if (typeof field === 'object' && field && '__as' in field) {
|
|
930
|
+
return field.__as === prop;
|
|
931
|
+
}
|
|
932
|
+
// not perfect, but should work most of the time, ideally we should check only the alias (`... as alias`)
|
|
933
|
+
return field.toString().includes(prop);
|
|
934
|
+
});
|
|
935
|
+
if (field) {
|
|
936
|
+
knexQuery.select(field);
|
|
937
|
+
}
|
|
938
|
+
});
|
|
939
|
+
}
|
|
811
940
|
// multiple sub-queries are needed to get around mysql limitations with order by + limit + where in + group by (o.O)
|
|
812
941
|
// https://stackoverflow.com/questions/17892762/mysql-this-version-of-mysql-doesnt-yet-support-limit-in-all-any-some-subqu
|
|
813
942
|
const subSubQuery = this.getKnex().select(pks).from(knexQuery);
|
|
814
943
|
this._limit = undefined;
|
|
815
944
|
this._offset = undefined;
|
|
816
|
-
const cond = this._cond;
|
|
817
945
|
this.select(this._fields).where({ [core_1.Utils.getPrimaryKeyHash(meta.primaryKeys)]: { $in: subSubQuery } });
|
|
818
|
-
if (this._populateWhere === core_1.PopulateHint.INFER) {
|
|
819
|
-
this.andWhere(cond);
|
|
820
|
-
}
|
|
821
|
-
else if (typeof this._populateWhere === 'object') {
|
|
822
|
-
this.andWhere(this._populateWhere);
|
|
823
|
-
}
|
|
824
946
|
}
|
|
825
947
|
wrapModifySubQuery(meta) {
|
|
826
948
|
const subQuery = this.clone();
|
|
@@ -864,11 +986,11 @@ class QueryBuilder {
|
|
|
864
986
|
fromSubQuery(target, aliasName) {
|
|
865
987
|
const subQuery = target.getKnexQuery();
|
|
866
988
|
const { entityName } = target.mainAlias;
|
|
867
|
-
aliasName
|
|
989
|
+
aliasName ??= this.getNextAlias(entityName);
|
|
868
990
|
this.createMainAlias(entityName, aliasName, subQuery);
|
|
869
991
|
}
|
|
870
992
|
fromEntityName(entityName, aliasName) {
|
|
871
|
-
aliasName
|
|
993
|
+
aliasName ??= this._mainAlias?.aliasName ?? this.getNextAlias(entityName);
|
|
872
994
|
this.createMainAlias(entityName, aliasName);
|
|
873
995
|
}
|
|
874
996
|
createQueryBuilderHelper() {
|
|
@@ -885,5 +1007,27 @@ class QueryBuilder {
|
|
|
885
1007
|
throw new Error('This QueryBuilder instance is already finalized, clone it first if you want to modify it.');
|
|
886
1008
|
}
|
|
887
1009
|
}
|
|
1010
|
+
/* istanbul ignore next */
|
|
1011
|
+
[(_QueryBuilder_query = new WeakMap(), util_1.inspect.custom)](depth) {
|
|
1012
|
+
const object = { ...this };
|
|
1013
|
+
const hidden = ['metadata', 'driver', 'context', 'platform', 'knex', 'type'];
|
|
1014
|
+
Object.keys(object).filter(k => k.startsWith('_')).forEach(k => delete object[k]);
|
|
1015
|
+
Object.keys(object).filter(k => object[k] == null).forEach(k => delete object[k]);
|
|
1016
|
+
hidden.forEach(k => delete object[k]);
|
|
1017
|
+
let prefix = this.type ? this.type.substring(0, 1) + this.type.toLowerCase().substring(1) : '';
|
|
1018
|
+
if (this._data) {
|
|
1019
|
+
object.data = this._data;
|
|
1020
|
+
}
|
|
1021
|
+
if (!core_1.Utils.isEmpty(this._cond)) {
|
|
1022
|
+
object.where = this._cond;
|
|
1023
|
+
}
|
|
1024
|
+
if (this._onConflict?.[0]) {
|
|
1025
|
+
prefix = 'Upsert';
|
|
1026
|
+
object.onConflict = this._onConflict[0];
|
|
1027
|
+
}
|
|
1028
|
+
const name = this._mainAlias ? `${prefix}QueryBuilder<${this._mainAlias?.entityName}>` : 'QueryBuilder';
|
|
1029
|
+
const ret = (0, util_1.inspect)(object, { depth });
|
|
1030
|
+
return ret === '[Object]' ? `[${name}]` : name + ' ' + ret;
|
|
1031
|
+
}
|
|
888
1032
|
}
|
|
889
1033
|
exports.QueryBuilder = QueryBuilder;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Knex } from 'knex';
|
|
2
|
-
import type { Dictionary, EntityData, EntityMetadata, EntityProperty, FlatQueryOrderMap, QBFilterQuery } from '@mikro-orm/core';
|
|
2
|
+
import type { Dictionary, EntityData, EntityKey, EntityMetadata, EntityProperty, FlatQueryOrderMap, QBFilterQuery } from '@mikro-orm/core';
|
|
3
3
|
import { LockMode } from '@mikro-orm/core';
|
|
4
4
|
import { QueryType } from './enums';
|
|
5
5
|
import type { Field, JoinOptions } from '../typings';
|
|
@@ -43,16 +43,14 @@ export declare class QueryBuilderHelper {
|
|
|
43
43
|
}[], qb: Knex.QueryBuilder): void;
|
|
44
44
|
appendQueryCondition(type: QueryType, cond: any, qb: Knex.QueryBuilder, operator?: '$and' | '$or', method?: 'where' | 'having'): void;
|
|
45
45
|
private appendQuerySubCondition;
|
|
46
|
-
private processCustomExpression;
|
|
47
46
|
private processObjectSubCondition;
|
|
48
47
|
private getOperatorReplacement;
|
|
49
48
|
getQueryOrder(type: QueryType, orderBy: FlatQueryOrderMap | FlatQueryOrderMap[], populate: Dictionary<string>): string;
|
|
50
49
|
getQueryOrderFromObject(type: QueryType, orderBy: FlatQueryOrderMap, populate: Dictionary<string>): string;
|
|
51
|
-
finalize(type: QueryType, qb: Knex.QueryBuilder, meta?: EntityMetadata): void;
|
|
52
|
-
splitField(field:
|
|
50
|
+
finalize(type: QueryType, qb: Knex.QueryBuilder, meta?: EntityMetadata, data?: Dictionary): void;
|
|
51
|
+
splitField<T>(field: EntityKey<T>, greedyAlias?: boolean): [string, EntityKey<T>];
|
|
53
52
|
getLockSQL(qb: Knex.QueryBuilder, lockMode: LockMode, lockTables?: string[]): void;
|
|
54
53
|
updateVersionProperty(qb: Knex.QueryBuilder, data: Dictionary): void;
|
|
55
|
-
static isCustomExpression(field: string, hasAlias?: boolean): boolean;
|
|
56
54
|
private prefix;
|
|
57
55
|
private appendGroupCondition;
|
|
58
56
|
private isPrefixed;
|