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