@mikro-orm/sql 7.0.0-dev.113 → 7.0.0-dev.115
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/AbstractSqlDriver.d.ts +13 -13
- package/AbstractSqlDriver.js +75 -78
- package/PivotCollectionPersister.js +3 -3
- package/SqlEntityManager.d.ts +1 -1
- package/package.json +2 -2
- package/plugin/transformer.js +1 -1
- package/query/CriteriaNode.d.ts +4 -4
- package/query/CriteriaNode.js +12 -13
- package/query/CriteriaNodeFactory.d.ts +6 -6
- package/query/CriteriaNodeFactory.js +19 -17
- package/query/NativeQueryBuilder.js +1 -2
- package/query/ObjectCriteriaNode.js +27 -27
- package/query/QueryBuilder.d.ts +12 -14
- package/query/QueryBuilder.js +73 -94
- package/query/QueryBuilderHelper.d.ts +10 -9
- package/query/QueryBuilderHelper.js +62 -45
- package/query/ScalarCriteriaNode.js +1 -1
- package/schema/DatabaseSchema.js +3 -7
- package/schema/SchemaHelper.d.ts +2 -2
- package/schema/SchemaHelper.js +2 -3
- package/schema/SqlSchemaGenerator.js +2 -2
- package/tsconfig.build.tsbuildinfo +1 -1
- package/typings.d.ts +5 -5
package/query/QueryBuilder.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { helper, isRaw, LoadStrategy, LockMode, PopulateHint, QueryFlag, QueryHelper, raw, RawQueryFragment, Reference, ReferenceKind, serialize, Utils, ValidationError,
|
|
1
|
+
import { helper, inspect, isRaw, LoadStrategy, LockMode, PopulateHint, QueryFlag, QueryHelper, raw, RawQueryFragment, Reference, ReferenceKind, serialize, Utils, ValidationError, } from '@mikro-orm/core';
|
|
2
2
|
import { JoinType, QueryType } from './enums.js';
|
|
3
3
|
import { QueryBuilderHelper } from './QueryBuilderHelper.js';
|
|
4
4
|
import { CriteriaNodeFactory } from './CriteriaNodeFactory.js';
|
|
@@ -47,8 +47,6 @@ export class QueryBuilder {
|
|
|
47
47
|
_populate = [];
|
|
48
48
|
/** @internal */
|
|
49
49
|
_populateMap = {};
|
|
50
|
-
/** @internal */
|
|
51
|
-
rawFragments = new Set();
|
|
52
50
|
aliasCounter = 0;
|
|
53
51
|
flags = new Set([QueryFlag.CONVERT_CUSTOM_TYPES]);
|
|
54
52
|
finalized = false;
|
|
@@ -140,7 +138,7 @@ export class QueryBuilder {
|
|
|
140
138
|
this._fields = Utils.asArray(field);
|
|
141
139
|
}
|
|
142
140
|
else if (distinct || this.hasToManyJoins()) {
|
|
143
|
-
this._fields = this.mainAlias.
|
|
141
|
+
this._fields = this.mainAlias.meta.primaryKeys;
|
|
144
142
|
}
|
|
145
143
|
else {
|
|
146
144
|
this._fields = [raw('*')];
|
|
@@ -276,15 +274,15 @@ export class QueryBuilder {
|
|
|
276
274
|
continue;
|
|
277
275
|
}
|
|
278
276
|
filterOptions = QueryHelper.mergePropertyFilters(join.prop.filters, filterOptions);
|
|
279
|
-
const cond = await em.applyFilters(join.prop.
|
|
280
|
-
if (Utils.hasObjectKeys(cond)) {
|
|
277
|
+
const cond = await em.applyFilters(join.prop.targetMeta.class, join.cond, filterOptions, 'read');
|
|
278
|
+
if (Utils.hasObjectKeys(cond) || RawQueryFragment.hasObjectFragments(cond)) {
|
|
281
279
|
// remove nested filters, we only care about scalars here, nesting would require another join branch
|
|
282
280
|
for (const key of Object.keys(cond)) {
|
|
283
281
|
if (Utils.isPlainObject(cond[key]) && Object.keys(cond[key]).every(k => !(Utils.isOperator(k) && !['$some', '$none', '$every'].includes(k)))) {
|
|
284
282
|
delete cond[key];
|
|
285
283
|
}
|
|
286
284
|
}
|
|
287
|
-
if (Utils.hasObjectKeys(join.cond)) {
|
|
285
|
+
if (Utils.hasObjectKeys(join.cond) || RawQueryFragment.hasObjectFragments(join.cond)) {
|
|
288
286
|
/* v8 ignore next */
|
|
289
287
|
join.cond = { $and: [join.cond, cond] };
|
|
290
288
|
}
|
|
@@ -296,7 +294,7 @@ export class QueryBuilder {
|
|
|
296
294
|
}
|
|
297
295
|
withSubQuery(subQuery, alias) {
|
|
298
296
|
this.ensureNotFinalized();
|
|
299
|
-
if (subQuery
|
|
297
|
+
if (isRaw(subQuery)) {
|
|
300
298
|
this.subQueries[alias] = this.platform.formatQuery(subQuery.sql, subQuery.params);
|
|
301
299
|
}
|
|
302
300
|
else {
|
|
@@ -306,9 +304,8 @@ export class QueryBuilder {
|
|
|
306
304
|
}
|
|
307
305
|
where(cond, params, operator) {
|
|
308
306
|
this.ensureNotFinalized();
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
const sql = this.platform.formatQuery(rawField.sql, rawField.params);
|
|
307
|
+
if (isRaw(cond)) {
|
|
308
|
+
const sql = this.platform.formatQuery(cond.sql, cond.params);
|
|
312
309
|
cond = { [raw(`(${sql})`)]: Utils.asArray(params) };
|
|
313
310
|
operator ??= '$and';
|
|
314
311
|
}
|
|
@@ -328,13 +325,13 @@ export class QueryBuilder {
|
|
|
328
325
|
});
|
|
329
326
|
}
|
|
330
327
|
const op = operator || params;
|
|
331
|
-
const topLevel = !op || !Utils.hasObjectKeys(this._cond);
|
|
328
|
+
const topLevel = !op || !(Utils.hasObjectKeys(this._cond) || RawQueryFragment.hasObjectFragments(this._cond));
|
|
332
329
|
const criteriaNode = CriteriaNodeFactory.createNode(this.metadata, this.mainAlias.entityName, cond);
|
|
333
330
|
const ignoreBranching = this.__populateWhere === 'infer';
|
|
334
331
|
if ([QueryType.UPDATE, QueryType.DELETE].includes(this.type) && criteriaNode.willAutoJoin(this, undefined, { ignoreBranching })) {
|
|
335
332
|
// use sub-query to support joining
|
|
336
333
|
this.setFlag(this.type === QueryType.UPDATE ? QueryFlag.UPDATE_SUB_QUERY : QueryFlag.DELETE_SUB_QUERY);
|
|
337
|
-
this.select(this.mainAlias.
|
|
334
|
+
this.select(this.mainAlias.meta.primaryKeys, true);
|
|
338
335
|
}
|
|
339
336
|
if (topLevel) {
|
|
340
337
|
this._cond = criteriaNode.process(this, { ignoreBranching });
|
|
@@ -370,6 +367,7 @@ export class QueryBuilder {
|
|
|
370
367
|
this._orderBy = [];
|
|
371
368
|
}
|
|
372
369
|
Utils.asArray(orderBy).forEach(o => {
|
|
370
|
+
this.helper.validateQueryOrder(o);
|
|
373
371
|
const processed = QueryHelper.processWhere({
|
|
374
372
|
where: o,
|
|
375
373
|
entityName: this.mainAlias.entityName,
|
|
@@ -381,6 +379,7 @@ export class QueryBuilder {
|
|
|
381
379
|
type: 'orderBy',
|
|
382
380
|
});
|
|
383
381
|
this._orderBy.push(CriteriaNodeFactory.createNode(this.metadata, this.mainAlias.entityName, processed).process(this, { matchPopulateJoins: true, type: 'orderBy' }));
|
|
382
|
+
// this._orderBy.push(CriteriaNodeFactory.createNode<Entity>(this.metadata, Utils.className(this.mainAlias.entityName), processed).process(this, { matchPopulateJoins: true, type: 'orderBy' }));
|
|
384
383
|
});
|
|
385
384
|
return this;
|
|
386
385
|
}
|
|
@@ -411,7 +410,7 @@ export class QueryBuilder {
|
|
|
411
410
|
return this.having(cond, params, '$or');
|
|
412
411
|
}
|
|
413
412
|
onConflict(fields = []) {
|
|
414
|
-
const meta = this.mainAlias.
|
|
413
|
+
const meta = this.mainAlias.meta;
|
|
415
414
|
this.ensureNotFinalized();
|
|
416
415
|
this._onConflict ??= [];
|
|
417
416
|
this._onConflict.push({
|
|
@@ -538,11 +537,10 @@ export class QueryBuilder {
|
|
|
538
537
|
this.fromSubQuery(target, aliasName);
|
|
539
538
|
}
|
|
540
539
|
else {
|
|
541
|
-
|
|
542
|
-
if (aliasName && this._mainAlias && entityName !== this._mainAlias.aliasName) {
|
|
540
|
+
if (aliasName && this._mainAlias && Utils.className(target) !== this._mainAlias.aliasName) {
|
|
543
541
|
throw new Error(`Cannot override the alias to '${aliasName}' since a query already contains references to '${this._mainAlias.aliasName}'`);
|
|
544
542
|
}
|
|
545
|
-
this.fromEntityName(
|
|
543
|
+
this.fromEntityName(target, aliasName);
|
|
546
544
|
}
|
|
547
545
|
return this;
|
|
548
546
|
}
|
|
@@ -553,9 +551,10 @@ export class QueryBuilder {
|
|
|
553
551
|
this._query = {};
|
|
554
552
|
this.finalize();
|
|
555
553
|
const qb = this.getQueryBase(processVirtualEntity);
|
|
554
|
+
const isNotEmptyObject = (obj) => Utils.hasObjectKeys(obj) || RawQueryFragment.hasObjectFragments(obj);
|
|
556
555
|
Utils.runIfNotEmpty(() => this.helper.appendQueryCondition(this.type, this._cond, qb), this._cond && !this._onConflict);
|
|
557
|
-
Utils.runIfNotEmpty(() => qb.groupBy(this.prepareFields(this._groupBy, 'groupBy')), this._groupBy);
|
|
558
|
-
Utils.runIfNotEmpty(() => this.helper.appendQueryCondition(this.type, this._having, qb, undefined, 'having'), this._having);
|
|
556
|
+
Utils.runIfNotEmpty(() => qb.groupBy(this.prepareFields(this._groupBy, 'groupBy')), isNotEmptyObject(this._groupBy));
|
|
557
|
+
Utils.runIfNotEmpty(() => this.helper.appendQueryCondition(this.type, this._having, qb, undefined, 'having'), isNotEmptyObject(this._having));
|
|
559
558
|
Utils.runIfNotEmpty(() => {
|
|
560
559
|
const queryOrder = this.helper.getQueryOrder(this.type, this._orderBy, this._populateMap);
|
|
561
560
|
if (queryOrder.length > 0) {
|
|
@@ -563,7 +562,7 @@ export class QueryBuilder {
|
|
|
563
562
|
qb.orderBy(sql);
|
|
564
563
|
return;
|
|
565
564
|
}
|
|
566
|
-
}, this._orderBy);
|
|
565
|
+
}, isNotEmptyObject(this._orderBy));
|
|
567
566
|
Utils.runIfNotEmpty(() => qb.limit(this._limit), this._limit != null);
|
|
568
567
|
Utils.runIfNotEmpty(() => qb.offset(this._offset), this._offset);
|
|
569
568
|
Utils.runIfNotEmpty(() => qb.comment(this._comments), this._comments);
|
|
@@ -572,17 +571,9 @@ export class QueryBuilder {
|
|
|
572
571
|
if (this.lockMode) {
|
|
573
572
|
this.helper.getLockSQL(qb, this.lockMode, this.lockTables, this._joins);
|
|
574
573
|
}
|
|
575
|
-
this.helper.finalize(this.type, qb, this.mainAlias.
|
|
576
|
-
this.clearRawFragmentsCache();
|
|
574
|
+
this.helper.finalize(this.type, qb, this.mainAlias.meta, this._data, this._returning);
|
|
577
575
|
return this._query.qb = qb;
|
|
578
576
|
}
|
|
579
|
-
/**
|
|
580
|
-
* @internal
|
|
581
|
-
*/
|
|
582
|
-
clearRawFragmentsCache() {
|
|
583
|
-
this.rawFragments.forEach(key => RawQueryFragment.remove(key));
|
|
584
|
-
this.rawFragments.clear();
|
|
585
|
-
}
|
|
586
577
|
/**
|
|
587
578
|
* Returns the query with parameters as wildcards.
|
|
588
579
|
*/
|
|
@@ -622,7 +613,7 @@ export class QueryBuilder {
|
|
|
622
613
|
* @internal
|
|
623
614
|
*/
|
|
624
615
|
getAliasForJoinPath(path, options) {
|
|
625
|
-
if (!path || path === this.mainAlias.entityName) {
|
|
616
|
+
if (!path || path === Utils.className(this.mainAlias.entityName)) {
|
|
626
617
|
return this.mainAlias.aliasName;
|
|
627
618
|
}
|
|
628
619
|
const join = typeof path === 'string' ? this.getJoinForPath(path, options) : path;
|
|
@@ -666,6 +657,7 @@ export class QueryBuilder {
|
|
|
666
657
|
* @internal
|
|
667
658
|
*/
|
|
668
659
|
getNextAlias(entityName = 'e') {
|
|
660
|
+
entityName = Utils.className(entityName);
|
|
669
661
|
return this.driver.config.getNamingStrategy().aliasName(entityName, this.aliasCounter++);
|
|
670
662
|
}
|
|
671
663
|
/**
|
|
@@ -697,7 +689,7 @@ export class QueryBuilder {
|
|
|
697
689
|
}
|
|
698
690
|
const loggerContext = { id: this.em?.id, ...this.loggerContext };
|
|
699
691
|
const res = await this.getConnection().execute(query.sql, query.params, method, this.context, loggerContext);
|
|
700
|
-
const meta = this.mainAlias.
|
|
692
|
+
const meta = this.mainAlias.meta;
|
|
701
693
|
if (!options.mapResults || !meta) {
|
|
702
694
|
await this.em?.storeCache(this._cache, cached, res);
|
|
703
695
|
return res;
|
|
@@ -711,7 +703,7 @@ export class QueryBuilder {
|
|
|
711
703
|
const map = {};
|
|
712
704
|
mapped = res.map(r => this.driver.mapResult(r, meta, this._populate, this, map));
|
|
713
705
|
if (options.mergeResults && joinedProps.length > 0) {
|
|
714
|
-
mapped = this.driver.mergeJoinedResult(mapped, this.mainAlias.
|
|
706
|
+
mapped = this.driver.mergeJoinedResult(mapped, this.mainAlias.meta, joinedProps);
|
|
715
707
|
}
|
|
716
708
|
}
|
|
717
709
|
else {
|
|
@@ -752,7 +744,7 @@ export class QueryBuilder {
|
|
|
752
744
|
const query = this.toQuery();
|
|
753
745
|
const loggerContext = { id: this.em?.id, ...this.loggerContext };
|
|
754
746
|
const res = this.getConnection().stream(query.sql, query.params, this.context, loggerContext);
|
|
755
|
-
const meta = this.mainAlias.
|
|
747
|
+
const meta = this.mainAlias.meta;
|
|
756
748
|
if (options.rawResults || !meta) {
|
|
757
749
|
yield* res;
|
|
758
750
|
return;
|
|
@@ -769,7 +761,7 @@ export class QueryBuilder {
|
|
|
769
761
|
continue;
|
|
770
762
|
}
|
|
771
763
|
if (stack.length > 0 && hash(stack[stack.length - 1]) !== hash(mapped)) {
|
|
772
|
-
const res = this.driver.mergeJoinedResult(stack, this.mainAlias.
|
|
764
|
+
const res = this.driver.mergeJoinedResult(stack, this.mainAlias.meta, joinedProps);
|
|
773
765
|
for (const row of res) {
|
|
774
766
|
yield this.mapResult(row, options.mapResults);
|
|
775
767
|
}
|
|
@@ -778,7 +770,7 @@ export class QueryBuilder {
|
|
|
778
770
|
stack.push(mapped);
|
|
779
771
|
}
|
|
780
772
|
if (stack.length > 0) {
|
|
781
|
-
const merged = this.driver.mergeJoinedResult(stack, this.mainAlias.
|
|
773
|
+
const merged = this.driver.mergeJoinedResult(stack, this.mainAlias.meta, joinedProps);
|
|
782
774
|
yield this.mapResult(merged[0], options.mapResults);
|
|
783
775
|
}
|
|
784
776
|
}
|
|
@@ -865,21 +857,21 @@ export class QueryBuilder {
|
|
|
865
857
|
await this.clone().getCount(),
|
|
866
858
|
];
|
|
867
859
|
}
|
|
868
|
-
|
|
869
|
-
* Returns native query builder instance with sub-query aliased with given alias.
|
|
870
|
-
* You can provide `EntityName.propName` as alias, then the field name will be used based on the metadata
|
|
871
|
-
*/
|
|
872
|
-
as(alias) {
|
|
860
|
+
as(aliasOrTargetEntity, alias) {
|
|
873
861
|
const qb = this.getNativeQuery();
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
862
|
+
let finalAlias = aliasOrTargetEntity;
|
|
863
|
+
/* v8 ignore next */
|
|
864
|
+
if (typeof aliasOrTargetEntity === 'string' && aliasOrTargetEntity.includes('.')) {
|
|
865
|
+
throw new Error('qb.as(alias) no longer supports target entity name prefix, use qb.as(TargetEntity, key) signature instead');
|
|
866
|
+
}
|
|
867
|
+
if (alias) {
|
|
868
|
+
const meta = this.metadata.get(aliasOrTargetEntity);
|
|
877
869
|
/* v8 ignore next */
|
|
878
|
-
|
|
870
|
+
finalAlias = meta.properties[alias]?.fieldNames[0] ?? alias;
|
|
879
871
|
}
|
|
880
|
-
qb.as(
|
|
872
|
+
qb.as(finalAlias);
|
|
881
873
|
// tag the instance, so it is possible to detect it easily
|
|
882
|
-
Object.defineProperty(qb, '__as', { enumerable: false, value:
|
|
874
|
+
Object.defineProperty(qb, '__as', { enumerable: false, value: finalAlias });
|
|
883
875
|
return qb;
|
|
884
876
|
}
|
|
885
877
|
clone(reset) {
|
|
@@ -892,16 +884,14 @@ export class QueryBuilder {
|
|
|
892
884
|
const properties = [
|
|
893
885
|
'flags', '_populate', '_populateWhere', '_populateFilter', '__populateWhere', '_populateMap', '_joins', '_joinedProps', '_cond', '_data', '_orderBy',
|
|
894
886
|
'_schema', '_indexHint', '_cache', 'subQueries', 'lockMode', 'lockTables', '_groupBy', '_having', '_returning',
|
|
895
|
-
'_comments', '_hintComments', '
|
|
887
|
+
'_comments', '_hintComments', 'aliasCounter',
|
|
896
888
|
];
|
|
897
|
-
RawQueryFragment.cloneRegistry = this.rawFragments;
|
|
898
889
|
for (const prop of Object.keys(this)) {
|
|
899
890
|
if (reset.includes(prop) || ['_helper', '_query'].includes(prop)) {
|
|
900
891
|
continue;
|
|
901
892
|
}
|
|
902
893
|
qb[prop] = properties.includes(prop) ? Utils.copy(this[prop]) : this[prop];
|
|
903
894
|
}
|
|
904
|
-
delete RawQueryFragment.cloneRegistry;
|
|
905
895
|
/* v8 ignore next */
|
|
906
896
|
if (this._fields && !reset.includes('_fields')) {
|
|
907
897
|
qb._fields = [...this._fields];
|
|
@@ -935,7 +925,7 @@ export class QueryBuilder {
|
|
|
935
925
|
if (res instanceof QueryBuilder) {
|
|
936
926
|
return `(${res.getFormattedQuery()}) as ${this.platform.quoteIdentifier(this.alias)}`;
|
|
937
927
|
}
|
|
938
|
-
if (res
|
|
928
|
+
if (isRaw(res)) {
|
|
939
929
|
const query = this.platform.formatQuery(res.sql, res.params);
|
|
940
930
|
return `(${query}) as ${this.platform.quoteIdentifier(this.alias)}`;
|
|
941
931
|
}
|
|
@@ -950,11 +940,11 @@ export class QueryBuilder {
|
|
|
950
940
|
kind: ReferenceKind.MANY_TO_ONE,
|
|
951
941
|
};
|
|
952
942
|
if (field instanceof QueryBuilder) {
|
|
953
|
-
prop.type = field.mainAlias.entityName;
|
|
954
|
-
prop.targetMeta = field.mainAlias.
|
|
943
|
+
prop.type = Utils.className(field.mainAlias.entityName);
|
|
944
|
+
prop.targetMeta = field.mainAlias.meta;
|
|
955
945
|
field = field.getNativeQuery();
|
|
956
946
|
}
|
|
957
|
-
if (field
|
|
947
|
+
if (isRaw(field)) {
|
|
958
948
|
field = this.platform.formatQuery(field.sql, field.params);
|
|
959
949
|
}
|
|
960
950
|
const key = `${this.alias}.${prop.name}#${alias}`;
|
|
@@ -983,7 +973,7 @@ export class QueryBuilder {
|
|
|
983
973
|
if (!prop) {
|
|
984
974
|
throw new Error(`Trying to join ${q(field)}, but ${q(fromField)} is not a defined relation on ${meta.className}.`);
|
|
985
975
|
}
|
|
986
|
-
this.createAlias(prop.
|
|
976
|
+
this.createAlias(prop.targetMeta.class, alias);
|
|
987
977
|
cond = QueryHelper.processWhere({
|
|
988
978
|
where: cond,
|
|
989
979
|
entityName: this.mainAlias.entityName,
|
|
@@ -992,10 +982,10 @@ export class QueryBuilder {
|
|
|
992
982
|
aliasMap: this.getAliasMap(),
|
|
993
983
|
aliased: [QueryType.SELECT, QueryType.COUNT].includes(this.type),
|
|
994
984
|
});
|
|
995
|
-
const criteriaNode = CriteriaNodeFactory.createNode(this.metadata, prop.targetMeta.
|
|
985
|
+
const criteriaNode = CriteriaNodeFactory.createNode(this.metadata, prop.targetMeta.class, cond);
|
|
996
986
|
cond = criteriaNode.process(this, { ignoreBranching: true, alias });
|
|
997
987
|
let aliasedName = `${fromAlias}.${prop.name}#${alias}`;
|
|
998
|
-
path ??= `${(Object.values(this._joins).find(j => j.alias === fromAlias)?.path ?? entityName)}.${prop.name}`;
|
|
988
|
+
path ??= `${(Object.values(this._joins).find(j => j.alias === fromAlias)?.path ?? Utils.className(entityName))}.${prop.name}`;
|
|
999
989
|
if (prop.kind === ReferenceKind.ONE_TO_MANY) {
|
|
1000
990
|
this._joins[aliasedName] = this.helper.joinOneToReference(prop, fromAlias, alias, type, cond, schema);
|
|
1001
991
|
this._joins[aliasedName].path ??= path;
|
|
@@ -1029,11 +1019,6 @@ export class QueryBuilder {
|
|
|
1029
1019
|
return this.helper.mapper(name, this.type, undefined, type === 'groupBy' ? null : undefined);
|
|
1030
1020
|
};
|
|
1031
1021
|
fields.forEach(field => {
|
|
1032
|
-
const rawField = RawQueryFragment.getKnownFragment(field, false);
|
|
1033
|
-
if (rawField) {
|
|
1034
|
-
ret.push(rawField);
|
|
1035
|
-
return;
|
|
1036
|
-
}
|
|
1037
1022
|
if (typeof field !== 'string') {
|
|
1038
1023
|
ret.push(field);
|
|
1039
1024
|
return;
|
|
@@ -1078,9 +1063,7 @@ export class QueryBuilder {
|
|
|
1078
1063
|
}
|
|
1079
1064
|
ret.push(getFieldName(field));
|
|
1080
1065
|
});
|
|
1081
|
-
const
|
|
1082
|
-
/* v8 ignore next */
|
|
1083
|
-
const requiresSQLConversion = meta?.props.filter(p => p.hasConvertToJSValueSQL && p.persist !== false) ?? [];
|
|
1066
|
+
const requiresSQLConversion = this.mainAlias.meta.props.filter(p => p.hasConvertToJSValueSQL && p.persist !== false);
|
|
1084
1067
|
if (this.flags.has(QueryFlag.CONVERT_CUSTOM_TYPES) && (fields.includes('*') || fields.includes(`${this.mainAlias.aliasName}.*`)) && requiresSQLConversion.length > 0) {
|
|
1085
1068
|
for (const p of requiresSQLConversion) {
|
|
1086
1069
|
ret.push(this.helper.mapper(p.name, this.type));
|
|
@@ -1088,10 +1071,7 @@ export class QueryBuilder {
|
|
|
1088
1071
|
}
|
|
1089
1072
|
for (const f of Object.keys(this._populateMap)) {
|
|
1090
1073
|
if (type === 'where' && this._joins[f]) {
|
|
1091
|
-
|
|
1092
|
-
for (const col of cols) {
|
|
1093
|
-
ret.push(col);
|
|
1094
|
-
}
|
|
1074
|
+
ret.push(...this.helper.mapJoinColumns(this.type, this._joins[f]));
|
|
1095
1075
|
}
|
|
1096
1076
|
}
|
|
1097
1077
|
return Utils.unique(ret);
|
|
@@ -1118,14 +1098,14 @@ export class QueryBuilder {
|
|
|
1118
1098
|
}
|
|
1119
1099
|
getQueryBase(processVirtualEntity) {
|
|
1120
1100
|
const qb = this.platform.createNativeQueryBuilder().setFlags(this.flags);
|
|
1121
|
-
const { subQuery, aliasName, entityName,
|
|
1101
|
+
const { subQuery, aliasName, entityName, meta } = this.mainAlias;
|
|
1122
1102
|
const requiresAlias = this.finalized && (this._explicitAlias || this.helper.isTableNameAliasRequired(this.type));
|
|
1123
1103
|
const alias = requiresAlias ? aliasName : undefined;
|
|
1124
1104
|
const schema = this.getSchema(this.mainAlias);
|
|
1125
1105
|
const tableName = subQuery ? subQuery.as(aliasName) : this.helper.getTableName(entityName);
|
|
1126
1106
|
const joinSchema = this._schema ?? this.em?.schema ?? schema;
|
|
1127
|
-
if (
|
|
1128
|
-
qb.from(raw(this.fromVirtual(
|
|
1107
|
+
if (meta.virtual && processVirtualEntity) {
|
|
1108
|
+
qb.from(raw(this.fromVirtual(meta)), { indexHint: this._indexHint });
|
|
1129
1109
|
}
|
|
1130
1110
|
else {
|
|
1131
1111
|
qb.from(tableName, {
|
|
@@ -1169,19 +1149,19 @@ export class QueryBuilder {
|
|
|
1169
1149
|
return qb;
|
|
1170
1150
|
}
|
|
1171
1151
|
applyDiscriminatorCondition() {
|
|
1172
|
-
const meta = this.mainAlias.
|
|
1173
|
-
if (!meta
|
|
1152
|
+
const meta = this.mainAlias.meta;
|
|
1153
|
+
if (!meta.discriminatorValue) {
|
|
1174
1154
|
return;
|
|
1175
1155
|
}
|
|
1176
|
-
const types = Object.values(meta.root.discriminatorMap).map(cls => this.metadata.
|
|
1156
|
+
const types = Object.values(meta.root.discriminatorMap).map(cls => this.metadata.get(cls));
|
|
1177
1157
|
const children = [];
|
|
1178
1158
|
const lookUpChildren = (ret, type) => {
|
|
1179
1159
|
const children = types.filter(meta2 => meta2.extends === type);
|
|
1180
|
-
children.forEach(m => lookUpChildren(ret, m.
|
|
1160
|
+
children.forEach(m => lookUpChildren(ret, m.class));
|
|
1181
1161
|
ret.push(...children.filter(c => c.discriminatorValue));
|
|
1182
1162
|
return children;
|
|
1183
1163
|
};
|
|
1184
|
-
lookUpChildren(children, meta.
|
|
1164
|
+
lookUpChildren(children, meta.class);
|
|
1185
1165
|
this.andWhere({
|
|
1186
1166
|
[meta.root.discriminatorColumn]: children.length > 0 ? { $in: [meta.discriminatorValue, ...children.map(c => c.discriminatorValue)] } : meta.discriminatorValue,
|
|
1187
1167
|
});
|
|
@@ -1193,7 +1173,7 @@ export class QueryBuilder {
|
|
|
1193
1173
|
if (!this._type) {
|
|
1194
1174
|
this.select('*');
|
|
1195
1175
|
}
|
|
1196
|
-
const meta = this.mainAlias.
|
|
1176
|
+
const meta = this.mainAlias.meta;
|
|
1197
1177
|
this.applyDiscriminatorCondition();
|
|
1198
1178
|
this.processPopulateHint();
|
|
1199
1179
|
this.processNestedJoins();
|
|
@@ -1206,7 +1186,7 @@ export class QueryBuilder {
|
|
|
1206
1186
|
return `${prop.formula(alias)} as ${aliased}`;
|
|
1207
1187
|
})
|
|
1208
1188
|
.filter(field => !this._fields.some(f => {
|
|
1209
|
-
if (f
|
|
1189
|
+
if (isRaw(f)) {
|
|
1210
1190
|
return f.sql === field && f.params.length === 0;
|
|
1211
1191
|
}
|
|
1212
1192
|
return f === field;
|
|
@@ -1233,7 +1213,7 @@ export class QueryBuilder {
|
|
|
1233
1213
|
if (this.populateHintFinalized) {
|
|
1234
1214
|
return;
|
|
1235
1215
|
}
|
|
1236
|
-
const meta = this.mainAlias.
|
|
1216
|
+
const meta = this.mainAlias.meta;
|
|
1237
1217
|
if (meta && this.flags.has(QueryFlag.AUTO_JOIN_ONE_TO_ONE_OWNER)) {
|
|
1238
1218
|
const relationsToPopulate = this._populate.map(({ field }) => field);
|
|
1239
1219
|
meta.relations
|
|
@@ -1251,12 +1231,12 @@ export class QueryBuilder {
|
|
|
1251
1231
|
}
|
|
1252
1232
|
if (meta && this.helper.isOneToOneInverse(fromField)) {
|
|
1253
1233
|
const prop = meta.properties[fromField];
|
|
1254
|
-
const alias = this.getNextAlias(prop.pivotEntity ?? prop.
|
|
1234
|
+
const alias = this.getNextAlias(prop.pivotEntity ?? prop.targetMeta.class);
|
|
1255
1235
|
const aliasedName = `${fromAlias}.${prop.name}#${alias}`;
|
|
1256
1236
|
this._joins[aliasedName] = this.helper.joinOneToReference(prop, this.mainAlias.aliasName, alias, JoinType.leftJoin);
|
|
1257
1237
|
this._joins[aliasedName].path = `${(Object.values(this._joins).find(j => j.alias === fromAlias)?.path ?? meta.className)}.${prop.name}`;
|
|
1258
1238
|
this._populateMap[aliasedName] = this._joins[aliasedName].alias;
|
|
1259
|
-
this.createAlias(prop.
|
|
1239
|
+
this.createAlias(prop.targetMeta.class, alias);
|
|
1260
1240
|
}
|
|
1261
1241
|
});
|
|
1262
1242
|
this.processPopulateWhere(false);
|
|
@@ -1372,11 +1352,10 @@ export class QueryBuilder {
|
|
|
1372
1352
|
if (this._orderBy.length > 0) {
|
|
1373
1353
|
const orderBy = [];
|
|
1374
1354
|
for (const orderMap of this._orderBy) {
|
|
1375
|
-
for (const
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
orderBy.push({ [rawField.clone()]: direction });
|
|
1355
|
+
for (const field of Utils.getObjectQueryKeys(orderMap)) {
|
|
1356
|
+
const direction = orderMap[field];
|
|
1357
|
+
if (RawQueryFragment.isKnownFragmentSymbol(field)) {
|
|
1358
|
+
orderBy.push({ [field]: direction });
|
|
1380
1359
|
continue;
|
|
1381
1360
|
}
|
|
1382
1361
|
const [a, f] = this.helper.splitField(field);
|
|
@@ -1401,14 +1380,14 @@ export class QueryBuilder {
|
|
|
1401
1380
|
if (typeof field === 'object' && field && '__as' in field) {
|
|
1402
1381
|
return field.__as === prop;
|
|
1403
1382
|
}
|
|
1404
|
-
if (field
|
|
1383
|
+
if (isRaw(field)) {
|
|
1405
1384
|
// not perfect, but should work most of the time, ideally we should check only the alias (`... as alias`)
|
|
1406
1385
|
return field.sql.includes(prop);
|
|
1407
1386
|
}
|
|
1408
1387
|
return false;
|
|
1409
1388
|
});
|
|
1410
1389
|
/* v8 ignore next */
|
|
1411
|
-
if (field
|
|
1390
|
+
if (isRaw(field)) {
|
|
1412
1391
|
innerQuery.select(field);
|
|
1413
1392
|
}
|
|
1414
1393
|
else if (field instanceof NativeQueryBuilder) {
|
|
@@ -1425,7 +1404,7 @@ export class QueryBuilder {
|
|
|
1425
1404
|
subSubQuery.select(pks).from(innerQuery);
|
|
1426
1405
|
this._limit = undefined;
|
|
1427
1406
|
this._offset = undefined;
|
|
1428
|
-
if (!this._fields.some(
|
|
1407
|
+
if (!this._fields.some(field => isRaw(field))) {
|
|
1429
1408
|
this.pruneExtraJoins(meta);
|
|
1430
1409
|
}
|
|
1431
1410
|
const { sql, params } = subSubQuery.compile();
|
|
@@ -1483,8 +1462,8 @@ export class QueryBuilder {
|
|
|
1483
1462
|
});
|
|
1484
1463
|
}
|
|
1485
1464
|
getSchema(alias) {
|
|
1486
|
-
const {
|
|
1487
|
-
const metaSchema =
|
|
1465
|
+
const { meta } = alias;
|
|
1466
|
+
const metaSchema = meta.schema && meta.schema !== '*' ? meta.schema : undefined;
|
|
1488
1467
|
const schema = this._schema ?? metaSchema ?? this.em?.schema ?? this.em?.config.getSchema(true);
|
|
1489
1468
|
if (schema === this.platform.getDefaultSchemaName()) {
|
|
1490
1469
|
return undefined;
|
|
@@ -1492,8 +1471,8 @@ export class QueryBuilder {
|
|
|
1492
1471
|
return schema;
|
|
1493
1472
|
}
|
|
1494
1473
|
createAlias(entityName, aliasName, subQuery) {
|
|
1495
|
-
const
|
|
1496
|
-
const alias = { aliasName, entityName,
|
|
1474
|
+
const meta = this.metadata.find(entityName);
|
|
1475
|
+
const alias = { aliasName, entityName, meta, subQuery };
|
|
1497
1476
|
this._aliases[aliasName] = alias;
|
|
1498
1477
|
return alias;
|
|
1499
1478
|
}
|
|
@@ -1551,7 +1530,7 @@ export class QueryBuilder {
|
|
|
1551
1530
|
if (!Utils.isEmpty(this._orderBy)) {
|
|
1552
1531
|
object.orderBy = this._orderBy;
|
|
1553
1532
|
}
|
|
1554
|
-
const name = this._mainAlias ? `${prefix}QueryBuilder<${this._mainAlias?.entityName}>` : 'QueryBuilder';
|
|
1533
|
+
const name = this._mainAlias ? `${prefix}QueryBuilder<${Utils.className(this._mainAlias?.entityName)}>` : 'QueryBuilder';
|
|
1555
1534
|
const ret = inspect(object, { depth });
|
|
1556
1535
|
return ret === '[Object]' ? `[${name}]` : name + ' ' + ret;
|
|
1557
1536
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Dictionary, type EntityData, type EntityKey, type EntityMetadata, type EntityProperty, type FlatQueryOrderMap, LockMode, type QBFilterQuery,
|
|
1
|
+
import { type Dictionary, type EntityData, type EntityKey, type EntityMetadata, type EntityName, type EntityProperty, type FlatQueryOrderMap, LockMode, type QBFilterQuery, type QBQueryOrderMap, Raw, type RawQueryFragmentSymbol } from '@mikro-orm/core';
|
|
2
2
|
import { JoinType, QueryType } from './enums.js';
|
|
3
3
|
import type { Field, JoinOptions } from '../typings.js';
|
|
4
4
|
import type { AbstractSqlDriver } from '../AbstractSqlDriver.js';
|
|
@@ -14,9 +14,9 @@ export declare class QueryBuilderHelper {
|
|
|
14
14
|
private readonly driver;
|
|
15
15
|
private readonly platform;
|
|
16
16
|
private readonly metadata;
|
|
17
|
-
constructor(entityName:
|
|
18
|
-
mapper(field: string |
|
|
19
|
-
mapper(field: string |
|
|
17
|
+
constructor(entityName: EntityName, alias: string, aliasMap: Dictionary<Alias<any>>, subQueries: Dictionary<string>, driver: AbstractSqlDriver);
|
|
18
|
+
mapper(field: string | Raw | RawQueryFragmentSymbol, type?: QueryType): string;
|
|
19
|
+
mapper(field: string | Raw | RawQueryFragmentSymbol, type?: QueryType, value?: any, alias?: string | null): string;
|
|
20
20
|
processData(data: Dictionary, convertCustomTypes: boolean, multi?: boolean): any;
|
|
21
21
|
joinOneToReference(prop: EntityProperty, ownerAlias: string, alias: string, type: JoinType, cond?: Dictionary, schema?: string): JoinOptions;
|
|
22
22
|
joinManyToOneReference(prop: EntityProperty, ownerAlias: string, alias: string, type: JoinType, cond?: Dictionary, schema?: string): JoinOptions;
|
|
@@ -26,9 +26,9 @@ export declare class QueryBuilderHelper {
|
|
|
26
26
|
sql: string;
|
|
27
27
|
params: unknown[];
|
|
28
28
|
};
|
|
29
|
-
mapJoinColumns(type: QueryType, join: JoinOptions): (string |
|
|
29
|
+
mapJoinColumns(type: QueryType, join: JoinOptions): (string | Raw)[];
|
|
30
30
|
isOneToOneInverse(field: string, meta?: EntityMetadata): boolean;
|
|
31
|
-
getTableName(entityName:
|
|
31
|
+
getTableName(entityName: EntityName): string;
|
|
32
32
|
/**
|
|
33
33
|
* Checks whether the RE can be rewritten to simple LIKE query
|
|
34
34
|
*/
|
|
@@ -45,6 +45,7 @@ export declare class QueryBuilderHelper {
|
|
|
45
45
|
private processObjectSubCondition;
|
|
46
46
|
private getValueReplacement;
|
|
47
47
|
private getOperatorReplacement;
|
|
48
|
+
validateQueryOrder<T>(orderBy: QBQueryOrderMap<T>): void;
|
|
48
49
|
getQueryOrder(type: QueryType, orderBy: FlatQueryOrderMap | FlatQueryOrderMap[], populate: Dictionary<string>): string[];
|
|
49
50
|
getQueryOrderFromObject(type: QueryType, orderBy: FlatQueryOrderMap, populate: Dictionary<string>): string[];
|
|
50
51
|
finalize(type: QueryType, qb: NativeQueryBuilder, meta?: EntityMetadata, data?: Dictionary, returning?: Field<any>[]): void;
|
|
@@ -61,12 +62,12 @@ export declare class QueryBuilderHelper {
|
|
|
61
62
|
}
|
|
62
63
|
export interface Alias<T> {
|
|
63
64
|
aliasName: string;
|
|
64
|
-
entityName:
|
|
65
|
-
|
|
65
|
+
entityName: EntityName<T>;
|
|
66
|
+
meta: EntityMetadata<T>;
|
|
66
67
|
subQuery?: NativeQueryBuilder;
|
|
67
68
|
}
|
|
68
69
|
export interface OnConflictClause<T> {
|
|
69
|
-
fields: string[] |
|
|
70
|
+
fields: string[] | Raw;
|
|
70
71
|
ignore?: boolean;
|
|
71
72
|
merge?: EntityData<T> | Field<T>[];
|
|
72
73
|
where?: QBFilterQuery<T>;
|