@mikro-orm/core 7.0.0-dev.23 → 7.0.0-dev.231
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 +91 -59
- package/EntityManager.js +303 -251
- package/MikroORM.d.ts +44 -35
- package/MikroORM.js +109 -143
- package/README.md +2 -0
- package/cache/FileCacheAdapter.d.ts +1 -1
- package/cache/FileCacheAdapter.js +17 -8
- 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 +12 -5
- package/connections/Connection.js +21 -12
- package/drivers/DatabaseDriver.d.ts +25 -16
- package/drivers/DatabaseDriver.js +118 -35
- package/drivers/IDatabaseDriver.d.ts +42 -19
- package/entity/BaseEntity.d.ts +61 -2
- package/entity/BaseEntity.js +0 -3
- package/entity/Collection.d.ts +101 -29
- package/entity/Collection.js +436 -104
- package/entity/EntityAssigner.d.ts +1 -1
- package/entity/EntityAssigner.js +26 -18
- package/entity/EntityFactory.d.ts +7 -1
- package/entity/EntityFactory.js +83 -54
- package/entity/EntityHelper.d.ts +2 -2
- package/entity/EntityHelper.js +48 -15
- package/entity/EntityLoader.d.ts +7 -6
- package/entity/EntityLoader.js +221 -93
- package/entity/EntityRepository.d.ts +27 -7
- package/entity/EntityRepository.js +8 -2
- package/entity/PolymorphicRef.d.ts +12 -0
- package/entity/PolymorphicRef.js +18 -0
- package/entity/Reference.d.ts +1 -5
- package/entity/Reference.js +21 -12
- package/entity/WrappedEntity.d.ts +0 -5
- package/entity/WrappedEntity.js +2 -7
- package/entity/defineEntity.d.ts +380 -310
- package/entity/defineEntity.js +124 -273
- package/entity/index.d.ts +2 -2
- package/entity/index.js +2 -2
- package/entity/utils.js +1 -1
- package/entity/validators.d.ts +11 -0
- package/entity/validators.js +65 -0
- package/enums.d.ts +8 -6
- package/enums.js +2 -1
- package/errors.d.ts +20 -10
- package/errors.js +55 -23
- package/events/EventManager.d.ts +2 -1
- package/events/EventManager.js +19 -11
- package/hydration/Hydrator.js +1 -2
- package/hydration/ObjectHydrator.d.ts +4 -4
- package/hydration/ObjectHydrator.js +87 -35
- package/index.d.ts +2 -2
- package/index.js +1 -2
- package/logging/DefaultLogger.d.ts +1 -1
- package/logging/DefaultLogger.js +1 -0
- package/logging/SimpleLogger.d.ts +1 -1
- package/logging/colors.d.ts +1 -1
- package/logging/colors.js +7 -6
- package/logging/index.d.ts +1 -0
- package/logging/index.js +1 -0
- package/logging/inspect.d.ts +2 -0
- package/logging/inspect.js +11 -0
- package/metadata/EntitySchema.d.ts +47 -23
- package/metadata/EntitySchema.js +92 -33
- package/metadata/MetadataDiscovery.d.ts +64 -9
- package/metadata/MetadataDiscovery.js +778 -325
- package/metadata/MetadataProvider.d.ts +11 -2
- package/metadata/MetadataProvider.js +46 -2
- package/metadata/MetadataStorage.d.ts +13 -11
- package/metadata/MetadataStorage.js +70 -37
- package/metadata/MetadataValidator.d.ts +32 -9
- package/metadata/MetadataValidator.js +196 -41
- 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 +526 -0
- package/metadata/types.js +1 -0
- package/naming-strategy/AbstractNamingStrategy.d.ts +16 -4
- package/naming-strategy/AbstractNamingStrategy.js +20 -2
- package/naming-strategy/EntityCaseNamingStrategy.d.ts +3 -3
- package/naming-strategy/EntityCaseNamingStrategy.js +6 -5
- package/naming-strategy/MongoNamingStrategy.d.ts +3 -3
- package/naming-strategy/MongoNamingStrategy.js +6 -6
- package/naming-strategy/NamingStrategy.d.ts +28 -4
- package/naming-strategy/UnderscoreNamingStrategy.d.ts +3 -3
- package/naming-strategy/UnderscoreNamingStrategy.js +6 -6
- package/not-supported.d.ts +2 -0
- package/not-supported.js +4 -0
- package/package.json +19 -11
- package/platforms/ExceptionConverter.js +1 -1
- package/platforms/Platform.d.ts +7 -14
- package/platforms/Platform.js +20 -43
- package/serialization/EntitySerializer.d.ts +5 -0
- package/serialization/EntitySerializer.js +47 -27
- package/serialization/EntityTransformer.js +28 -18
- package/serialization/SerializationContext.d.ts +6 -6
- package/serialization/SerializationContext.js +3 -3
- 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 +1 -0
- package/types/BooleanType.js +3 -0
- package/types/DecimalType.d.ts +6 -4
- package/types/DecimalType.js +2 -2
- package/types/DoubleType.js +1 -1
- package/types/EnumArrayType.js +1 -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 -4
- package/types/Type.js +3 -3
- package/types/Uint8ArrayType.d.ts +0 -1
- package/types/Uint8ArrayType.js +1 -4
- package/types/index.d.ts +1 -1
- package/typings.d.ts +381 -171
- package/typings.js +97 -44
- package/unit-of-work/ChangeSet.d.ts +4 -6
- package/unit-of-work/ChangeSet.js +4 -5
- package/unit-of-work/ChangeSetComputer.d.ts +1 -3
- package/unit-of-work/ChangeSetComputer.js +35 -14
- package/unit-of-work/ChangeSetPersister.d.ts +7 -3
- package/unit-of-work/ChangeSetPersister.js +83 -25
- package/unit-of-work/CommitOrderCalculator.d.ts +12 -10
- package/unit-of-work/CommitOrderCalculator.js +13 -13
- package/unit-of-work/IdentityMap.d.ts +12 -0
- package/unit-of-work/IdentityMap.js +39 -1
- package/unit-of-work/UnitOfWork.d.ts +27 -3
- package/unit-of-work/UnitOfWork.js +258 -92
- package/utils/AbstractSchemaGenerator.d.ts +5 -5
- package/utils/AbstractSchemaGenerator.js +28 -17
- package/utils/AsyncContext.d.ts +6 -0
- package/utils/AsyncContext.js +42 -0
- package/utils/Configuration.d.ts +795 -209
- package/utils/Configuration.js +150 -192
- package/utils/ConfigurationLoader.d.ts +1 -54
- package/utils/ConfigurationLoader.js +1 -352
- package/utils/Cursor.d.ts +0 -3
- package/utils/Cursor.js +24 -11
- package/utils/DataloaderUtils.d.ts +10 -5
- package/utils/DataloaderUtils.js +29 -12
- package/utils/EntityComparator.d.ts +16 -9
- package/utils/EntityComparator.js +158 -58
- package/utils/QueryHelper.d.ts +18 -6
- package/utils/QueryHelper.js +76 -23
- package/utils/RawQueryFragment.d.ts +28 -34
- package/utils/RawQueryFragment.js +35 -71
- package/utils/RequestContext.js +2 -2
- package/utils/TransactionContext.js +2 -2
- package/utils/TransactionManager.js +28 -4
- package/utils/Utils.d.ts +14 -127
- package/utils/Utils.js +85 -397
- package/utils/clone.js +8 -23
- package/utils/env-vars.d.ts +7 -0
- package/utils/env-vars.js +97 -0
- package/utils/fs-utils.d.ts +33 -0
- package/utils/fs-utils.js +192 -0
- package/utils/index.d.ts +1 -1
- package/utils/index.js +1 -1
- package/utils/upsert-utils.d.ts +9 -4
- package/utils/upsert-utils.js +46 -3
- 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 -12
- package/decorators/Embedded.js +0 -18
- package/decorators/Entity.d.ts +0 -33
- 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 -42
- package/decorators/ManyToMany.js +0 -14
- package/decorators/ManyToOne.d.ts +0 -34
- 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 -28
- 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 -14
- 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 -118
- package/entity/ArrayCollection.js +0 -407
- 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
|
@@ -4,8 +4,8 @@ import { ValidationError } from '../errors.js';
|
|
|
4
4
|
import { LoadStrategy, PopulatePath, ReferenceKind, } from '../enums.js';
|
|
5
5
|
import { Reference } from './Reference.js';
|
|
6
6
|
import { helper } from './wrap.js';
|
|
7
|
-
import { raw, RawQueryFragment } from '../utils/RawQueryFragment.js';
|
|
8
7
|
import { expandDotPaths } from './utils.js';
|
|
8
|
+
import { Raw } from '../utils/RawQueryFragment.js';
|
|
9
9
|
export class EntityLoader {
|
|
10
10
|
em;
|
|
11
11
|
metadata;
|
|
@@ -32,7 +32,6 @@ 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;
|
|
@@ -40,9 +39,9 @@ export class EntityLoader {
|
|
|
40
39
|
if (references.length > 0) {
|
|
41
40
|
await this.populateScalar(meta, references, { ...options, populateWhere: undefined });
|
|
42
41
|
}
|
|
43
|
-
populate = this.normalizePopulate(entityName, populate, options.strategy, options.lookup);
|
|
42
|
+
populate = this.normalizePopulate(entityName, populate, options.strategy, options.lookup, options.exclude);
|
|
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
|
}
|
|
@@ -57,7 +56,7 @@ export class EntityLoader {
|
|
|
57
56
|
visited.delete(entity);
|
|
58
57
|
}
|
|
59
58
|
}
|
|
60
|
-
normalizePopulate(entityName, populate, strategy, lookup = true) {
|
|
59
|
+
normalizePopulate(entityName, populate, strategy, lookup = true, exclude) {
|
|
61
60
|
const meta = this.metadata.find(entityName);
|
|
62
61
|
let normalized = Utils.asArray(populate).map(field => {
|
|
63
62
|
return typeof field === 'boolean' || field.field === PopulatePath.ALL ? { all: !!field, field: meta.primaryKeys[0] } : field;
|
|
@@ -68,7 +67,7 @@ export class EntityLoader {
|
|
|
68
67
|
// convert nested `field` with dot syntax to PopulateOptions with `children` array
|
|
69
68
|
expandDotPaths(meta, normalized, true);
|
|
70
69
|
if (lookup && populate !== false) {
|
|
71
|
-
normalized = this.lookupEagerLoadedRelationships(entityName, normalized, strategy);
|
|
70
|
+
normalized = this.lookupEagerLoadedRelationships(entityName, normalized, strategy, '', [], exclude);
|
|
72
71
|
// convert nested `field` with dot syntax produced by eager relations
|
|
73
72
|
expandDotPaths(meta, normalized, true);
|
|
74
73
|
}
|
|
@@ -142,15 +141,20 @@ export class EntityLoader {
|
|
|
142
141
|
.flatMap(orderBy => orderBy[prop.name]);
|
|
143
142
|
const where = await this.extractChildCondition(options, prop);
|
|
144
143
|
if (prop.kind === ReferenceKind.MANY_TO_MANY && this.driver.getPlatform().usesPivotTable()) {
|
|
145
|
-
const
|
|
144
|
+
const pivotOrderBy = QueryHelper.mergeOrderBy(innerOrderBy, prop.orderBy, prop.targetMeta?.orderBy);
|
|
145
|
+
const res = await this.findChildrenFromPivotTable(filtered, prop, options, pivotOrderBy, populate, !!ref);
|
|
146
146
|
return Utils.flatten(res);
|
|
147
147
|
}
|
|
148
|
+
if (prop.polymorphic && prop.polymorphTargets) {
|
|
149
|
+
return this.populatePolymorphic(entities, prop, options, !!ref);
|
|
150
|
+
}
|
|
148
151
|
const { items, partial } = await this.findChildren(options.filtered ?? entities, prop, populate, {
|
|
149
152
|
...options,
|
|
150
153
|
where,
|
|
151
154
|
orderBy: innerOrderBy,
|
|
152
155
|
}, !!(ref || prop.mapToPk));
|
|
153
|
-
|
|
156
|
+
const customOrder = innerOrderBy.length > 0 || !!prop.orderBy || !!prop.targetMeta?.orderBy;
|
|
157
|
+
this.initializeCollections(filtered, prop, field, items, customOrder, partial);
|
|
154
158
|
return items;
|
|
155
159
|
}
|
|
156
160
|
async populateScalar(meta, filtered, options) {
|
|
@@ -158,12 +162,70 @@ export class EntityLoader {
|
|
|
158
162
|
const ids = Utils.unique(filtered.map(e => Utils.getPrimaryKeyValues(e, meta, true)));
|
|
159
163
|
const where = this.mergePrimaryCondition(ids, pk, options, meta, this.metadata, this.driver.getPlatform());
|
|
160
164
|
const { filters, convertCustomTypes, lockMode, strategy, populateWhere, connectionType, logging, fields } = options;
|
|
161
|
-
await this.em.find(meta.
|
|
165
|
+
await this.em.find(meta.class, where, {
|
|
162
166
|
filters, convertCustomTypes, lockMode, strategy, populateWhere, connectionType, logging,
|
|
163
167
|
fields: fields,
|
|
164
168
|
populate: [],
|
|
165
169
|
});
|
|
166
170
|
}
|
|
171
|
+
async populatePolymorphic(entities, prop, options, ref) {
|
|
172
|
+
const ownerMeta = this.metadata.get(entities[0].constructor);
|
|
173
|
+
// Separate entities: those with loaded refs vs those needing FK load
|
|
174
|
+
const toPopulate = [];
|
|
175
|
+
const needsFkLoad = [];
|
|
176
|
+
for (const entity of entities) {
|
|
177
|
+
const refValue = entity[prop.name];
|
|
178
|
+
if (refValue && helper(refValue).hasPrimaryKey()) {
|
|
179
|
+
if ((ref && !options.refresh) || // :ref hint - already have reference
|
|
180
|
+
(!ref && helper(refValue).__initialized && !options.refresh) // already loaded
|
|
181
|
+
) {
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
toPopulate.push(entity);
|
|
185
|
+
}
|
|
186
|
+
else if (refValue == null && !helper(entity).__loadedProperties.has(prop.name)) {
|
|
187
|
+
// FK columns weren't loaded (partial loading) — need to re-fetch them.
|
|
188
|
+
// If the property IS in __loadedProperties, the FK was loaded and is genuinely null.
|
|
189
|
+
needsFkLoad.push(entity);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
// Load FK columns using populateScalar pattern
|
|
193
|
+
if (needsFkLoad.length > 0) {
|
|
194
|
+
await this.populateScalar(ownerMeta, needsFkLoad, {
|
|
195
|
+
...options,
|
|
196
|
+
fields: [...ownerMeta.primaryKeys, prop.name],
|
|
197
|
+
});
|
|
198
|
+
// After loading FKs, add to toPopulate if not using :ref hint
|
|
199
|
+
if (!ref) {
|
|
200
|
+
for (const entity of needsFkLoad) {
|
|
201
|
+
const refValue = entity[prop.name];
|
|
202
|
+
if (refValue && helper(refValue).hasPrimaryKey()) {
|
|
203
|
+
toPopulate.push(entity);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
if (toPopulate.length === 0) {
|
|
209
|
+
return [];
|
|
210
|
+
}
|
|
211
|
+
// Group references by target class for batch loading
|
|
212
|
+
const groups = new Map();
|
|
213
|
+
for (const entity of toPopulate) {
|
|
214
|
+
const refValue = Reference.unwrapReference(entity[prop.name]);
|
|
215
|
+
const discriminator = QueryHelper.findDiscriminatorValue(prop.discriminatorMap, helper(refValue).__meta.class);
|
|
216
|
+
const group = groups.get(discriminator) ?? [];
|
|
217
|
+
group.push(refValue);
|
|
218
|
+
groups.set(discriminator, group);
|
|
219
|
+
}
|
|
220
|
+
// Load each group concurrently - identity map handles merging with existing references
|
|
221
|
+
const allItems = [];
|
|
222
|
+
await Promise.all([...groups].map(async ([discriminator, children]) => {
|
|
223
|
+
const targetMeta = this.metadata.find(prop.discriminatorMap[discriminator]);
|
|
224
|
+
await this.populateScalar(targetMeta, children, options);
|
|
225
|
+
allItems.push(...children);
|
|
226
|
+
}));
|
|
227
|
+
return allItems;
|
|
228
|
+
}
|
|
167
229
|
initializeCollections(filtered, prop, field, children, customOrder, partial) {
|
|
168
230
|
if (prop.kind === ReferenceKind.ONE_TO_MANY) {
|
|
169
231
|
this.initializeOneToMany(filtered, children, prop, field, partial);
|
|
@@ -182,7 +244,7 @@ export class EntityLoader {
|
|
|
182
244
|
for (const child of children) {
|
|
183
245
|
const pk = child.__helper.__data[prop.mappedBy] ?? child[prop.mappedBy];
|
|
184
246
|
if (pk) {
|
|
185
|
-
const key = helper(mapToPk ? this.em.getReference(prop.
|
|
247
|
+
const key = helper(mapToPk ? this.em.getReference(prop.targetMeta.class, pk) : pk).getSerializedPrimaryKey();
|
|
186
248
|
map[key]?.push(child);
|
|
187
249
|
}
|
|
188
250
|
}
|
|
@@ -210,13 +272,23 @@ export class EntityLoader {
|
|
|
210
272
|
}
|
|
211
273
|
}
|
|
212
274
|
async findChildren(entities, prop, populate, options, ref) {
|
|
213
|
-
const children = this.getChildReferences(entities, prop, options, ref);
|
|
275
|
+
const children = Utils.unique(this.getChildReferences(entities, prop, options, ref));
|
|
214
276
|
const meta = prop.targetMeta;
|
|
215
|
-
|
|
277
|
+
// When targetKey is set, use it for FK lookup instead of the PK
|
|
278
|
+
let fk = prop.targetKey ?? Utils.getPrimaryKeyHash(meta.primaryKeys);
|
|
216
279
|
let schema = options.schema;
|
|
217
280
|
const partial = !Utils.isEmpty(prop.where) || !Utils.isEmpty(options.where);
|
|
281
|
+
let polymorphicOwnerProp;
|
|
218
282
|
if (prop.kind === ReferenceKind.ONE_TO_MANY || (prop.kind === ReferenceKind.MANY_TO_MANY && !prop.owner)) {
|
|
219
|
-
|
|
283
|
+
const ownerProp = meta.properties[prop.mappedBy];
|
|
284
|
+
if (ownerProp.polymorphic && ownerProp.fieldNames.length >= 2) {
|
|
285
|
+
const idColumns = ownerProp.fieldNames.slice(1);
|
|
286
|
+
fk = idColumns.length === 1 ? idColumns[0] : idColumns;
|
|
287
|
+
polymorphicOwnerProp = ownerProp;
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
fk = ownerProp.name;
|
|
291
|
+
}
|
|
220
292
|
}
|
|
221
293
|
if (prop.kind === ReferenceKind.ONE_TO_ONE && !prop.owner && !ref) {
|
|
222
294
|
children.length = 0;
|
|
@@ -229,8 +301,24 @@ export class EntityLoader {
|
|
|
229
301
|
if (!schema && [ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(prop.kind)) {
|
|
230
302
|
schema = children.find(e => e.__helper.__schema)?.__helper.__schema;
|
|
231
303
|
}
|
|
232
|
-
const ids = Utils.unique(children.map(e => e.__helper.getPrimaryKey()));
|
|
233
|
-
let where
|
|
304
|
+
const ids = Utils.unique(children.map(e => prop.targetKey ? e[prop.targetKey] : e.__helper.getPrimaryKey()));
|
|
305
|
+
let where;
|
|
306
|
+
if (polymorphicOwnerProp && Array.isArray(fk)) {
|
|
307
|
+
const conditions = ids.map(id => {
|
|
308
|
+
const pkValues = Object.values(id);
|
|
309
|
+
return Object.fromEntries(fk.map((col, idx) => [col, pkValues[idx]]));
|
|
310
|
+
});
|
|
311
|
+
where = (conditions.length === 1 ? conditions[0] : { $or: conditions });
|
|
312
|
+
}
|
|
313
|
+
else {
|
|
314
|
+
where = this.mergePrimaryCondition(ids, fk, options, meta, this.metadata, this.driver.getPlatform());
|
|
315
|
+
}
|
|
316
|
+
if (polymorphicOwnerProp) {
|
|
317
|
+
const parentMeta = this.metadata.find(entities[0].constructor);
|
|
318
|
+
const discriminatorValue = QueryHelper.findDiscriminatorValue(polymorphicOwnerProp.discriminatorMap, parentMeta.class) ?? parentMeta.tableName;
|
|
319
|
+
const discriminatorColumn = polymorphicOwnerProp.fieldNames[0];
|
|
320
|
+
where = { $and: [where, { [discriminatorColumn]: discriminatorValue }] };
|
|
321
|
+
}
|
|
234
322
|
const fields = this.buildFields(options.fields, prop, ref);
|
|
235
323
|
/* eslint-disable prefer-const */
|
|
236
324
|
let { refresh, filters, convertCustomTypes, lockMode, strategy, populateWhere = 'infer', connectionType, logging, } = options;
|
|
@@ -238,28 +326,11 @@ export class EntityLoader {
|
|
|
238
326
|
if (typeof populateWhere === 'object') {
|
|
239
327
|
populateWhere = await this.extractChildCondition({ where: populateWhere }, prop);
|
|
240
328
|
}
|
|
241
|
-
if (!Utils.isEmpty(prop.where)) {
|
|
329
|
+
if (!Utils.isEmpty(prop.where) || Raw.hasObjectFragments(prop.where)) {
|
|
242
330
|
where = { $and: [where, prop.where] };
|
|
243
331
|
}
|
|
244
|
-
const
|
|
245
|
-
|
|
246
|
-
for (const item of Utils.asArray(prop.orderBy)) {
|
|
247
|
-
for (const field of Utils.keys(item)) {
|
|
248
|
-
const rawField = RawQueryFragment.getKnownFragment(field, false);
|
|
249
|
-
if (rawField) {
|
|
250
|
-
const raw2 = raw(rawField.sql, rawField.params);
|
|
251
|
-
propOrderBy.push({ [raw2.toString()]: item[field] });
|
|
252
|
-
continue;
|
|
253
|
-
}
|
|
254
|
-
propOrderBy.push({ [field]: item[field] });
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
const orderBy = [...Utils.asArray(options.orderBy), ...propOrderBy].filter((order, idx, array) => {
|
|
259
|
-
// skip consecutive ordering with the same key to get around mongo issues
|
|
260
|
-
return idx === 0 || !Utils.equals(Object.keys(array[idx - 1]), Object.keys(order));
|
|
261
|
-
});
|
|
262
|
-
const items = await this.em.find(prop.type, where, {
|
|
332
|
+
const orderBy = QueryHelper.mergeOrderBy(options.orderBy, prop.orderBy);
|
|
333
|
+
const items = await this.em.find(meta.class, where, {
|
|
263
334
|
filters, convertCustomTypes, lockMode, populateWhere, logging,
|
|
264
335
|
orderBy,
|
|
265
336
|
populate: populate.children ?? populate.all ?? [],
|
|
@@ -270,6 +341,49 @@ export class EntityLoader {
|
|
|
270
341
|
// @ts-ignore not a public option, will be propagated to the populate call
|
|
271
342
|
visited: options.visited,
|
|
272
343
|
});
|
|
344
|
+
// For targetKey relations, wire up loaded entities to parent references
|
|
345
|
+
// This is needed because the references were created under alternate key,
|
|
346
|
+
// but loaded entities are stored under PK, so they don't automatically merge
|
|
347
|
+
if (prop.targetKey && [ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(prop.kind)) {
|
|
348
|
+
const itemsByKey = new Map();
|
|
349
|
+
for (const item of items) {
|
|
350
|
+
itemsByKey.set('' + item[prop.targetKey], item);
|
|
351
|
+
}
|
|
352
|
+
for (const entity of entities) {
|
|
353
|
+
const ref = entity[prop.name];
|
|
354
|
+
/* v8 ignore next */
|
|
355
|
+
if (!ref) {
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
const keyValue = '' + (Reference.isReference(ref) ? ref.unwrap()[prop.targetKey] : ref[prop.targetKey]);
|
|
359
|
+
const loadedItem = itemsByKey.get(keyValue);
|
|
360
|
+
if (loadedItem) {
|
|
361
|
+
entity[prop.name] = (Reference.isReference(ref) ? Reference.create(loadedItem) : loadedItem);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
if ([ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(prop.kind) && items.length !== children.length) {
|
|
366
|
+
const nullVal = this.em.config.get('forceUndefined') ? undefined : null;
|
|
367
|
+
const itemsMap = new Set();
|
|
368
|
+
const childrenMap = new Set();
|
|
369
|
+
// Use targetKey value if set, otherwise use serialized PK
|
|
370
|
+
const getKey = (e) => prop.targetKey ? '' + e[prop.targetKey] : helper(e).getSerializedPrimaryKey();
|
|
371
|
+
for (const item of items) {
|
|
372
|
+
/* v8 ignore next */
|
|
373
|
+
itemsMap.add(getKey(item));
|
|
374
|
+
}
|
|
375
|
+
for (const child of children) {
|
|
376
|
+
childrenMap.add(getKey(child));
|
|
377
|
+
}
|
|
378
|
+
for (const entity of entities) {
|
|
379
|
+
const ref = entity[prop.name] ?? {};
|
|
380
|
+
const key = helper(ref) ? getKey(ref) : undefined;
|
|
381
|
+
if (key && childrenMap.has(key) && !itemsMap.has(key)) {
|
|
382
|
+
entity[prop.name] = nullVal;
|
|
383
|
+
helper(entity).__originalEntityData[prop.name] = null;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
273
387
|
for (const item of items) {
|
|
274
388
|
if (ref && !helper(item).__onLoadFired) {
|
|
275
389
|
helper(item).__initialized = false;
|
|
@@ -280,7 +394,7 @@ export class EntityLoader {
|
|
|
280
394
|
return { items, partial };
|
|
281
395
|
}
|
|
282
396
|
mergePrimaryCondition(ids, pk, options, meta, metadata, platform) {
|
|
283
|
-
const cond1 = QueryHelper.processWhere({ where: { [pk]: { $in: ids } }, entityName: meta.
|
|
397
|
+
const cond1 = QueryHelper.processWhere({ where: { [pk]: { $in: ids } }, entityName: meta.class, metadata, platform, convertCustomTypes: !options.convertCustomTypes });
|
|
284
398
|
const where = { ...options.where };
|
|
285
399
|
Utils.dropUndefinedProperties(where);
|
|
286
400
|
return where[pk]
|
|
@@ -293,6 +407,7 @@ export class EntityLoader {
|
|
|
293
407
|
if (prop.kind === ReferenceKind.SCALAR && !prop.lazy) {
|
|
294
408
|
return;
|
|
295
409
|
}
|
|
410
|
+
options = { ...options, filters: QueryHelper.mergePropertyFilters(prop.filters, options.filters) };
|
|
296
411
|
const populated = await this.populateMany(entityName, entities, populate, options);
|
|
297
412
|
if (!populate.children && !populate.all) {
|
|
298
413
|
return;
|
|
@@ -331,26 +446,42 @@ export class EntityLoader {
|
|
|
331
446
|
for (const entity of entities) {
|
|
332
447
|
visited.add(entity);
|
|
333
448
|
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
449
|
+
if (!prop.targetMeta) {
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
const populateChildren = async (targetMeta, items) => {
|
|
453
|
+
await this.populate(targetMeta.class, items, populate.children ?? populate.all, {
|
|
454
|
+
where: await this.extractChildCondition(options, prop, false),
|
|
455
|
+
orderBy: innerOrderBy,
|
|
456
|
+
fields,
|
|
457
|
+
exclude,
|
|
458
|
+
validate: false,
|
|
459
|
+
lookup: false,
|
|
460
|
+
filters,
|
|
461
|
+
ignoreLazyScalarProperties,
|
|
462
|
+
populateWhere,
|
|
463
|
+
connectionType,
|
|
464
|
+
logging,
|
|
465
|
+
schema,
|
|
466
|
+
// @ts-ignore not a public option, will be propagated to the populate call
|
|
467
|
+
refresh: refresh && !filtered.every(item => options.visited.has(item)),
|
|
468
|
+
// @ts-ignore not a public option, will be propagated to the populate call
|
|
469
|
+
visited: options.visited,
|
|
470
|
+
// @ts-ignore not a public option
|
|
471
|
+
filtered,
|
|
472
|
+
});
|
|
473
|
+
};
|
|
474
|
+
if (prop.polymorphic && prop.polymorphTargets) {
|
|
475
|
+
await Promise.all(prop.polymorphTargets.map(async (targetMeta) => {
|
|
476
|
+
const targetChildren = unique.filter(child => helper(child).__meta.className === targetMeta.className);
|
|
477
|
+
if (targetChildren.length > 0) {
|
|
478
|
+
await populateChildren(targetMeta, targetChildren);
|
|
479
|
+
}
|
|
480
|
+
}));
|
|
481
|
+
}
|
|
482
|
+
else {
|
|
483
|
+
await populateChildren(prop.targetMeta, unique);
|
|
484
|
+
}
|
|
354
485
|
}
|
|
355
486
|
/** @internal */
|
|
356
487
|
async findChildrenFromPivotTable(filtered, prop, options, orderBy, populate, pivotJoin) {
|
|
@@ -359,11 +490,9 @@ export class EntityLoader {
|
|
|
359
490
|
let where = await this.extractChildCondition(options, prop, true);
|
|
360
491
|
const fields = this.buildFields(options.fields, prop);
|
|
361
492
|
const exclude = Array.isArray(options.exclude) ? Utils.extractChildElements(options.exclude, prop.name) : options.exclude;
|
|
362
|
-
const
|
|
363
|
-
|
|
364
|
-
delete options2
|
|
365
|
-
options2.fields = fields;
|
|
366
|
-
options2.exclude = exclude;
|
|
493
|
+
const populateFilter = options.populateFilter?.[prop.name];
|
|
494
|
+
const options2 = { ...options, fields, exclude, populateFilter };
|
|
495
|
+
['limit', 'offset', 'first', 'last', 'before', 'after', 'overfetch'].forEach(prop => delete options2[prop]);
|
|
367
496
|
options2.populate = (populate?.children ?? []);
|
|
368
497
|
if (prop.customType) {
|
|
369
498
|
ids.forEach((id, idx) => ids[idx] = QueryHelper.processCustomType(prop, id, this.driver.getPlatform()));
|
|
@@ -376,12 +505,12 @@ export class EntityLoader {
|
|
|
376
505
|
for (const entity of filtered) {
|
|
377
506
|
const items = map[entity.__helper.getSerializedPrimaryKey()].map(item => {
|
|
378
507
|
if (pivotJoin) {
|
|
379
|
-
return this.em.getReference(prop.
|
|
508
|
+
return this.em.getReference(prop.targetMeta.class, item, {
|
|
380
509
|
convertCustomTypes: true,
|
|
381
510
|
schema: options.schema ?? this.em.config.get('schema'),
|
|
382
511
|
});
|
|
383
512
|
}
|
|
384
|
-
const entity = this.em.getEntityFactory().create(prop.
|
|
513
|
+
const entity = this.em.getEntityFactory().create(prop.targetMeta.class, item, {
|
|
385
514
|
refresh,
|
|
386
515
|
merge: true,
|
|
387
516
|
convertCustomTypes: true,
|
|
@@ -397,16 +526,13 @@ export class EntityLoader {
|
|
|
397
526
|
async extractChildCondition(options, prop, filters = false) {
|
|
398
527
|
const where = options.where;
|
|
399
528
|
const subCond = Utils.isPlainObject(where[prop.name]) ? where[prop.name] : {};
|
|
400
|
-
const meta2 =
|
|
401
|
-
if (!meta2) {
|
|
402
|
-
return {};
|
|
403
|
-
}
|
|
529
|
+
const meta2 = prop.targetMeta;
|
|
404
530
|
const pk = Utils.getPrimaryKeyHash(meta2.primaryKeys);
|
|
405
531
|
['$and', '$or'].forEach(op => {
|
|
406
532
|
if (where[op]) {
|
|
407
533
|
const child = where[op]
|
|
408
534
|
.map((cond) => cond[prop.name])
|
|
409
|
-
.filter((sub) => sub != null && !(Utils.isPlainObject(sub) &&
|
|
535
|
+
.filter((sub) => sub != null && !(Utils.isPlainObject(sub) && Utils.getObjectQueryKeys(sub).every(key => Utils.isOperator(key, false))))
|
|
410
536
|
.map((cond) => {
|
|
411
537
|
if (Utils.isPrimaryKey(cond)) {
|
|
412
538
|
return { [pk]: cond };
|
|
@@ -427,7 +553,7 @@ export class EntityLoader {
|
|
|
427
553
|
});
|
|
428
554
|
}
|
|
429
555
|
if (filters) {
|
|
430
|
-
return this.em.applyFilters(
|
|
556
|
+
return this.em.applyFilters(meta2.class, subCond, options.filters, 'read', options);
|
|
431
557
|
}
|
|
432
558
|
return subCond;
|
|
433
559
|
}
|
|
@@ -445,44 +571,43 @@ export class EntityLoader {
|
|
|
445
571
|
const parts = f.toString().split('.');
|
|
446
572
|
const propName = parts.shift();
|
|
447
573
|
const childPropName = parts.join('.');
|
|
448
|
-
/* v8 ignore next
|
|
574
|
+
/* v8 ignore next */
|
|
449
575
|
if (propName === prop.name) {
|
|
450
576
|
ret.push(childPropName);
|
|
451
577
|
}
|
|
452
578
|
}
|
|
453
579
|
return ret;
|
|
454
580
|
}, []);
|
|
455
|
-
if (ret.length === 0) {
|
|
456
|
-
return undefined;
|
|
457
|
-
}
|
|
458
581
|
// we need to automatically select the FKs too, e.g. for 1:m relations to be able to wire them with the items
|
|
459
582
|
if (prop.kind === ReferenceKind.ONE_TO_MANY || prop.kind === ReferenceKind.MANY_TO_MANY) {
|
|
460
583
|
const owner = prop.targetMeta.properties[prop.mappedBy];
|
|
461
|
-
|
|
584
|
+
// when the owning FK is lazy, we need to explicitly select it even without user-provided fields,
|
|
585
|
+
// otherwise the driver will exclude it and we won't be able to map children to their parent collections
|
|
586
|
+
if (owner && !ret.includes(owner.name) && (ret.length > 0 || owner.lazy)) {
|
|
462
587
|
ret.push(owner.name);
|
|
463
588
|
}
|
|
464
589
|
}
|
|
590
|
+
if (ret.length === 0) {
|
|
591
|
+
return undefined;
|
|
592
|
+
}
|
|
465
593
|
return ret;
|
|
466
594
|
}
|
|
467
595
|
getChildReferences(entities, prop, options, ref) {
|
|
468
596
|
const filtered = this.filterCollections(entities, prop.name, options, ref);
|
|
469
|
-
const children = [];
|
|
470
597
|
if (prop.kind === ReferenceKind.ONE_TO_MANY) {
|
|
471
|
-
|
|
598
|
+
return filtered.map(e => e[prop.name].owner);
|
|
472
599
|
}
|
|
473
|
-
|
|
474
|
-
|
|
600
|
+
if (prop.kind === ReferenceKind.MANY_TO_MANY && prop.owner) {
|
|
601
|
+
return filtered.reduce((a, b) => {
|
|
475
602
|
a.push(...b[prop.name].getItems());
|
|
476
603
|
return a;
|
|
477
|
-
}, [])
|
|
478
|
-
}
|
|
479
|
-
else if (prop.kind === ReferenceKind.MANY_TO_MANY) { // inverse side
|
|
480
|
-
children.push(...filtered);
|
|
604
|
+
}, []);
|
|
481
605
|
}
|
|
482
|
-
|
|
483
|
-
|
|
606
|
+
if (prop.kind === ReferenceKind.MANY_TO_MANY) { // inverse side
|
|
607
|
+
return filtered;
|
|
484
608
|
}
|
|
485
|
-
|
|
609
|
+
// MANY_TO_ONE or ONE_TO_ONE
|
|
610
|
+
return this.filterReferences(entities, prop.name, options, ref);
|
|
486
611
|
}
|
|
487
612
|
filterCollections(entities, field, options, ref) {
|
|
488
613
|
if (options.refresh) {
|
|
@@ -499,7 +624,7 @@ export class EntityLoader {
|
|
|
499
624
|
return wrapped.__loadedProperties.has(field);
|
|
500
625
|
}
|
|
501
626
|
const [f, ...r] = field.split('.');
|
|
502
|
-
/* v8 ignore next
|
|
627
|
+
/* v8 ignore next */
|
|
503
628
|
if (!wrapped.__loadedProperties.has(f) || !wrapped.__meta.properties[f]?.targetMeta) {
|
|
504
629
|
return false;
|
|
505
630
|
}
|
|
@@ -532,7 +657,7 @@ export class EntityLoader {
|
|
|
532
657
|
.map(e => Reference.unwrapReference(e[field]));
|
|
533
658
|
}
|
|
534
659
|
filterByReferences(entities, field, refresh) {
|
|
535
|
-
/* v8 ignore next
|
|
660
|
+
/* v8 ignore next */
|
|
536
661
|
if (refresh) {
|
|
537
662
|
return entities;
|
|
538
663
|
}
|
|
@@ -558,33 +683,36 @@ export class EntityLoader {
|
|
|
558
683
|
}
|
|
559
684
|
return `${this.getRelationName(meta, meta.properties[prop.embedded[0]])}.${prop.embedded[1]}`;
|
|
560
685
|
}
|
|
561
|
-
lookupEagerLoadedRelationships(entityName, populate, strategy, prefix = '', visited = []) {
|
|
686
|
+
lookupEagerLoadedRelationships(entityName, populate, strategy, prefix = '', visited = [], exclude) {
|
|
562
687
|
const meta = this.metadata.find(entityName);
|
|
563
688
|
if (!meta && !prefix) {
|
|
564
689
|
return populate;
|
|
565
690
|
}
|
|
566
|
-
if (visited.includes(
|
|
691
|
+
if (!meta || visited.includes(meta)) {
|
|
567
692
|
return [];
|
|
568
693
|
}
|
|
569
|
-
visited.push(
|
|
694
|
+
visited.push(meta);
|
|
570
695
|
const ret = prefix === '' ? [...populate] : [];
|
|
571
696
|
meta.relations
|
|
572
697
|
.filter(prop => {
|
|
698
|
+
const field = this.getRelationName(meta, prop);
|
|
699
|
+
const prefixed = prefix ? `${prefix}.${field}` : field;
|
|
700
|
+
const isExcluded = exclude?.includes(prefixed);
|
|
573
701
|
const eager = prop.eager && !populate.some(p => p.field === `${prop.name}:ref`);
|
|
574
702
|
const populated = populate.some(p => p.field === prop.name);
|
|
575
703
|
const disabled = populate.some(p => p.field === prop.name && p.all === false);
|
|
576
|
-
return !disabled && (eager || populated);
|
|
704
|
+
return !disabled && !isExcluded && (eager || populated);
|
|
577
705
|
})
|
|
578
706
|
.forEach(prop => {
|
|
579
707
|
const field = this.getRelationName(meta, prop);
|
|
580
708
|
const prefixed = prefix ? `${prefix}.${field}` : field;
|
|
581
709
|
const nestedPopulate = populate.filter(p => p.field === prop.name).flatMap(p => p.children).filter(Boolean);
|
|
582
|
-
const nested = this.lookupEagerLoadedRelationships(prop.
|
|
710
|
+
const nested = this.lookupEagerLoadedRelationships(prop.targetMeta.class, nestedPopulate, strategy, prefixed, visited.slice(), exclude);
|
|
583
711
|
if (nested.length > 0) {
|
|
584
712
|
ret.push(...nested);
|
|
585
713
|
}
|
|
586
714
|
else {
|
|
587
|
-
const selfReferencing = [meta.
|
|
715
|
+
const selfReferencing = [meta.tableName, ...visited.map(m => m.tableName)].includes(prop.targetMeta.tableName) && prop.eager;
|
|
588
716
|
ret.push({
|
|
589
717
|
field: prefixed,
|
|
590
718
|
// enforce select-in strategy for self-referencing relations
|
|
@@ -2,7 +2,7 @@ import type { PopulatePath } from '../enums.js';
|
|
|
2
2
|
import type { CreateOptions, EntityManager, MergeOptions } from '../EntityManager.js';
|
|
3
3
|
import type { AssignOptions } from './EntityAssigner.js';
|
|
4
4
|
import type { EntityData, EntityName, Primary, Loaded, FilterQuery, EntityDictionary, AutoPath, RequiredEntityData, Ref, EntityType, EntityDTO, MergeSelected, FromEntityType, IsSubset, MergeLoaded, ArrayElement } from '../typings.js';
|
|
5
|
-
import type { CountOptions, DeleteOptions, FindAllOptions, FindByCursorOptions, FindOneOptions, FindOneOrFailOptions, FindOptions, GetReferenceOptions, NativeInsertUpdateOptions, UpdateOptions, UpsertManyOptions, UpsertOptions } from '../drivers/IDatabaseDriver.js';
|
|
5
|
+
import type { CountOptions, DeleteOptions, FindAllOptions, FindByCursorOptions, FindOneOptions, FindOneOrFailOptions, FindOptions, GetReferenceOptions, NativeInsertUpdateOptions, StreamOptions, UpdateOptions, UpsertManyOptions, UpsertOptions } from '../drivers/IDatabaseDriver.js';
|
|
6
6
|
import type { EntityLoaderOptions } from './EntityLoader.js';
|
|
7
7
|
import type { Cursor } from '../utils/Cursor.js';
|
|
8
8
|
export declare class EntityRepository<Entity extends object> {
|
|
@@ -80,11 +80,15 @@ 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>(
|
|
83
|
+
findByCursor<Hint extends string = never, Fields extends string = '*', Excludes extends string = never, IncludeCount extends boolean = true>(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
|
*/
|
|
87
87
|
findAll<Hint extends string = never, Fields extends string = '*', Excludes extends string = never>(options?: FindAllOptions<Entity, Hint, Fields, Excludes>): Promise<Loaded<Entity, Hint, Fields, Excludes>[]>;
|
|
88
|
+
/**
|
|
89
|
+
* @inheritDoc EntityManager.stream
|
|
90
|
+
*/
|
|
91
|
+
stream<Hint extends string = never, Fields extends string = '*', Excludes extends string = never>(options?: StreamOptions<Entity, Hint, Fields, Excludes>): AsyncIterableIterator<Loaded<Entity, Hint, Fields, Excludes>>;
|
|
88
92
|
/**
|
|
89
93
|
* @inheritDoc EntityManager.insert
|
|
90
94
|
*/
|
|
@@ -107,10 +111,26 @@ export declare class EntityRepository<Entity extends object> {
|
|
|
107
111
|
map(result: EntityDictionary<Entity>, options?: {
|
|
108
112
|
schema?: string;
|
|
109
113
|
}): Entity;
|
|
114
|
+
/**
|
|
115
|
+
* Gets a reference to the entity identified by the given type and alternate key property without actually loading it.
|
|
116
|
+
* The key option specifies which property to use for identity map lookup instead of the primary key.
|
|
117
|
+
*/
|
|
118
|
+
getReference<K extends string & keyof Entity>(id: Entity[K], options: Omit<GetReferenceOptions, 'key' | 'wrapped'> & {
|
|
119
|
+
key: K;
|
|
120
|
+
wrapped: true;
|
|
121
|
+
}): Ref<Entity>;
|
|
122
|
+
/**
|
|
123
|
+
* Gets a reference to the entity identified by the given type and alternate key property without actually loading it.
|
|
124
|
+
* The key option specifies which property to use for identity map lookup instead of the primary key.
|
|
125
|
+
*/
|
|
126
|
+
getReference<K extends string & keyof Entity>(id: Entity[K], options: Omit<GetReferenceOptions, 'key'> & {
|
|
127
|
+
key: K;
|
|
128
|
+
wrapped?: false;
|
|
129
|
+
}): Entity;
|
|
110
130
|
/**
|
|
111
131
|
* Gets a reference to the entity identified by the given type and identifier without actually loading it, if the entity is not yet loaded
|
|
112
132
|
*/
|
|
113
|
-
getReference(id: Primary<Entity>, options: Omit<GetReferenceOptions, 'wrapped'> & {
|
|
133
|
+
getReference(id: Primary<Entity>, options: Omit<GetReferenceOptions, 'wrapped' | 'key'> & {
|
|
114
134
|
wrapped: true;
|
|
115
135
|
}): Ref<Entity>;
|
|
116
136
|
/**
|
|
@@ -120,7 +140,7 @@ export declare class EntityRepository<Entity extends object> {
|
|
|
120
140
|
/**
|
|
121
141
|
* Gets a reference to the entity identified by the given type and identifier without actually loading it, if the entity is not yet loaded
|
|
122
142
|
*/
|
|
123
|
-
getReference(id: Primary<Entity>, options: Omit<GetReferenceOptions, 'wrapped'> & {
|
|
143
|
+
getReference(id: Primary<Entity>, options: Omit<GetReferenceOptions, 'wrapped' | 'key'> & {
|
|
124
144
|
wrapped: false;
|
|
125
145
|
}): Entity;
|
|
126
146
|
/**
|
|
@@ -146,13 +166,13 @@ export declare class EntityRepository<Entity extends object> {
|
|
|
146
166
|
* The newly created entity will be automatically marked for persistence via `em.persist` unless you disable this
|
|
147
167
|
* behavior, either locally via `persist: false` option, or globally via `persistOnCreate` ORM config option.
|
|
148
168
|
*/
|
|
149
|
-
create<Convert extends boolean = false>(data: RequiredEntityData<Entity, never, Convert>, options?: CreateOptions<Convert>): Entity;
|
|
169
|
+
create<Convert extends boolean = false, Data extends RequiredEntityData<Entity, never, Convert> = RequiredEntityData<Entity, never, Convert>>(data: Data & IsSubset<RequiredEntityData<Entity, never, Convert>, Data>, options?: CreateOptions<Convert>): Entity;
|
|
150
170
|
/**
|
|
151
171
|
* Creates new instance of given entity and populates it with given data.
|
|
152
172
|
* The entity constructor will be used unless you provide `{ managed: true }` in the `options` parameter.
|
|
153
173
|
* The constructor will be given parameters based on the defined constructor of the entity. If the constructor
|
|
154
174
|
* parameter matches a property name, its value will be extracted from `data`. If no matching property exists,
|
|
155
|
-
* the whole `data` parameter will be
|
|
175
|
+
* the whole `data` parameter will be pass. This means we can also define `constructor(data: Partial<T>)` and
|
|
156
176
|
* `em.create()` will pass the data into it (unless we have a property named `data` too).
|
|
157
177
|
*
|
|
158
178
|
* The parameters are strictly checked, you need to provide all required properties. You can use `OptionalProps`
|
|
@@ -162,7 +182,7 @@ export declare class EntityRepository<Entity extends object> {
|
|
|
162
182
|
* The newly created entity will be automatically marked for persistence via `em.persist` unless you disable this
|
|
163
183
|
* behavior, either locally via `persist: false` option, or globally via `persistOnCreate` ORM config option.
|
|
164
184
|
*/
|
|
165
|
-
create<Convert extends boolean = false>(data: EntityData<Entity, Convert>, options: CreateOptions<Convert> & {
|
|
185
|
+
create<Convert extends boolean = false, Data extends EntityData<Entity, Convert> = EntityData<Entity, Convert>>(data: Data & IsSubset<EntityData<Entity, Convert>, Data>, options: CreateOptions<Convert> & {
|
|
166
186
|
partial: true;
|
|
167
187
|
}): Entity;
|
|
168
188
|
/**
|
|
@@ -90,8 +90,8 @@ export class EntityRepository {
|
|
|
90
90
|
/**
|
|
91
91
|
* @inheritDoc EntityManager.findByCursor
|
|
92
92
|
*/
|
|
93
|
-
async findByCursor(
|
|
94
|
-
return this.getEntityManager().findByCursor(this.entityName,
|
|
93
|
+
async findByCursor(options) {
|
|
94
|
+
return this.getEntityManager().findByCursor(this.entityName, options);
|
|
95
95
|
}
|
|
96
96
|
/**
|
|
97
97
|
* Finds all entities of given type. You can pass additional options via the `options` parameter.
|
|
@@ -99,6 +99,12 @@ export class EntityRepository {
|
|
|
99
99
|
async findAll(options) {
|
|
100
100
|
return this.getEntityManager().findAll(this.entityName, options);
|
|
101
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* @inheritDoc EntityManager.stream
|
|
104
|
+
*/
|
|
105
|
+
async *stream(options) {
|
|
106
|
+
yield* this.getEntityManager().stream(this.entityName, options);
|
|
107
|
+
}
|
|
102
108
|
/**
|
|
103
109
|
* @inheritDoc EntityManager.insert
|
|
104
110
|
*/
|