@mikro-orm/core 7.0.0-dev.8 → 7.0.0-dev.81
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 +85 -48
- package/EntityManager.js +300 -225
- package/MikroORM.d.ts +40 -31
- package/MikroORM.js +98 -137
- package/README.md +3 -2
- package/cache/FileCacheAdapter.d.ts +1 -1
- package/cache/FileCacheAdapter.js +6 -5
- package/cache/GeneratedCacheAdapter.d.ts +0 -1
- package/cache/GeneratedCacheAdapter.js +0 -2
- package/cache/index.d.ts +0 -1
- package/cache/index.js +0 -1
- package/connections/Connection.d.ts +11 -7
- package/connections/Connection.js +16 -14
- package/drivers/DatabaseDriver.d.ts +11 -5
- package/drivers/DatabaseDriver.js +23 -11
- package/drivers/IDatabaseDriver.d.ts +27 -5
- package/entity/BaseEntity.d.ts +0 -1
- package/entity/BaseEntity.js +0 -3
- package/entity/Collection.d.ts +98 -30
- package/entity/Collection.js +432 -93
- package/entity/EntityAssigner.d.ts +1 -1
- package/entity/EntityAssigner.js +15 -7
- package/entity/EntityFactory.d.ts +7 -0
- package/entity/EntityFactory.js +64 -41
- package/entity/EntityHelper.js +26 -9
- package/entity/EntityLoader.d.ts +5 -4
- package/entity/EntityLoader.js +73 -40
- package/entity/EntityRepository.d.ts +1 -1
- package/entity/Reference.d.ts +9 -7
- package/entity/Reference.js +33 -6
- package/entity/WrappedEntity.d.ts +2 -4
- package/entity/WrappedEntity.js +1 -5
- package/entity/defineEntity.d.ts +549 -0
- package/entity/defineEntity.js +529 -0
- package/entity/index.d.ts +3 -2
- package/entity/index.js +3 -2
- package/entity/utils.d.ts +7 -0
- package/entity/utils.js +16 -4
- package/entity/validators.d.ts +11 -0
- package/entity/validators.js +65 -0
- package/enums.d.ts +21 -6
- package/enums.js +14 -1
- package/errors.d.ts +6 -2
- package/errors.js +14 -9
- package/events/EventSubscriber.d.ts +3 -1
- package/hydration/Hydrator.js +1 -2
- package/hydration/ObjectHydrator.d.ts +4 -4
- package/hydration/ObjectHydrator.js +36 -25
- package/index.d.ts +2 -2
- package/index.js +1 -2
- package/logging/DefaultLogger.d.ts +1 -1
- package/logging/SimpleLogger.d.ts +1 -1
- package/metadata/EntitySchema.d.ts +9 -13
- package/metadata/EntitySchema.js +44 -26
- package/metadata/MetadataDiscovery.d.ts +6 -9
- package/metadata/MetadataDiscovery.js +167 -206
- package/metadata/MetadataProvider.d.ts +11 -2
- package/metadata/MetadataProvider.js +44 -2
- package/metadata/MetadataStorage.d.ts +1 -6
- package/metadata/MetadataStorage.js +6 -18
- package/metadata/MetadataValidator.d.ts +0 -7
- package/metadata/MetadataValidator.js +4 -13
- package/metadata/discover-entities.d.ts +5 -0
- package/metadata/discover-entities.js +40 -0
- package/metadata/index.d.ts +1 -1
- package/metadata/index.js +1 -1
- package/metadata/types.d.ts +480 -0
- package/metadata/types.js +1 -0
- package/naming-strategy/AbstractNamingStrategy.d.ts +5 -1
- package/naming-strategy/AbstractNamingStrategy.js +8 -2
- package/naming-strategy/NamingStrategy.d.ts +11 -1
- package/not-supported.d.ts +2 -0
- package/not-supported.js +4 -0
- package/package.json +18 -10
- package/platforms/ExceptionConverter.js +1 -1
- package/platforms/Platform.d.ts +6 -10
- package/platforms/Platform.js +14 -39
- package/serialization/EntitySerializer.d.ts +2 -0
- package/serialization/EntitySerializer.js +32 -14
- package/serialization/EntityTransformer.js +22 -12
- package/serialization/SerializationContext.js +16 -13
- package/types/ArrayType.d.ts +1 -1
- package/types/ArrayType.js +2 -3
- package/types/BigIntType.d.ts +8 -6
- package/types/BigIntType.js +1 -1
- package/types/BlobType.d.ts +0 -1
- package/types/BlobType.js +0 -3
- package/types/BooleanType.d.ts +2 -1
- package/types/BooleanType.js +3 -0
- package/types/DecimalType.d.ts +6 -4
- package/types/DecimalType.js +3 -3
- package/types/DoubleType.js +2 -2
- package/types/JsonType.d.ts +1 -1
- package/types/JsonType.js +7 -2
- package/types/TinyIntType.js +1 -1
- package/types/Type.d.ts +2 -1
- package/types/Type.js +1 -1
- package/types/Uint8ArrayType.d.ts +0 -1
- package/types/Uint8ArrayType.js +1 -4
- package/types/index.d.ts +1 -1
- package/typings.d.ts +113 -77
- package/typings.js +41 -35
- package/unit-of-work/ChangeSetComputer.d.ts +1 -3
- package/unit-of-work/ChangeSetComputer.js +11 -9
- package/unit-of-work/ChangeSetPersister.d.ts +5 -4
- package/unit-of-work/ChangeSetPersister.js +58 -20
- package/unit-of-work/UnitOfWork.d.ts +8 -1
- package/unit-of-work/UnitOfWork.js +115 -57
- package/utils/AbstractSchemaGenerator.d.ts +5 -5
- package/utils/AbstractSchemaGenerator.js +11 -9
- package/utils/Configuration.d.ts +757 -206
- package/utils/Configuration.js +139 -187
- package/utils/ConfigurationLoader.d.ts +1 -54
- package/utils/ConfigurationLoader.js +1 -352
- package/utils/Cursor.d.ts +3 -3
- package/utils/Cursor.js +4 -1
- package/utils/DataloaderUtils.d.ts +15 -5
- package/utils/DataloaderUtils.js +54 -8
- package/utils/EntityComparator.d.ts +8 -4
- package/utils/EntityComparator.js +111 -64
- package/utils/QueryHelper.d.ts +9 -1
- package/utils/QueryHelper.js +70 -9
- package/utils/RawQueryFragment.d.ts +36 -4
- package/utils/RawQueryFragment.js +35 -14
- package/utils/TransactionManager.d.ts +65 -0
- package/utils/TransactionManager.js +223 -0
- package/utils/Utils.d.ts +8 -97
- package/utils/Utils.js +88 -303
- package/utils/clone.js +2 -3
- package/utils/env-vars.d.ts +3 -0
- package/utils/env-vars.js +87 -0
- package/utils/fs-utils.d.ts +12 -0
- package/utils/fs-utils.js +96 -0
- package/utils/index.d.ts +2 -1
- package/utils/index.js +2 -1
- package/utils/upsert-utils.d.ts +7 -2
- package/utils/upsert-utils.js +55 -4
- package/decorators/Check.d.ts +0 -3
- package/decorators/Check.js +0 -13
- package/decorators/CreateRequestContext.d.ts +0 -3
- package/decorators/CreateRequestContext.js +0 -32
- package/decorators/Embeddable.d.ts +0 -8
- package/decorators/Embeddable.js +0 -11
- package/decorators/Embedded.d.ts +0 -18
- package/decorators/Embedded.js +0 -18
- package/decorators/Entity.d.ts +0 -18
- package/decorators/Entity.js +0 -12
- package/decorators/Enum.d.ts +0 -9
- package/decorators/Enum.js +0 -16
- package/decorators/Filter.d.ts +0 -2
- package/decorators/Filter.js +0 -8
- package/decorators/Formula.d.ts +0 -4
- package/decorators/Formula.js +0 -15
- package/decorators/Indexed.d.ts +0 -19
- package/decorators/Indexed.js +0 -20
- package/decorators/ManyToMany.d.ts +0 -40
- package/decorators/ManyToMany.js +0 -14
- package/decorators/ManyToOne.d.ts +0 -30
- package/decorators/ManyToOne.js +0 -14
- package/decorators/OneToMany.d.ts +0 -28
- package/decorators/OneToMany.js +0 -17
- package/decorators/OneToOne.d.ts +0 -24
- package/decorators/OneToOne.js +0 -7
- package/decorators/PrimaryKey.d.ts +0 -8
- package/decorators/PrimaryKey.js +0 -20
- package/decorators/Property.d.ts +0 -250
- package/decorators/Property.js +0 -32
- package/decorators/Transactional.d.ts +0 -13
- package/decorators/Transactional.js +0 -28
- package/decorators/hooks.d.ts +0 -16
- package/decorators/hooks.js +0 -47
- package/decorators/index.d.ts +0 -17
- package/decorators/index.js +0 -17
- package/entity/ArrayCollection.d.ts +0 -116
- package/entity/ArrayCollection.js +0 -402
- package/entity/EntityValidator.d.ts +0 -19
- package/entity/EntityValidator.js +0 -150
- package/metadata/ReflectMetadataProvider.d.ts +0 -8
- package/metadata/ReflectMetadataProvider.js +0 -44
- package/utils/resolveContextProvider.d.ts +0 -10
- package/utils/resolveContextProvider.js +0 -28
package/entity/EntityLoader.js
CHANGED
|
@@ -32,17 +32,16 @@ export class EntityLoader {
|
|
|
32
32
|
const visited = options.visited ??= new Set();
|
|
33
33
|
options.where ??= {};
|
|
34
34
|
options.orderBy ??= {};
|
|
35
|
-
options.filters ??= {};
|
|
36
35
|
options.lookup ??= true;
|
|
37
36
|
options.validate ??= true;
|
|
38
37
|
options.refresh ??= false;
|
|
39
38
|
options.convertCustomTypes ??= true;
|
|
40
39
|
if (references.length > 0) {
|
|
41
|
-
await this.populateScalar(meta, references, options);
|
|
40
|
+
await this.populateScalar(meta, references, { ...options, populateWhere: undefined });
|
|
42
41
|
}
|
|
43
42
|
populate = this.normalizePopulate(entityName, populate, options.strategy, options.lookup);
|
|
44
43
|
const invalid = populate.find(({ field }) => !this.em.canPopulate(entityName, field));
|
|
45
|
-
/* v8 ignore next
|
|
44
|
+
/* v8 ignore next */
|
|
46
45
|
if (options.validate && invalid) {
|
|
47
46
|
throw ValidationError.invalidPropertyName(entityName, invalid.field);
|
|
48
47
|
}
|
|
@@ -140,17 +139,22 @@ export class EntityLoader {
|
|
|
140
139
|
const innerOrderBy = Utils.asArray(options.orderBy)
|
|
141
140
|
.filter(orderBy => (Array.isArray(orderBy[prop.name]) && orderBy[prop.name].length > 0) || Utils.isObject(orderBy[prop.name]))
|
|
142
141
|
.flatMap(orderBy => orderBy[prop.name]);
|
|
142
|
+
const where = await this.extractChildCondition(options, prop);
|
|
143
143
|
if (prop.kind === ReferenceKind.MANY_TO_MANY && this.driver.getPlatform().usesPivotTable()) {
|
|
144
|
-
|
|
144
|
+
const res = await this.findChildrenFromPivotTable(filtered, prop, options, innerOrderBy, populate, !!ref);
|
|
145
|
+
return Utils.flatten(res);
|
|
145
146
|
}
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
147
|
+
const { items, partial } = await this.findChildren(options.filtered ?? entities, prop, populate, {
|
|
148
|
+
...options,
|
|
149
|
+
where,
|
|
150
|
+
orderBy: innerOrderBy,
|
|
151
|
+
}, !!(ref || prop.mapToPk));
|
|
152
|
+
this.initializeCollections(filtered, prop, field, items, innerOrderBy.length > 0, partial);
|
|
153
|
+
return items;
|
|
150
154
|
}
|
|
151
155
|
async populateScalar(meta, filtered, options) {
|
|
152
156
|
const pk = Utils.getPrimaryKeyHash(meta.primaryKeys);
|
|
153
|
-
const ids = Utils.unique(filtered.map(e => Utils.getPrimaryKeyValues(e, meta
|
|
157
|
+
const ids = Utils.unique(filtered.map(e => Utils.getPrimaryKeyValues(e, meta, true)));
|
|
154
158
|
const where = this.mergePrimaryCondition(ids, pk, options, meta, this.metadata, this.driver.getPlatform());
|
|
155
159
|
const { filters, convertCustomTypes, lockMode, strategy, populateWhere, connectionType, logging, fields } = options;
|
|
156
160
|
await this.em.find(meta.className, where, {
|
|
@@ -159,15 +163,15 @@ export class EntityLoader {
|
|
|
159
163
|
populate: [],
|
|
160
164
|
});
|
|
161
165
|
}
|
|
162
|
-
initializeCollections(filtered, prop, field, children, customOrder) {
|
|
166
|
+
initializeCollections(filtered, prop, field, children, customOrder, partial) {
|
|
163
167
|
if (prop.kind === ReferenceKind.ONE_TO_MANY) {
|
|
164
|
-
this.initializeOneToMany(filtered, children, prop, field);
|
|
168
|
+
this.initializeOneToMany(filtered, children, prop, field, partial);
|
|
165
169
|
}
|
|
166
170
|
if (prop.kind === ReferenceKind.MANY_TO_MANY && !this.driver.getPlatform().usesPivotTable()) {
|
|
167
|
-
this.initializeManyToMany(filtered, children, prop, field, customOrder);
|
|
171
|
+
this.initializeManyToMany(filtered, children, prop, field, customOrder, partial);
|
|
168
172
|
}
|
|
169
173
|
}
|
|
170
|
-
initializeOneToMany(filtered, children, prop, field) {
|
|
174
|
+
initializeOneToMany(filtered, children, prop, field, partial) {
|
|
171
175
|
const mapToPk = prop.targetMeta.properties[prop.mappedBy].mapToPk;
|
|
172
176
|
const map = {};
|
|
173
177
|
for (const entity of filtered) {
|
|
@@ -183,14 +187,14 @@ export class EntityLoader {
|
|
|
183
187
|
}
|
|
184
188
|
for (const entity of filtered) {
|
|
185
189
|
const key = helper(entity).getSerializedPrimaryKey();
|
|
186
|
-
entity[field].hydrate(map[key]);
|
|
190
|
+
entity[field].hydrate(map[key], undefined, partial);
|
|
187
191
|
}
|
|
188
192
|
}
|
|
189
|
-
initializeManyToMany(filtered, children, prop, field, customOrder) {
|
|
193
|
+
initializeManyToMany(filtered, children, prop, field, customOrder, partial) {
|
|
190
194
|
if (prop.mappedBy) {
|
|
191
195
|
for (const entity of filtered) {
|
|
192
196
|
const items = children.filter(child => child[prop.mappedBy].contains(entity, false));
|
|
193
|
-
entity[field].hydrate(items, true);
|
|
197
|
+
entity[field].hydrate(items, true, partial);
|
|
194
198
|
}
|
|
195
199
|
}
|
|
196
200
|
else { // owning side of M:N without pivot table needs to be reordered
|
|
@@ -200,15 +204,16 @@ export class EntityLoader {
|
|
|
200
204
|
if (!customOrder) {
|
|
201
205
|
items.sort((a, b) => order.indexOf(a) - order.indexOf(b));
|
|
202
206
|
}
|
|
203
|
-
entity[field].hydrate(items, true);
|
|
207
|
+
entity[field].hydrate(items, true, partial);
|
|
204
208
|
}
|
|
205
209
|
}
|
|
206
210
|
}
|
|
207
211
|
async findChildren(entities, prop, populate, options, ref) {
|
|
208
|
-
const children = this.getChildReferences(entities, prop, options, ref);
|
|
212
|
+
const children = Utils.unique(this.getChildReferences(entities, prop, options, ref));
|
|
209
213
|
const meta = prop.targetMeta;
|
|
210
214
|
let fk = Utils.getPrimaryKeyHash(meta.primaryKeys);
|
|
211
215
|
let schema = options.schema;
|
|
216
|
+
const partial = !Utils.isEmpty(prop.where) || !Utils.isEmpty(options.where);
|
|
212
217
|
if (prop.kind === ReferenceKind.ONE_TO_MANY || (prop.kind === ReferenceKind.MANY_TO_MANY && !prop.owner)) {
|
|
213
218
|
fk = meta.properties[prop.mappedBy].name;
|
|
214
219
|
}
|
|
@@ -218,7 +223,7 @@ export class EntityLoader {
|
|
|
218
223
|
children.push(...this.filterByReferences(entities, prop.name, options.refresh));
|
|
219
224
|
}
|
|
220
225
|
if (children.length === 0) {
|
|
221
|
-
return [];
|
|
226
|
+
return { items: [], partial };
|
|
222
227
|
}
|
|
223
228
|
if (!schema && [ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(prop.kind)) {
|
|
224
229
|
schema = children.find(e => e.__helper.__schema)?.__helper.__schema;
|
|
@@ -227,7 +232,7 @@ export class EntityLoader {
|
|
|
227
232
|
let where = this.mergePrimaryCondition(ids, fk, options, meta, this.metadata, this.driver.getPlatform());
|
|
228
233
|
const fields = this.buildFields(options.fields, prop, ref);
|
|
229
234
|
/* eslint-disable prefer-const */
|
|
230
|
-
let { refresh, filters, convertCustomTypes, lockMode, strategy, populateWhere, connectionType, logging, } = options;
|
|
235
|
+
let { refresh, filters, convertCustomTypes, lockMode, strategy, populateWhere = 'infer', connectionType, logging, } = options;
|
|
231
236
|
/* eslint-enable prefer-const */
|
|
232
237
|
if (typeof populateWhere === 'object') {
|
|
233
238
|
populateWhere = await this.extractChildCondition({ where: populateWhere }, prop);
|
|
@@ -264,6 +269,24 @@ export class EntityLoader {
|
|
|
264
269
|
// @ts-ignore not a public option, will be propagated to the populate call
|
|
265
270
|
visited: options.visited,
|
|
266
271
|
});
|
|
272
|
+
if ([ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(prop.kind) && items.length !== children.length) {
|
|
273
|
+
const nullVal = this.em.config.get('forceUndefined') ? undefined : null;
|
|
274
|
+
const itemsMap = new Set();
|
|
275
|
+
const childrenMap = new Set();
|
|
276
|
+
for (const item of items) {
|
|
277
|
+
itemsMap.add(helper(item).getSerializedPrimaryKey());
|
|
278
|
+
}
|
|
279
|
+
for (const child of children) {
|
|
280
|
+
childrenMap.add(helper(child).getSerializedPrimaryKey());
|
|
281
|
+
}
|
|
282
|
+
for (const entity of entities) {
|
|
283
|
+
const key = helper(entity[prop.name] ?? {})?.getSerializedPrimaryKey();
|
|
284
|
+
if (childrenMap.has(key) && !itemsMap.has(key)) {
|
|
285
|
+
entity[prop.name] = nullVal;
|
|
286
|
+
helper(entity).__originalEntityData[prop.name] = null;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
267
290
|
for (const item of items) {
|
|
268
291
|
if (ref && !helper(item).__onLoadFired) {
|
|
269
292
|
helper(item).__initialized = false;
|
|
@@ -271,7 +294,7 @@ export class EntityLoader {
|
|
|
271
294
|
this.em.getUnitOfWork()['loadedEntities'].delete(item);
|
|
272
295
|
}
|
|
273
296
|
}
|
|
274
|
-
return items;
|
|
297
|
+
return { items, partial };
|
|
275
298
|
}
|
|
276
299
|
mergePrimaryCondition(ids, pk, options, meta, metadata, platform) {
|
|
277
300
|
const cond1 = QueryHelper.processWhere({ where: { [pk]: { $in: ids } }, entityName: meta.className, metadata, platform, convertCustomTypes: !options.convertCustomTypes });
|
|
@@ -287,6 +310,7 @@ export class EntityLoader {
|
|
|
287
310
|
if (prop.kind === ReferenceKind.SCALAR && !prop.lazy) {
|
|
288
311
|
return;
|
|
289
312
|
}
|
|
313
|
+
options = { ...options, filters: QueryHelper.mergePropertyFilters(prop.filters, options.filters) };
|
|
290
314
|
const populated = await this.populateMany(entityName, entities, populate, options);
|
|
291
315
|
if (!populate.children && !populate.all) {
|
|
292
316
|
return;
|
|
@@ -314,10 +338,18 @@ export class EntityLoader {
|
|
|
314
338
|
const innerOrderBy = Utils.asArray(options.orderBy)
|
|
315
339
|
.filter(orderBy => Utils.isObject(orderBy[prop.name]))
|
|
316
340
|
.map(orderBy => orderBy[prop.name]);
|
|
317
|
-
const { refresh, filters, ignoreLazyScalarProperties, populateWhere, connectionType, logging } = options;
|
|
341
|
+
const { refresh, filters, ignoreLazyScalarProperties, populateWhere, connectionType, logging, schema } = options;
|
|
318
342
|
const exclude = Array.isArray(options.exclude) ? Utils.extractChildElements(options.exclude, prop.name) : options.exclude;
|
|
319
|
-
const
|
|
320
|
-
|
|
343
|
+
const visited = options.visited;
|
|
344
|
+
for (const entity of entities) {
|
|
345
|
+
visited.delete(entity);
|
|
346
|
+
}
|
|
347
|
+
const unique = Utils.unique(children);
|
|
348
|
+
const filtered = unique.filter(e => !visited.has(e));
|
|
349
|
+
for (const entity of entities) {
|
|
350
|
+
visited.add(entity);
|
|
351
|
+
}
|
|
352
|
+
await this.populate(prop.type, unique, populate.children ?? populate.all, {
|
|
321
353
|
where: await this.extractChildCondition(options, prop, false),
|
|
322
354
|
orderBy: innerOrderBy,
|
|
323
355
|
fields,
|
|
@@ -329,12 +361,16 @@ export class EntityLoader {
|
|
|
329
361
|
populateWhere,
|
|
330
362
|
connectionType,
|
|
331
363
|
logging,
|
|
364
|
+
schema,
|
|
332
365
|
// @ts-ignore not a public option, will be propagated to the populate call
|
|
333
366
|
refresh: refresh && !filtered.every(item => options.visited.has(item)),
|
|
334
367
|
// @ts-ignore not a public option, will be propagated to the populate call
|
|
335
368
|
visited: options.visited,
|
|
369
|
+
// @ts-ignore not a public option
|
|
370
|
+
filtered,
|
|
336
371
|
});
|
|
337
372
|
}
|
|
373
|
+
/** @internal */
|
|
338
374
|
async findChildrenFromPivotTable(filtered, prop, options, orderBy, populate, pivotJoin) {
|
|
339
375
|
const ids = filtered.map(e => e.__helper.__primaryKeys);
|
|
340
376
|
const refresh = options.refresh;
|
|
@@ -372,7 +408,7 @@ export class EntityLoader {
|
|
|
372
408
|
return this.em.getUnitOfWork().register(entity, item, { refresh, loaded: true });
|
|
373
409
|
});
|
|
374
410
|
entity[prop.name].hydrate(items, true);
|
|
375
|
-
children.push(
|
|
411
|
+
children.push(items);
|
|
376
412
|
}
|
|
377
413
|
return children;
|
|
378
414
|
}
|
|
@@ -427,7 +463,7 @@ export class EntityLoader {
|
|
|
427
463
|
const parts = f.toString().split('.');
|
|
428
464
|
const propName = parts.shift();
|
|
429
465
|
const childPropName = parts.join('.');
|
|
430
|
-
/* v8 ignore next
|
|
466
|
+
/* v8 ignore next */
|
|
431
467
|
if (propName === prop.name) {
|
|
432
468
|
ret.push(childPropName);
|
|
433
469
|
}
|
|
@@ -448,23 +484,20 @@ export class EntityLoader {
|
|
|
448
484
|
}
|
|
449
485
|
getChildReferences(entities, prop, options, ref) {
|
|
450
486
|
const filtered = this.filterCollections(entities, prop.name, options, ref);
|
|
451
|
-
const children = [];
|
|
452
487
|
if (prop.kind === ReferenceKind.ONE_TO_MANY) {
|
|
453
|
-
|
|
488
|
+
return filtered.map(e => e[prop.name].owner);
|
|
454
489
|
}
|
|
455
|
-
|
|
456
|
-
|
|
490
|
+
if (prop.kind === ReferenceKind.MANY_TO_MANY && prop.owner) {
|
|
491
|
+
return filtered.reduce((a, b) => {
|
|
457
492
|
a.push(...b[prop.name].getItems());
|
|
458
493
|
return a;
|
|
459
|
-
}, [])
|
|
494
|
+
}, []);
|
|
460
495
|
}
|
|
461
|
-
|
|
462
|
-
|
|
496
|
+
if (prop.kind === ReferenceKind.MANY_TO_MANY) { // inverse side
|
|
497
|
+
return filtered;
|
|
463
498
|
}
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
}
|
|
467
|
-
return children;
|
|
499
|
+
// MANY_TO_ONE or ONE_TO_ONE
|
|
500
|
+
return this.filterReferences(entities, prop.name, options, ref);
|
|
468
501
|
}
|
|
469
502
|
filterCollections(entities, field, options, ref) {
|
|
470
503
|
if (options.refresh) {
|
|
@@ -481,7 +514,7 @@ export class EntityLoader {
|
|
|
481
514
|
return wrapped.__loadedProperties.has(field);
|
|
482
515
|
}
|
|
483
516
|
const [f, ...r] = field.split('.');
|
|
484
|
-
/* v8 ignore next
|
|
517
|
+
/* v8 ignore next */
|
|
485
518
|
if (!wrapped.__loadedProperties.has(f) || !wrapped.__meta.properties[f]?.targetMeta) {
|
|
486
519
|
return false;
|
|
487
520
|
}
|
|
@@ -514,11 +547,11 @@ export class EntityLoader {
|
|
|
514
547
|
.map(e => Reference.unwrapReference(e[field]));
|
|
515
548
|
}
|
|
516
549
|
filterByReferences(entities, field, refresh) {
|
|
517
|
-
/* v8 ignore next
|
|
550
|
+
/* v8 ignore next */
|
|
518
551
|
if (refresh) {
|
|
519
552
|
return entities;
|
|
520
553
|
}
|
|
521
|
-
return entities.filter(e => !e[field]?.__helper?.__initialized);
|
|
554
|
+
return entities.filter(e => e[field] !== null && !e[field]?.__helper?.__initialized);
|
|
522
555
|
}
|
|
523
556
|
lookupAllRelationships(entityName) {
|
|
524
557
|
const ret = [];
|
|
@@ -80,7 +80,7 @@ export declare class EntityRepository<Entity extends object> {
|
|
|
80
80
|
/**
|
|
81
81
|
* @inheritDoc EntityManager.findByCursor
|
|
82
82
|
*/
|
|
83
|
-
findByCursor<Hint extends string = never, Fields extends string = '*', Excludes extends string = never>(where: FilterQuery<Entity>, options: FindByCursorOptions<Entity, Hint, Fields, Excludes>): Promise<Cursor<Entity, Hint, Fields, Excludes>>;
|
|
83
|
+
findByCursor<Hint extends string = never, Fields extends string = '*', Excludes extends string = never, IncludeCount extends boolean = true>(where: FilterQuery<Entity>, options: FindByCursorOptions<Entity, Hint, Fields, Excludes, IncludeCount>): Promise<Cursor<Entity, Hint, Fields, Excludes, IncludeCount>>;
|
|
84
84
|
/**
|
|
85
85
|
* Finds all entities of given type. You can pass additional options via the `options` parameter.
|
|
86
86
|
*/
|
package/entity/Reference.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { inspect } from 'node:util';
|
|
2
|
-
import type { AddEager, Dictionary, EntityClass, EntityKey, EntityProperty, Loaded, LoadedReference, Primary, Ref } from '../typings.js';
|
|
2
|
+
import type { AddEager, AddOptional, Dictionary, EntityClass, EntityKey, EntityProperty, Loaded, LoadedReference, Primary, Ref } from '../typings.js';
|
|
3
3
|
import type { FindOneOptions, FindOneOrFailOptions } from '../drivers/IDatabaseDriver.js';
|
|
4
4
|
export declare class Reference<T extends object> {
|
|
5
5
|
private entity;
|
|
6
|
+
private property?;
|
|
6
7
|
constructor(entity: T);
|
|
7
8
|
static create<T extends object>(entity: T | Ref<T>): Ref<T>;
|
|
8
9
|
static createFromPK<T extends object>(entityType: EntityClass<T>, pk: Primary<T>, options?: {
|
|
@@ -56,6 +57,11 @@ export declare class ScalarReference<Value> {
|
|
|
56
57
|
* Returns either the whole entity, or the requested property.
|
|
57
58
|
*/
|
|
58
59
|
load(options?: Omit<LoadReferenceOptions<any, any>, 'populate' | 'fields' | 'exclude'>): Promise<Value | undefined>;
|
|
60
|
+
/**
|
|
61
|
+
* Ensures the underlying entity is loaded first (without reloading it if it already is loaded).
|
|
62
|
+
* Returns the entity or throws an error just like `em.findOneOrFail()` (and respects the same config options).
|
|
63
|
+
*/
|
|
64
|
+
loadOrFail(options?: Omit<LoadReferenceOrFailOptions<any, any>, 'populate' | 'fields' | 'exclude'>): Promise<Value>;
|
|
59
65
|
set(value: Value): void;
|
|
60
66
|
bind<Entity extends object>(entity: Entity, property: EntityKey<Entity>): void;
|
|
61
67
|
unwrap(): Value | undefined;
|
|
@@ -72,15 +78,11 @@ export interface LoadReferenceOrFailOptions<T extends object, P extends string =
|
|
|
72
78
|
/**
|
|
73
79
|
* shortcut for `wrap(entity).toReference()`
|
|
74
80
|
*/
|
|
75
|
-
export declare function ref<
|
|
81
|
+
export declare function ref<I extends unknown | Ref<unknown> | undefined | null, T extends I & {}>(entity: I): Ref<T> & LoadedReference<Loaded<T, AddEager<T>>> | AddOptional<typeof entity>;
|
|
76
82
|
/**
|
|
77
83
|
* shortcut for `Reference.createFromPK(entityType, pk)`
|
|
78
84
|
*/
|
|
79
|
-
export declare function ref<T, PKV extends Primary<T> = Primary<T>>(entityType: EntityClass<T>, pk
|
|
80
|
-
/**
|
|
81
|
-
* shortcut for `wrap(entity).toReference()`
|
|
82
|
-
*/
|
|
83
|
-
export declare function ref<T>(value: T | Ref<T>): Ref<T> & LoadedReference<Loaded<T, AddEager<T>>>;
|
|
85
|
+
export declare function ref<I extends unknown | undefined | null, T, PKV extends Primary<T> = Primary<T>>(entityType: EntityClass<T>, pk: I): Ref<T> | AddOptional<typeof pk>;
|
|
84
86
|
/**
|
|
85
87
|
* shortcut for `Reference.createNakedFromPK(entityType, pk)`
|
|
86
88
|
*/
|
package/entity/Reference.js
CHANGED
|
@@ -2,8 +2,11 @@ import { inspect } from 'node:util';
|
|
|
2
2
|
import { DataloaderType } from '../enums.js';
|
|
3
3
|
import { helper, wrap } from './wrap.js';
|
|
4
4
|
import { Utils } from '../utils/Utils.js';
|
|
5
|
+
import { QueryHelper } from '../utils/QueryHelper.js';
|
|
6
|
+
import { NotFoundError } from '../errors.js';
|
|
5
7
|
export class Reference {
|
|
6
8
|
entity;
|
|
9
|
+
property;
|
|
7
10
|
constructor(entity) {
|
|
8
11
|
this.entity = entity;
|
|
9
12
|
this.set(entity);
|
|
@@ -33,10 +36,15 @@ export class Reference {
|
|
|
33
36
|
}
|
|
34
37
|
static createFromPK(entityType, pk, options) {
|
|
35
38
|
const ref = this.createNakedFromPK(entityType, pk, options);
|
|
36
|
-
return helper(ref)
|
|
39
|
+
return helper(ref)?.toReference() ?? ref;
|
|
37
40
|
}
|
|
38
41
|
static createNakedFromPK(entityType, pk, options) {
|
|
39
42
|
const factory = entityType.prototype.__factory;
|
|
43
|
+
if (!factory) {
|
|
44
|
+
// this can happen only if `ref()` is used as a property initializer, and the value is important only for the
|
|
45
|
+
// inference of defaults, so it's fine to return it directly without wrapping with `Reference` class
|
|
46
|
+
return pk;
|
|
47
|
+
}
|
|
40
48
|
const entity = factory.createReference(entityType, pk, {
|
|
41
49
|
merge: false,
|
|
42
50
|
convertCustomTypes: false,
|
|
@@ -58,7 +66,9 @@ export class Reference {
|
|
|
58
66
|
*/
|
|
59
67
|
static wrapReference(entity, prop) {
|
|
60
68
|
if (entity && prop.ref && !Reference.isReference(entity)) {
|
|
61
|
-
|
|
69
|
+
const ref = Reference.create(entity);
|
|
70
|
+
ref.property = prop;
|
|
71
|
+
return ref;
|
|
62
72
|
}
|
|
63
73
|
return entity;
|
|
64
74
|
}
|
|
@@ -78,13 +88,14 @@ export class Reference {
|
|
|
78
88
|
if (!wrapped.__em) {
|
|
79
89
|
return this.entity;
|
|
80
90
|
}
|
|
91
|
+
options = { ...options, filters: QueryHelper.mergePropertyFilters(this.property?.filters, options.filters) };
|
|
81
92
|
if (this.isInitialized() && !options.refresh && options.populate) {
|
|
82
93
|
await wrapped.__em.populate(this.entity, options.populate, options);
|
|
83
94
|
}
|
|
84
95
|
if (!this.isInitialized() || options.refresh) {
|
|
85
96
|
if (options.dataloader ?? [DataloaderType.ALL, DataloaderType.REFERENCE].includes(wrapped.__em.config.getDataloaderType())) {
|
|
86
|
-
|
|
87
|
-
return
|
|
97
|
+
const dataLoader = await wrapped.__em.getDataLoader('ref');
|
|
98
|
+
return dataLoader.load([this, options]);
|
|
88
99
|
}
|
|
89
100
|
return wrapped.init(options);
|
|
90
101
|
}
|
|
@@ -137,7 +148,7 @@ export class Reference {
|
|
|
137
148
|
/** @ignore */
|
|
138
149
|
[inspect.custom](depth = 2) {
|
|
139
150
|
const object = { ...this };
|
|
140
|
-
const hidden = ['meta'];
|
|
151
|
+
const hidden = ['meta', 'property'];
|
|
141
152
|
hidden.forEach(k => delete object[k]);
|
|
142
153
|
const ret = inspect(object, { depth });
|
|
143
154
|
const wrapped = helper(this.entity);
|
|
@@ -171,6 +182,22 @@ export class ScalarReference {
|
|
|
171
182
|
}
|
|
172
183
|
return this.value;
|
|
173
184
|
}
|
|
185
|
+
/**
|
|
186
|
+
* Ensures the underlying entity is loaded first (without reloading it if it already is loaded).
|
|
187
|
+
* Returns the entity or throws an error just like `em.findOneOrFail()` (and respects the same config options).
|
|
188
|
+
*/
|
|
189
|
+
async loadOrFail(options = {}) {
|
|
190
|
+
const ret = await this.load(options);
|
|
191
|
+
if (ret == null) {
|
|
192
|
+
const wrapped = helper(this.entity);
|
|
193
|
+
options.failHandler ??= wrapped.__em.config.get('findOneOrFailHandler');
|
|
194
|
+
const entityName = this.entity.constructor.name;
|
|
195
|
+
const where = wrapped.getPrimaryKey();
|
|
196
|
+
const whereString = typeof where === 'object' ? inspect(where) : where;
|
|
197
|
+
throw new NotFoundError(`${entityName} (${whereString}) failed to load property '${this.property}'`);
|
|
198
|
+
}
|
|
199
|
+
return ret;
|
|
200
|
+
}
|
|
174
201
|
set(value) {
|
|
175
202
|
this.value = value;
|
|
176
203
|
this.initialized = true;
|
|
@@ -186,8 +213,8 @@ export class ScalarReference {
|
|
|
186
213
|
isInitialized() {
|
|
187
214
|
return this.initialized;
|
|
188
215
|
}
|
|
189
|
-
/* v8 ignore next 4 */
|
|
190
216
|
/** @ignore */
|
|
217
|
+
/* v8 ignore next */
|
|
191
218
|
[inspect.custom]() {
|
|
192
219
|
return this.initialized ? `Ref<${inspect(this.value)}>` : `Ref<?>`;
|
|
193
220
|
}
|
|
@@ -11,7 +11,6 @@ import { type SerializeOptions } from '../serialization/EntitySerializer.js';
|
|
|
11
11
|
import type { FindOneOptions, LoadHint } from '../drivers/IDatabaseDriver.js';
|
|
12
12
|
export declare class WrappedEntity<Entity extends object> {
|
|
13
13
|
__initialized: boolean;
|
|
14
|
-
__touched: boolean;
|
|
15
14
|
__populated?: boolean;
|
|
16
15
|
__managed?: boolean;
|
|
17
16
|
__onLoadFired?: boolean;
|
|
@@ -41,7 +40,6 @@ export declare class WrappedEntity<Entity extends object> {
|
|
|
41
40
|
private readonly pkGetterConverted?;
|
|
42
41
|
constructor(entity: Entity, hydrator: IHydrator, pkGetter?: (e: Entity) => Primary<Entity>, pkSerializer?: (e: Entity) => string, pkGetterConverted?: (e: Entity) => Primary<Entity>);
|
|
43
42
|
isInitialized(): boolean;
|
|
44
|
-
isTouched(): boolean;
|
|
45
43
|
isManaged(): boolean;
|
|
46
44
|
populated(populated?: boolean | undefined): void;
|
|
47
45
|
setSerializationContext<Hint extends string = never, Fields extends string = '*', Exclude extends string = never>(options: LoadHint<Entity, Hint, Fields, Exclude>): void;
|
|
@@ -61,8 +59,8 @@ export declare class WrappedEntity<Entity extends object> {
|
|
|
61
59
|
setPrimaryKey(id: Primary<Entity> | null): void;
|
|
62
60
|
getSerializedPrimaryKey(): string;
|
|
63
61
|
get __meta(): EntityMetadata<Entity>;
|
|
64
|
-
get __platform(): import("
|
|
65
|
-
get __config(): import("
|
|
62
|
+
get __platform(): import("@mikro-orm/knex").Platform;
|
|
63
|
+
get __config(): import("@mikro-orm/knex").Configuration<import("../drivers/IDatabaseDriver.js").IDatabaseDriver<import("@mikro-orm/knex").Connection>, EntityManager<import("../drivers/IDatabaseDriver.js").IDatabaseDriver<import("@mikro-orm/knex").Connection>>>;
|
|
66
64
|
get __primaryKeys(): Primary<Entity>[];
|
|
67
65
|
/** @ignore */
|
|
68
66
|
[inspect.custom](): string;
|
package/entity/WrappedEntity.js
CHANGED
|
@@ -15,7 +15,6 @@ export class WrappedEntity {
|
|
|
15
15
|
this.pkSerializer = pkSerializer;
|
|
16
16
|
this.pkGetterConverted = pkGetterConverted;
|
|
17
17
|
this.__initialized = true;
|
|
18
|
-
this.__touched = false;
|
|
19
18
|
this.__serializationContext = {};
|
|
20
19
|
this.__loadedProperties = new Set();
|
|
21
20
|
this.__data = {};
|
|
@@ -24,9 +23,6 @@ export class WrappedEntity {
|
|
|
24
23
|
isInitialized() {
|
|
25
24
|
return this.__initialized;
|
|
26
25
|
}
|
|
27
|
-
isTouched() {
|
|
28
|
-
return this.__touched;
|
|
29
|
-
}
|
|
30
26
|
isManaged() {
|
|
31
27
|
return !!this.__managed;
|
|
32
28
|
}
|
|
@@ -150,7 +146,7 @@ export class WrappedEntity {
|
|
|
150
146
|
return this.__em?.config ?? this.entity.__config;
|
|
151
147
|
}
|
|
152
148
|
get __primaryKeys() {
|
|
153
|
-
return Utils.getPrimaryKeyValues(this.entity, this.__meta
|
|
149
|
+
return Utils.getPrimaryKeyValues(this.entity, this.__meta);
|
|
154
150
|
}
|
|
155
151
|
/** @ignore */
|
|
156
152
|
[inspect.custom]() {
|