@mikro-orm/core 7.0.0-dev.300 → 7.0.0-dev.301
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/EntityManager.d.ts +1 -1
- package/EntityManager.js +94 -43
- package/MikroORM.js +4 -4
- package/cache/FileCacheAdapter.js +1 -3
- package/connections/Connection.js +16 -3
- package/drivers/DatabaseDriver.js +25 -7
- package/entity/Collection.js +43 -17
- package/entity/EntityAssigner.js +23 -11
- package/entity/EntityFactory.js +32 -12
- package/entity/EntityHelper.js +12 -8
- package/entity/EntityLoader.js +55 -22
- package/entity/Reference.d.ts +1 -1
- package/entity/Reference.js +37 -8
- package/entity/WrappedEntity.js +5 -1
- package/entity/defineEntity.d.ts +5 -7
- package/entity/utils.js +28 -26
- package/entity/validators.js +2 -1
- package/enums.js +12 -17
- package/errors.js +18 -8
- package/events/EventManager.js +1 -1
- package/exceptions.js +7 -2
- package/hydration/ObjectHydrator.js +27 -13
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/logging/DefaultLogger.js +3 -5
- package/logging/colors.js +3 -6
- package/metadata/EntitySchema.js +12 -2
- package/metadata/MetadataDiscovery.js +101 -46
- package/metadata/MetadataProvider.js +6 -1
- package/metadata/MetadataStorage.js +1 -3
- package/metadata/MetadataValidator.js +20 -5
- package/metadata/types.d.ts +2 -2
- package/naming-strategy/AbstractNamingStrategy.js +5 -2
- package/not-supported.js +5 -1
- package/package.json +38 -38
- package/platforms/Platform.js +46 -23
- package/serialization/EntitySerializer.js +7 -3
- package/serialization/SerializationContext.js +1 -1
- package/typings.d.ts +23 -23
- package/typings.js +9 -9
- package/unit-of-work/ChangeSet.js +4 -4
- package/unit-of-work/ChangeSetComputer.js +8 -6
- package/unit-of-work/ChangeSetPersister.js +13 -8
- package/unit-of-work/CommitOrderCalculator.js +4 -2
- package/unit-of-work/UnitOfWork.d.ts +7 -1
- package/unit-of-work/UnitOfWork.js +51 -22
- package/utils/AbstractMigrator.js +3 -5
- package/utils/AbstractSchemaGenerator.js +2 -1
- package/utils/AsyncContext.js +1 -1
- package/utils/Configuration.js +8 -4
- package/utils/Cursor.js +4 -2
- package/utils/DataloaderUtils.js +15 -12
- package/utils/EntityComparator.js +51 -43
- package/utils/QueryHelper.js +38 -26
- package/utils/RawQueryFragment.js +3 -2
- package/utils/TransactionManager.js +2 -1
- package/utils/Utils.d.ts +1 -1
- package/utils/Utils.js +36 -30
- package/utils/env-vars.js +6 -5
- package/utils/fs-utils.js +2 -5
- package/utils/upsert-utils.js +6 -3
package/EntityManager.d.ts
CHANGED
|
@@ -594,7 +594,7 @@ export interface MergeOptions {
|
|
|
594
594
|
schema?: string;
|
|
595
595
|
disableContextResolution?: boolean;
|
|
596
596
|
validate?: boolean;
|
|
597
|
-
cascade?: boolean
|
|
597
|
+
cascade?: boolean /** @default true */;
|
|
598
598
|
}
|
|
599
599
|
export interface ForkOptions {
|
|
600
600
|
/** do we want a clear identity map? defaults to true */
|
package/EntityManager.js
CHANGED
|
@@ -123,7 +123,7 @@ export class EntityManager {
|
|
|
123
123
|
else {
|
|
124
124
|
options.orderBy ??= {};
|
|
125
125
|
}
|
|
126
|
-
options.populate = await em.preparePopulate(entityName, options);
|
|
126
|
+
options.populate = (await em.preparePopulate(entityName, options));
|
|
127
127
|
const populate = options.populate;
|
|
128
128
|
const cacheKey = em.cacheKey(entityName, options, 'em.find', where);
|
|
129
129
|
const cached = await em.tryCache(entityName, options.cache, cacheKey, options.refresh, true);
|
|
@@ -195,10 +195,10 @@ export class EntityManager {
|
|
|
195
195
|
em.prepareOptions(options);
|
|
196
196
|
options.strategy = 'joined';
|
|
197
197
|
await em.tryFlush(entityName, options);
|
|
198
|
-
const where = await em.processWhere(entityName, options.where ?? {}, options, 'read');
|
|
198
|
+
const where = (await em.processWhere(entityName, options.where ?? {}, options, 'read'));
|
|
199
199
|
validateParams(where);
|
|
200
200
|
options.orderBy = options.orderBy || {};
|
|
201
|
-
options.populate = await em.preparePopulate(entityName, options);
|
|
201
|
+
options.populate = (await em.preparePopulate(entityName, options));
|
|
202
202
|
const meta = this.metadata.get(entityName);
|
|
203
203
|
options = { ...options };
|
|
204
204
|
// save the original hint value so we know it was infer/all
|
|
@@ -304,7 +304,7 @@ export class EntityManager {
|
|
|
304
304
|
if (!this.driver.getPlatform().supportsUnionWhere()) {
|
|
305
305
|
throw new Error(`unionWhere is only supported on SQL drivers`);
|
|
306
306
|
}
|
|
307
|
-
options.unionWhere = await Promise.all(options.unionWhere.map(branch => this.processWhere(entityName, branch, options, type)));
|
|
307
|
+
options.unionWhere = (await Promise.all(options.unionWhere.map(branch => this.processWhere(entityName, branch, options, type))));
|
|
308
308
|
}
|
|
309
309
|
}
|
|
310
310
|
// this method only handles the problem for mongo driver, SQL drivers have their implementation inside QueryBuilder
|
|
@@ -323,7 +323,10 @@ export class EntityManager {
|
|
|
323
323
|
};
|
|
324
324
|
lookUpChildren(children, meta.class);
|
|
325
325
|
/* v8 ignore next */
|
|
326
|
-
where[meta.root.discriminatorColumn] =
|
|
326
|
+
where[meta.root.discriminatorColumn] =
|
|
327
|
+
children.length > 0
|
|
328
|
+
? { $in: [meta.discriminatorValue, ...children.map(c => c.discriminatorValue)] }
|
|
329
|
+
: meta.discriminatorValue;
|
|
327
330
|
return where;
|
|
328
331
|
}
|
|
329
332
|
createPopulateWhere(cond, options) {
|
|
@@ -390,10 +393,11 @@ export class EntityManager {
|
|
|
390
393
|
}
|
|
391
394
|
const ret = options.populate;
|
|
392
395
|
for (const prop of meta.relations) {
|
|
393
|
-
if (prop.object
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
396
|
+
if (prop.object ||
|
|
397
|
+
![ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) ||
|
|
398
|
+
!((options.fields?.length ?? 0) === 0 ||
|
|
399
|
+
options.fields?.some(f => prop.name === f || prop.name.startsWith(`${String(f)}.`))) ||
|
|
400
|
+
(parent?.class === prop.targetMeta.root.class && parent.propName === prop.inversedBy)) {
|
|
397
401
|
continue;
|
|
398
402
|
}
|
|
399
403
|
options = { ...options, filters: QueryHelper.mergePropertyFilters(prop.filters, options.filters) };
|
|
@@ -433,9 +437,7 @@ export class EntityManager {
|
|
|
433
437
|
const ret = [];
|
|
434
438
|
const active = new Set();
|
|
435
439
|
const push = (source) => {
|
|
436
|
-
const activeFilters = QueryHelper
|
|
437
|
-
.getActiveFilters(meta, options, source)
|
|
438
|
-
.filter(f => !active.has(f.name));
|
|
440
|
+
const activeFilters = QueryHelper.getActiveFilters(meta, options, source).filter(f => !active.has(f.name));
|
|
439
441
|
filters.push(...activeFilters);
|
|
440
442
|
activeFilters.forEach(f => active.add(f.name));
|
|
441
443
|
};
|
|
@@ -449,6 +451,7 @@ export class EntityManager {
|
|
|
449
451
|
let cond;
|
|
450
452
|
if (filter.cond instanceof Function) {
|
|
451
453
|
// @ts-ignore
|
|
454
|
+
// oxfmt-ignore
|
|
452
455
|
const args = Utils.isPlainObject(options?.[filter.name]) ? options[filter.name] : this.getContext().filterParams[filter.name];
|
|
453
456
|
if (!args && filter.cond.length > 0 && filter.args !== false) {
|
|
454
457
|
throw new Error(`No arguments provided for filter '${filter.name}'`);
|
|
@@ -591,12 +594,18 @@ export class EntityManager {
|
|
|
591
594
|
for (const e of fork.unitOfWork.getIdentityMap()) {
|
|
592
595
|
const ref = em.getReference(e.constructor, helper(e).getPrimaryKey());
|
|
593
596
|
const data = helper(e).serialize({ ignoreSerializers: true, includeHidden: true, convertCustomTypes: false });
|
|
594
|
-
em.config
|
|
597
|
+
em.config
|
|
598
|
+
.getHydrator(this.metadata)
|
|
599
|
+
.hydrate(ref, helper(ref).__meta, data, em.entityFactory, 'full', false, false);
|
|
595
600
|
Utils.merge(helper(ref).__originalEntityData, this.comparator.prepareEntity(e));
|
|
596
601
|
found ||= ref === entity;
|
|
597
602
|
}
|
|
598
603
|
if (!found) {
|
|
599
|
-
const data = helper(reloaded).serialize({
|
|
604
|
+
const data = helper(reloaded).serialize({
|
|
605
|
+
ignoreSerializers: true,
|
|
606
|
+
includeHidden: true,
|
|
607
|
+
convertCustomTypes: true,
|
|
608
|
+
});
|
|
600
609
|
em.config.getHydrator(this.metadata).hydrate(entity, wrapped.__meta, data, em.entityFactory, 'full', false, true);
|
|
601
610
|
Utils.merge(wrapped.__originalEntityData, this.comparator.prepareEntity(reloaded));
|
|
602
611
|
}
|
|
@@ -632,7 +641,7 @@ export class EntityManager {
|
|
|
632
641
|
return em.lockAndPopulate(meta, entity, where, options);
|
|
633
642
|
}
|
|
634
643
|
validateParams(where);
|
|
635
|
-
options.populate = await em.preparePopulate(entityName, options);
|
|
644
|
+
options.populate = (await em.preparePopulate(entityName, options));
|
|
636
645
|
const cacheKey = em.cacheKey(entityName, options, 'em.findOne', where);
|
|
637
646
|
const cached = await em.tryCache(entityName, options.cache, cacheKey, options.refresh, true);
|
|
638
647
|
if (cached?.data !== undefined) {
|
|
@@ -780,9 +789,12 @@ export class EntityManager {
|
|
|
780
789
|
initialized: true,
|
|
781
790
|
schema: options.schema,
|
|
782
791
|
});
|
|
783
|
-
const uniqueFields = options.onConflictFields ??
|
|
792
|
+
const uniqueFields = options.onConflictFields ??
|
|
793
|
+
(Utils.isPlainObject(where) ? Object.keys(where) : meta.primaryKeys);
|
|
784
794
|
const returning = getOnConflictReturningFields(meta, data, uniqueFields, options);
|
|
785
|
-
if (options.onConflictAction === 'ignore' ||
|
|
795
|
+
if (options.onConflictAction === 'ignore' ||
|
|
796
|
+
!helper(entity).hasPrimaryKey() ||
|
|
797
|
+
(returning.length > 0 && !(this.getPlatform().usesReturningStatement() && ret.row))) {
|
|
786
798
|
const where = {};
|
|
787
799
|
if (Array.isArray(uniqueFields)) {
|
|
788
800
|
for (const prop of uniqueFields) {
|
|
@@ -906,7 +918,9 @@ export class EntityManager {
|
|
|
906
918
|
}
|
|
907
919
|
}
|
|
908
920
|
const unique = options.onConflictFields ?? meta.props.filter(p => p.unique).map(p => p.name);
|
|
909
|
-
propIndex =
|
|
921
|
+
propIndex =
|
|
922
|
+
!isRaw(unique) &&
|
|
923
|
+
unique.findIndex(p => data[p] ?? data[p.substring(0, p.indexOf('.'))] != null);
|
|
910
924
|
const tmp = getWhereCondition(meta, options.onConflictFields, row, where);
|
|
911
925
|
propIndex = tmp.propIndex;
|
|
912
926
|
where = QueryHelper.processWhere({
|
|
@@ -939,12 +953,16 @@ export class EntityManager {
|
|
|
939
953
|
entitiesByData.clear();
|
|
940
954
|
const loadPK = new Map();
|
|
941
955
|
allData.forEach((row, i) => {
|
|
942
|
-
em.unitOfWork
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
956
|
+
em.unitOfWork
|
|
957
|
+
.getChangeSetPersister()
|
|
958
|
+
.mapReturnedValues(Utils.isEntity(data[i]) ? data[i] : null, Utils.isEntity(data[i]) ? {} : data[i], res.rows?.[i], meta, true);
|
|
959
|
+
const entity = Utils.isEntity(data[i])
|
|
960
|
+
? data[i]
|
|
961
|
+
: em.entityFactory.create(entityName, row, {
|
|
962
|
+
refresh: true,
|
|
963
|
+
initialized: true,
|
|
964
|
+
schema: options.schema,
|
|
965
|
+
});
|
|
948
966
|
if (!helper(entity).hasPrimaryKey()) {
|
|
949
967
|
loadPK.set(entity, allWhere[i]);
|
|
950
968
|
}
|
|
@@ -952,12 +970,15 @@ export class EntityManager {
|
|
|
952
970
|
entitiesByData.set(row, entity);
|
|
953
971
|
});
|
|
954
972
|
// skip if we got the PKs via returning statement (`rows`)
|
|
973
|
+
// oxfmt-ignore
|
|
955
974
|
const uniqueFields = options.onConflictFields ?? (Utils.isPlainObject(allWhere[0]) ? Object.keys(allWhere[0]).flatMap(key => Utils.splitPrimaryKeys(key)) : meta.primaryKeys);
|
|
956
975
|
const returning = getOnConflictReturningFields(meta, data[0], uniqueFields, options);
|
|
957
976
|
const reloadFields = returning.length > 0 && !(this.getPlatform().usesReturningStatement() && res.rows?.length);
|
|
958
977
|
if (options.onConflictAction === 'ignore' || (!res.rows?.length && loadPK.size > 0) || reloadFields) {
|
|
959
978
|
const unique = meta.hydrateProps.filter(p => !p.lazy).map(p => p.name);
|
|
960
|
-
const add = new Set(propIndex !== false && propIndex >= 0
|
|
979
|
+
const add = new Set(propIndex !== false && propIndex >= 0
|
|
980
|
+
? [unique[propIndex]]
|
|
981
|
+
: []);
|
|
961
982
|
for (const cond of loadPK.values()) {
|
|
962
983
|
Utils.keys(cond).forEach(key => add.add(key));
|
|
963
984
|
}
|
|
@@ -970,7 +991,9 @@ export class EntityManager {
|
|
|
970
991
|
});
|
|
971
992
|
});
|
|
972
993
|
const data2 = await this.driver.find(meta.class, where, {
|
|
973
|
-
fields: returning
|
|
994
|
+
fields: returning
|
|
995
|
+
.concat(...add)
|
|
996
|
+
.concat(...(Array.isArray(uniqueFields) ? uniqueFields : [])),
|
|
974
997
|
ctx: em.transactionContext,
|
|
975
998
|
convertCustomTypes: true,
|
|
976
999
|
connectionType: 'write',
|
|
@@ -1146,7 +1169,10 @@ export class EntityManager {
|
|
|
1146
1169
|
}
|
|
1147
1170
|
data = QueryHelper.processObjectParams(data);
|
|
1148
1171
|
validateParams(data, 'insert data');
|
|
1149
|
-
const res = await em.driver.nativeInsert(entityName, data, {
|
|
1172
|
+
const res = await em.driver.nativeInsert(entityName, data, {
|
|
1173
|
+
ctx: em.transactionContext,
|
|
1174
|
+
...options,
|
|
1175
|
+
});
|
|
1150
1176
|
return res.insertId;
|
|
1151
1177
|
}
|
|
1152
1178
|
/**
|
|
@@ -1186,7 +1212,10 @@ export class EntityManager {
|
|
|
1186
1212
|
}
|
|
1187
1213
|
data = data.map(row => QueryHelper.processObjectParams(row));
|
|
1188
1214
|
data.forEach(row => validateParams(row, 'insert data'));
|
|
1189
|
-
const res = await em.driver.nativeInsertMany(entityName, data, {
|
|
1215
|
+
const res = await em.driver.nativeInsertMany(entityName, data, {
|
|
1216
|
+
ctx: em.transactionContext,
|
|
1217
|
+
...options,
|
|
1218
|
+
});
|
|
1190
1219
|
if (res.insertedIds) {
|
|
1191
1220
|
return res.insertedIds;
|
|
1192
1221
|
}
|
|
@@ -1203,7 +1232,11 @@ export class EntityManager {
|
|
|
1203
1232
|
where = await em.processWhere(entityName, where, { ...options, convertCustomTypes: false }, 'update');
|
|
1204
1233
|
validateParams(data, 'update data');
|
|
1205
1234
|
validateParams(where, 'update condition');
|
|
1206
|
-
const res = await em.driver.nativeUpdate(entityName, where, data, {
|
|
1235
|
+
const res = await em.driver.nativeUpdate(entityName, where, data, {
|
|
1236
|
+
ctx: em.transactionContext,
|
|
1237
|
+
em,
|
|
1238
|
+
...options,
|
|
1239
|
+
});
|
|
1207
1240
|
return res.affectedRows;
|
|
1208
1241
|
}
|
|
1209
1242
|
/**
|
|
@@ -1213,9 +1246,13 @@ export class EntityManager {
|
|
|
1213
1246
|
const em = this.getContext(false);
|
|
1214
1247
|
em.prepareOptions(options);
|
|
1215
1248
|
await em.processUnionWhere(entityName, options, 'delete');
|
|
1216
|
-
where = await em.processWhere(entityName, where, options, 'delete');
|
|
1249
|
+
where = (await em.processWhere(entityName, where, options, 'delete'));
|
|
1217
1250
|
validateParams(where, 'delete condition');
|
|
1218
|
-
const res = await em.driver.nativeDelete(entityName, where, {
|
|
1251
|
+
const res = await em.driver.nativeDelete(entityName, where, {
|
|
1252
|
+
ctx: em.transactionContext,
|
|
1253
|
+
em,
|
|
1254
|
+
...options,
|
|
1255
|
+
});
|
|
1219
1256
|
return res.affectedRows;
|
|
1220
1257
|
}
|
|
1221
1258
|
/**
|
|
@@ -1226,7 +1263,10 @@ export class EntityManager {
|
|
|
1226
1263
|
const data = this.driver.mapResult(result, meta);
|
|
1227
1264
|
for (const k of Object.keys(data)) {
|
|
1228
1265
|
const prop = meta.properties[k];
|
|
1229
|
-
if (prop?.kind === ReferenceKind.SCALAR &&
|
|
1266
|
+
if (prop?.kind === ReferenceKind.SCALAR &&
|
|
1267
|
+
SCALAR_TYPES.has(prop.runtimeType) &&
|
|
1268
|
+
!prop.customType &&
|
|
1269
|
+
(prop.setter || !prop.getter)) {
|
|
1230
1270
|
validateProperty(prop, data[k], data);
|
|
1231
1271
|
}
|
|
1232
1272
|
}
|
|
@@ -1255,7 +1295,9 @@ export class EntityManager {
|
|
|
1255
1295
|
return entity;
|
|
1256
1296
|
}
|
|
1257
1297
|
const dataIsEntity = Utils.isEntity(data);
|
|
1258
|
-
entity = dataIsEntity
|
|
1298
|
+
entity = dataIsEntity
|
|
1299
|
+
? data
|
|
1300
|
+
: em.entityFactory.create(entityName, data, { merge: true, ...options });
|
|
1259
1301
|
const visited = options.cascade ? undefined : new Set([entity]);
|
|
1260
1302
|
em.unitOfWork.merge(entity, visited);
|
|
1261
1303
|
return entity;
|
|
@@ -1325,7 +1367,7 @@ export class EntityManager {
|
|
|
1325
1367
|
em.prepareOptions(options);
|
|
1326
1368
|
await em.tryFlush(entityName, options);
|
|
1327
1369
|
where = await em.processWhere(entityName, where, options, 'read');
|
|
1328
|
-
options.populate = await em.preparePopulate(entityName, options);
|
|
1370
|
+
options.populate = (await em.preparePopulate(entityName, options));
|
|
1329
1371
|
options = { ...options };
|
|
1330
1372
|
// save the original hint value so we know it was infer/all
|
|
1331
1373
|
const meta = em.metadata.find(entityName);
|
|
@@ -1472,7 +1514,8 @@ export class EntityManager {
|
|
|
1472
1514
|
em.config.set('allowGlobalContext', true);
|
|
1473
1515
|
const fork = new em.constructor(em.config, em.driver, em.metadata, options.useContext, eventManager);
|
|
1474
1516
|
fork.setFlushMode(options.flushMode ?? em.flushMode);
|
|
1475
|
-
fork.disableTransactions =
|
|
1517
|
+
fork.disableTransactions =
|
|
1518
|
+
options.disableTransactions ?? this.disableTransactions ?? this.config.get('disableTransactions');
|
|
1476
1519
|
em.config.set('allowGlobalContext', allowGlobalContext);
|
|
1477
1520
|
if (options.keepTransactionContext) {
|
|
1478
1521
|
fork.transactionContext = em.transactionContext;
|
|
@@ -1639,11 +1682,14 @@ export class EntityManager {
|
|
|
1639
1682
|
const ret = [];
|
|
1640
1683
|
for (let field of fields) {
|
|
1641
1684
|
if (field === PopulatePath.ALL || field.startsWith(`${PopulatePath.ALL}.`)) {
|
|
1642
|
-
ret.push(...meta.props
|
|
1685
|
+
ret.push(...meta.props
|
|
1686
|
+
.filter(prop => prop.lazy || [ReferenceKind.SCALAR, ReferenceKind.EMBEDDED].includes(prop.kind))
|
|
1687
|
+
.map(prop => prop.name));
|
|
1643
1688
|
continue;
|
|
1644
1689
|
}
|
|
1645
1690
|
field = field.split(':')[0];
|
|
1646
|
-
if (!field.includes('.') &&
|
|
1691
|
+
if (!field.includes('.') &&
|
|
1692
|
+
![ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(meta.properties[field].kind)) {
|
|
1647
1693
|
ret.push(field);
|
|
1648
1694
|
continue;
|
|
1649
1695
|
}
|
|
@@ -1672,7 +1718,8 @@ export class EntityManager {
|
|
|
1672
1718
|
return populate;
|
|
1673
1719
|
}
|
|
1674
1720
|
if (typeof options.populate !== 'boolean') {
|
|
1675
|
-
options.populate = Utils.asArray(options.populate)
|
|
1721
|
+
options.populate = Utils.asArray(options.populate)
|
|
1722
|
+
.map(field => {
|
|
1676
1723
|
/* v8 ignore next */
|
|
1677
1724
|
if (typeof field === 'boolean' || field === PopulatePath.ALL) {
|
|
1678
1725
|
return [{ field: meta.primaryKeys[0], strategy: options.strategy, all: !!field }]; //
|
|
@@ -1687,7 +1734,8 @@ export class EntityManager {
|
|
|
1687
1734
|
return [{ field, strategy: options.strategy }];
|
|
1688
1735
|
}
|
|
1689
1736
|
return [field];
|
|
1690
|
-
})
|
|
1737
|
+
})
|
|
1738
|
+
.flat();
|
|
1691
1739
|
}
|
|
1692
1740
|
const populate = this.entityLoader.normalizePopulate(entityName, options.populate, options.strategy, true, options.exclude);
|
|
1693
1741
|
const invalid = populate.find(({ field }) => !this.canPopulate(entityName, field));
|
|
@@ -1789,7 +1837,7 @@ export class EntityManager {
|
|
|
1789
1837
|
config ??= this.config.get('resultCache').global;
|
|
1790
1838
|
if (config) {
|
|
1791
1839
|
const em = this.getContext();
|
|
1792
|
-
const expiration = Array.isArray(config) ? config[1] :
|
|
1840
|
+
const expiration = Array.isArray(config) ? config[1] : typeof config === 'number' ? config : undefined;
|
|
1793
1841
|
await em.resultCache.set(key.key, data instanceof Function ? data() : data, '', expiration);
|
|
1794
1842
|
}
|
|
1795
1843
|
}
|
|
@@ -1831,9 +1879,12 @@ export class EntityManager {
|
|
|
1831
1879
|
const { DataloaderUtils } = await import('@mikro-orm/core/dataloader');
|
|
1832
1880
|
const DataLoader = await DataloaderUtils.getDataLoader();
|
|
1833
1881
|
switch (type) {
|
|
1834
|
-
case 'ref':
|
|
1835
|
-
|
|
1836
|
-
case 'm
|
|
1882
|
+
case 'ref':
|
|
1883
|
+
return (em.loaders[type] ??= new DataLoader(DataloaderUtils.getRefBatchLoadFn(em)));
|
|
1884
|
+
case '1:m':
|
|
1885
|
+
return (em.loaders[type] ??= new DataLoader(DataloaderUtils.getColBatchLoadFn(em)));
|
|
1886
|
+
case 'm:n':
|
|
1887
|
+
return (em.loaders[type] ??= new DataLoader(DataloaderUtils.getManyToManyColBatchLoadFn(em)));
|
|
1837
1888
|
}
|
|
1838
1889
|
}
|
|
1839
1890
|
/**
|
package/MikroORM.js
CHANGED
|
@@ -104,9 +104,7 @@ export class MikroORM {
|
|
|
104
104
|
*/
|
|
105
105
|
constructor(options) {
|
|
106
106
|
const env = loadEnvironmentVars();
|
|
107
|
-
options = options.preferEnvVars
|
|
108
|
-
? Utils.merge(options, env)
|
|
109
|
-
: Utils.merge(env, options);
|
|
107
|
+
options = options.preferEnvVars ? Utils.merge(options, env) : Utils.merge(env, options);
|
|
110
108
|
this.config = new Configuration(options);
|
|
111
109
|
const discovery = this.config.get('discovery');
|
|
112
110
|
this.driver = this.config.getDriver();
|
|
@@ -213,6 +211,8 @@ export class MikroORM {
|
|
|
213
211
|
* Gets the EntityGenerator.
|
|
214
212
|
*/
|
|
215
213
|
get entityGenerator() {
|
|
216
|
-
return this.driver
|
|
214
|
+
return this.driver
|
|
215
|
+
.getPlatform()
|
|
216
|
+
.getExtension('EntityGenerator', '@mikro-orm/entity-generator', '@mikro-orm/entity-generator', this.em);
|
|
217
217
|
}
|
|
218
218
|
}
|
|
@@ -68,9 +68,7 @@ export class FileCacheAdapter {
|
|
|
68
68
|
if (!this.options.combined) {
|
|
69
69
|
return;
|
|
70
70
|
}
|
|
71
|
-
let path = typeof this.options.combined === 'string'
|
|
72
|
-
? this.options.combined
|
|
73
|
-
: './metadata.json';
|
|
71
|
+
let path = typeof this.options.combined === 'string' ? this.options.combined : './metadata.json';
|
|
74
72
|
path = fs.normalizePath(this.options.cacheDir, path);
|
|
75
73
|
this.options.combined = path; // override in the options, so we can log it from the CLI in `cache:generate` command
|
|
76
74
|
writeFileSync(path, JSON.stringify(this.cache, null, this.pretty ? 2 : undefined));
|
|
@@ -16,7 +16,18 @@ export class Connection {
|
|
|
16
16
|
this.options = Utils.copy(options);
|
|
17
17
|
}
|
|
18
18
|
else {
|
|
19
|
-
const props = [
|
|
19
|
+
const props = [
|
|
20
|
+
'dbName',
|
|
21
|
+
'clientUrl',
|
|
22
|
+
'host',
|
|
23
|
+
'port',
|
|
24
|
+
'user',
|
|
25
|
+
'password',
|
|
26
|
+
'multipleStatements',
|
|
27
|
+
'pool',
|
|
28
|
+
'schema',
|
|
29
|
+
'driverOptions',
|
|
30
|
+
];
|
|
20
31
|
this.options = props.reduce((o, i) => {
|
|
21
32
|
o[i] = this.config.get(i);
|
|
22
33
|
return o;
|
|
@@ -89,8 +100,10 @@ export class Connection {
|
|
|
89
100
|
this.options.host = ret.host = this.options.host ?? this.config.get('host', decodeURIComponent(url.hostname));
|
|
90
101
|
this.options.port = ret.port = this.options.port ?? this.config.get('port', +url.port);
|
|
91
102
|
this.options.user = ret.user = this.options.user ?? this.config.get('user', decodeURIComponent(url.username));
|
|
92
|
-
this.options.password = ret.password =
|
|
93
|
-
|
|
103
|
+
this.options.password = ret.password =
|
|
104
|
+
this.options.password ?? this.config.get('password', decodeURIComponent(url.password));
|
|
105
|
+
this.options.dbName = ret.database =
|
|
106
|
+
this.options.dbName ?? this.config.get('dbName', decodeURIComponent(url.pathname).replace(/^\//, ''));
|
|
94
107
|
}
|
|
95
108
|
return ret;
|
|
96
109
|
}
|
|
@@ -157,11 +157,11 @@ export class DatabaseDriver {
|
|
|
157
157
|
Object.assign(o, createOrderBy(key, direction[key]));
|
|
158
158
|
return o;
|
|
159
159
|
}, {});
|
|
160
|
-
return
|
|
160
|
+
return { [prop]: value };
|
|
161
161
|
}
|
|
162
162
|
const desc = direction === QueryOrderNumeric.DESC || direction.toString().toLowerCase() === 'desc';
|
|
163
163
|
const dir = Utils.xor(desc, isLast) ? 'desc' : 'asc';
|
|
164
|
-
return
|
|
164
|
+
return { [prop]: dir };
|
|
165
165
|
};
|
|
166
166
|
return {
|
|
167
167
|
orderBy: definition.map(([prop, direction]) => createOrderBy(prop, direction)),
|
|
@@ -301,16 +301,23 @@ export class DatabaseDriver {
|
|
|
301
301
|
if (prop.joinColumns && Array.isArray(data[k])) {
|
|
302
302
|
const copy = Utils.flatten(data[k]);
|
|
303
303
|
delete data[k];
|
|
304
|
-
prop.joinColumns.forEach((joinColumn, idx) => data[joinColumn] = copy[idx]);
|
|
304
|
+
prop.joinColumns.forEach((joinColumn, idx) => (data[joinColumn] = copy[idx]));
|
|
305
305
|
return;
|
|
306
306
|
}
|
|
307
307
|
if (prop.joinColumns?.length > 1 && data[k] == null) {
|
|
308
308
|
delete data[k];
|
|
309
|
-
prop.ownColumns.forEach(joinColumn => data[joinColumn] = null);
|
|
309
|
+
prop.ownColumns.forEach(joinColumn => (data[joinColumn] = null));
|
|
310
310
|
return;
|
|
311
311
|
}
|
|
312
|
-
if (prop.customType &&
|
|
313
|
-
|
|
312
|
+
if (prop.customType &&
|
|
313
|
+
convertCustomTypes &&
|
|
314
|
+
!(prop.customType instanceof JsonType && object) &&
|
|
315
|
+
!isRaw(data[k])) {
|
|
316
|
+
data[k] = prop.customType.convertToDatabaseValue(data[k], this.platform, {
|
|
317
|
+
fromQuery: true,
|
|
318
|
+
key: k,
|
|
319
|
+
mode: 'query-data',
|
|
320
|
+
});
|
|
314
321
|
}
|
|
315
322
|
if (prop.hasConvertToDatabaseValueSQL && !prop.object && !isRaw(data[k])) {
|
|
316
323
|
const quoted = this.platform.quoteValue(data[k]);
|
|
@@ -390,7 +397,18 @@ export class DatabaseDriver {
|
|
|
390
397
|
createReplicas(cb) {
|
|
391
398
|
const replicas = this.config.get('replicas', []);
|
|
392
399
|
const ret = [];
|
|
393
|
-
const props = [
|
|
400
|
+
const props = [
|
|
401
|
+
'dbName',
|
|
402
|
+
'clientUrl',
|
|
403
|
+
'host',
|
|
404
|
+
'port',
|
|
405
|
+
'user',
|
|
406
|
+
'password',
|
|
407
|
+
'multipleStatements',
|
|
408
|
+
'pool',
|
|
409
|
+
'name',
|
|
410
|
+
'driverOptions',
|
|
411
|
+
];
|
|
394
412
|
for (const conf of replicas) {
|
|
395
413
|
const replicaConfig = Utils.copy(conf);
|
|
396
414
|
for (const prop of props) {
|
package/entity/Collection.js
CHANGED
|
@@ -22,7 +22,7 @@ export class Collection {
|
|
|
22
22
|
if (items) {
|
|
23
23
|
let i = 0;
|
|
24
24
|
this.items = new Set(items);
|
|
25
|
-
this.items.forEach(item => this[i++] = item);
|
|
25
|
+
this.items.forEach(item => (this[i++] = item));
|
|
26
26
|
}
|
|
27
27
|
this.initialized = !!items || initialized;
|
|
28
28
|
}
|
|
@@ -58,7 +58,7 @@ export class Collection {
|
|
|
58
58
|
helper(this.owner).setSerializationContext({
|
|
59
59
|
populate: Array.isArray(options.populate)
|
|
60
60
|
? options.populate.map(hint => `${this.property.name}.${hint}`)
|
|
61
|
-
: options.populate ?? [this.property.name],
|
|
61
|
+
: (options.populate ?? [this.property.name]),
|
|
62
62
|
});
|
|
63
63
|
}
|
|
64
64
|
/**
|
|
@@ -79,8 +79,10 @@ export class Collection {
|
|
|
79
79
|
return this._count;
|
|
80
80
|
}
|
|
81
81
|
const em = this.getEntityManager();
|
|
82
|
-
if (!em.getPlatform().usesPivotTable() &&
|
|
83
|
-
|
|
82
|
+
if (!em.getPlatform().usesPivotTable() &&
|
|
83
|
+
this.property.kind === ReferenceKind.MANY_TO_MANY &&
|
|
84
|
+
this.property.owner) {
|
|
85
|
+
return (this._count = this.length);
|
|
84
86
|
}
|
|
85
87
|
const cond = this.createLoadCountCondition(where ?? {});
|
|
86
88
|
const count = await em.count(this.property.targetMeta.class, cond, countOptions);
|
|
@@ -96,16 +98,18 @@ export class Collection {
|
|
|
96
98
|
if (this.property.kind === ReferenceKind.MANY_TO_MANY && em.getPlatform().usesPivotTable()) {
|
|
97
99
|
// M:N via pivot table bypasses em.find(), so merge all 3 levels here
|
|
98
100
|
opts.orderBy = QueryHelper.mergeOrderBy(opts.orderBy, this.property.orderBy, this.property.targetMeta?.orderBy);
|
|
99
|
-
options.populate = await em.preparePopulate(this.property.targetMeta.class, options);
|
|
100
|
-
const cond = await em.applyFilters(this.property.targetMeta.class, where, options.filters ?? {}, 'read');
|
|
101
|
-
const map = await em
|
|
101
|
+
options.populate = (await em.preparePopulate(this.property.targetMeta.class, options));
|
|
102
|
+
const cond = (await em.applyFilters(this.property.targetMeta.class, where, options.filters ?? {}, 'read'));
|
|
103
|
+
const map = await em
|
|
104
|
+
.getDriver()
|
|
105
|
+
.loadFromPivotTable(this.property, [helper(this.owner).__primaryKeys], cond, opts.orderBy, ctx, options);
|
|
102
106
|
items = map[helper(this.owner).getSerializedPrimaryKey()].map((item) => em.merge(this.property.targetMeta.class, item, { convertCustomTypes: true }));
|
|
103
107
|
await em.populate(items, options.populate, options);
|
|
104
108
|
}
|
|
105
109
|
else {
|
|
106
110
|
// em.find() merges entity-level orderBy, so only merge runtime + relation here
|
|
107
111
|
opts.orderBy = QueryHelper.mergeOrderBy(opts.orderBy, this.property.orderBy);
|
|
108
|
-
items = await em.find(this.property.targetMeta.class, this.createCondition(where), opts);
|
|
112
|
+
items = (await em.find(this.property.targetMeta.class, this.createCondition(where), opts));
|
|
109
113
|
}
|
|
110
114
|
if (options.store) {
|
|
111
115
|
this.hydrate(items, true);
|
|
@@ -262,11 +266,9 @@ export class Collection {
|
|
|
262
266
|
return this;
|
|
263
267
|
}
|
|
264
268
|
const populate = Array.isArray(options.populate)
|
|
265
|
-
? options.populate.map(f => f === '*' ? f : `${this.property.name}.${f}`)
|
|
269
|
+
? options.populate.map(f => (f === '*' ? f : `${this.property.name}.${f}`))
|
|
266
270
|
: [`${this.property.name}${options.ref ? ':ref' : ''}`];
|
|
267
|
-
const schema = this.property.targetMeta.schema === '*'
|
|
268
|
-
? helper(this.owner).__schema
|
|
269
|
-
: undefined;
|
|
271
|
+
const schema = this.property.targetMeta.schema === '*' ? helper(this.owner).__schema : undefined;
|
|
270
272
|
await em.populate(this.owner, populate, {
|
|
271
273
|
refresh: true,
|
|
272
274
|
...options,
|
|
@@ -297,7 +299,8 @@ export class Collection {
|
|
|
297
299
|
if (this.property.kind === ReferenceKind.ONE_TO_MANY) {
|
|
298
300
|
cond[this.property.mappedBy] = helper(this.owner).getPrimaryKey();
|
|
299
301
|
}
|
|
300
|
-
else {
|
|
302
|
+
else {
|
|
303
|
+
// MANY_TO_MANY
|
|
301
304
|
this.createManyToManyCondition(cond);
|
|
302
305
|
}
|
|
303
306
|
return cond;
|
|
@@ -386,7 +389,9 @@ export class Collection {
|
|
|
386
389
|
if (items.length === 0) {
|
|
387
390
|
return [];
|
|
388
391
|
}
|
|
389
|
-
field ??= targetMeta.compositePK
|
|
392
|
+
field ??= targetMeta.compositePK
|
|
393
|
+
? targetMeta.primaryKeys
|
|
394
|
+
: (targetMeta.serializedPrimaryKey ?? targetMeta.primaryKeys[0]);
|
|
390
395
|
const cb = (i, f) => {
|
|
391
396
|
if (Utils.isEntity(i[f], true)) {
|
|
392
397
|
return wrap(i[f], true).getPrimaryKey();
|
|
@@ -616,6 +621,7 @@ export class Collection {
|
|
|
616
621
|
* @internal
|
|
617
622
|
*/
|
|
618
623
|
get property() {
|
|
624
|
+
// cannot be typed to `EntityProperty<O, T>` as it causes issues in assignability of `Loaded` type
|
|
619
625
|
if (!this._property) {
|
|
620
626
|
const meta = wrap(this.owner, true).__meta;
|
|
621
627
|
/* v8 ignore next */
|
|
@@ -630,6 +636,7 @@ export class Collection {
|
|
|
630
636
|
* @internal
|
|
631
637
|
*/
|
|
632
638
|
set property(prop) {
|
|
639
|
+
// cannot be typed to `EntityProperty<O, T>` as it causes issues in assignability of `Loaded` type
|
|
633
640
|
this._property = prop;
|
|
634
641
|
}
|
|
635
642
|
propagate(item, method) {
|
|
@@ -696,7 +703,18 @@ export class Collection {
|
|
|
696
703
|
/** @ignore */
|
|
697
704
|
[Symbol.for('nodejs.util.inspect.custom')](depth = 2) {
|
|
698
705
|
const object = { ...this };
|
|
699
|
-
const hidden = [
|
|
706
|
+
const hidden = [
|
|
707
|
+
'items',
|
|
708
|
+
'owner',
|
|
709
|
+
'_property',
|
|
710
|
+
'_count',
|
|
711
|
+
'snapshot',
|
|
712
|
+
'_populated',
|
|
713
|
+
'_lazyInitialized',
|
|
714
|
+
'_em',
|
|
715
|
+
'readonly',
|
|
716
|
+
'partial',
|
|
717
|
+
];
|
|
700
718
|
hidden.forEach(k => delete object[k]);
|
|
701
719
|
const ret = inspect(object, { depth });
|
|
702
720
|
const name = `${this.constructor.name}<${this.property?.type ?? 'unknown'}>`;
|
|
@@ -704,7 +722,15 @@ export class Collection {
|
|
|
704
722
|
}
|
|
705
723
|
}
|
|
706
724
|
Object.defineProperties(Collection.prototype, {
|
|
707
|
-
$: {
|
|
708
|
-
|
|
725
|
+
$: {
|
|
726
|
+
get() {
|
|
727
|
+
return this;
|
|
728
|
+
},
|
|
729
|
+
},
|
|
730
|
+
get: {
|
|
731
|
+
get() {
|
|
732
|
+
return () => this;
|
|
733
|
+
},
|
|
734
|
+
},
|
|
709
735
|
__collection: { value: true, enumerable: false, writable: false },
|
|
710
736
|
});
|