@mikro-orm/core 7.0.0-rc.3 → 7.0.1-dev.0
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 +2 -15
- package/EntityManager.js +155 -152
- package/MikroORM.d.ts +4 -6
- package/MikroORM.js +20 -20
- package/README.md +5 -4
- package/cache/FileCacheAdapter.d.ts +1 -5
- package/cache/FileCacheAdapter.js +22 -22
- package/cache/GeneratedCacheAdapter.d.ts +1 -1
- package/cache/GeneratedCacheAdapter.js +6 -6
- package/cache/MemoryCacheAdapter.d.ts +1 -2
- package/cache/MemoryCacheAdapter.js +8 -8
- package/cache/index.d.ts +1 -1
- package/cache/index.js +0 -1
- package/connections/Connection.d.ts +1 -0
- package/connections/Connection.js +27 -11
- package/drivers/DatabaseDriver.d.ts +0 -2
- package/drivers/DatabaseDriver.js +2 -4
- package/entity/Collection.d.ts +1 -9
- package/entity/Collection.js +95 -105
- package/entity/EntityFactory.d.ts +1 -8
- package/entity/EntityFactory.js +48 -48
- package/entity/EntityLoader.d.ts +1 -3
- package/entity/EntityLoader.js +36 -39
- package/entity/Reference.d.ts +1 -2
- package/entity/Reference.js +11 -11
- package/entity/WrappedEntity.d.ts +4 -2
- package/entity/defineEntity.d.ts +18 -73
- package/enums.d.ts +2 -1
- package/enums.js +1 -0
- package/errors.d.ts +11 -11
- package/errors.js +3 -13
- package/events/EventManager.d.ts +1 -4
- package/events/EventManager.js +25 -22
- package/events/index.d.ts +1 -1
- package/events/index.js +0 -1
- package/exceptions.js +8 -6
- package/hydration/ObjectHydrator.d.ts +1 -2
- package/hydration/ObjectHydrator.js +16 -16
- package/logging/DefaultLogger.js +3 -2
- package/logging/Logger.d.ts +2 -1
- package/logging/colors.js +1 -1
- package/logging/index.d.ts +1 -1
- package/logging/index.js +0 -1
- package/metadata/EntitySchema.d.ts +1 -1
- package/metadata/MetadataDiscovery.d.ts +1 -9
- package/metadata/MetadataDiscovery.js +162 -149
- package/metadata/MetadataStorage.d.ts +1 -5
- package/metadata/MetadataStorage.js +36 -36
- package/metadata/discover-entities.js +1 -1
- package/metadata/index.d.ts +1 -1
- package/metadata/index.js +0 -1
- package/naming-strategy/AbstractNamingStrategy.js +1 -1
- package/naming-strategy/EntityCaseNamingStrategy.js +1 -1
- package/naming-strategy/index.d.ts +1 -1
- package/naming-strategy/index.js +0 -1
- package/package.json +1 -1
- package/platforms/Platform.d.ts +23 -1
- package/platforms/Platform.js +57 -4
- package/serialization/EntitySerializer.js +1 -1
- package/serialization/EntityTransformer.js +4 -1
- package/serialization/SerializationContext.d.ts +4 -8
- package/serialization/SerializationContext.js +20 -15
- package/types/UuidType.d.ts +2 -0
- package/types/UuidType.js +14 -2
- package/types/index.d.ts +2 -1
- package/typings.d.ts +12 -1
- package/unit-of-work/ChangeSetComputer.d.ts +1 -6
- package/unit-of-work/ChangeSetComputer.js +21 -21
- package/unit-of-work/ChangeSetPersister.d.ts +1 -9
- package/unit-of-work/ChangeSetPersister.js +52 -52
- package/unit-of-work/CommitOrderCalculator.d.ts +1 -4
- package/unit-of-work/CommitOrderCalculator.js +13 -13
- package/unit-of-work/IdentityMap.d.ts +2 -5
- package/unit-of-work/IdentityMap.js +18 -18
- package/unit-of-work/UnitOfWork.d.ts +5 -19
- package/unit-of-work/UnitOfWork.js +182 -174
- package/utils/AbstractMigrator.d.ts +1 -1
- package/utils/AbstractMigrator.js +7 -7
- package/utils/Configuration.d.ts +90 -189
- package/utils/Configuration.js +94 -78
- package/utils/Cursor.d.ts +3 -3
- package/utils/Cursor.js +4 -4
- package/utils/EntityComparator.d.ts +8 -15
- package/utils/EntityComparator.js +49 -49
- package/utils/QueryHelper.d.ts +16 -1
- package/utils/QueryHelper.js +70 -24
- package/utils/RawQueryFragment.d.ts +4 -4
- package/utils/TransactionManager.js +1 -2
- package/utils/Utils.d.ts +1 -1
- package/utils/Utils.js +5 -4
- package/utils/clone.js +5 -0
- package/utils/fs-utils.d.ts +3 -17
- package/utils/fs-utils.js +1 -1
- package/utils/upsert-utils.js +1 -1
package/entity/EntityFactory.js
CHANGED
|
@@ -6,23 +6,23 @@ import { helper } from './wrap.js';
|
|
|
6
6
|
import { EntityHelper } from './EntityHelper.js';
|
|
7
7
|
import { JsonType } from '../types/JsonType.js';
|
|
8
8
|
export class EntityFactory {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
9
|
+
#driver;
|
|
10
|
+
#platform;
|
|
11
|
+
#config;
|
|
12
|
+
#metadata;
|
|
13
|
+
#hydrator;
|
|
14
|
+
#eventManager;
|
|
15
|
+
#comparator;
|
|
16
|
+
#em;
|
|
17
17
|
constructor(em) {
|
|
18
|
-
this
|
|
19
|
-
this
|
|
20
|
-
this
|
|
21
|
-
this
|
|
22
|
-
this
|
|
23
|
-
this
|
|
24
|
-
this
|
|
25
|
-
this
|
|
18
|
+
this.#em = em;
|
|
19
|
+
this.#driver = this.#em.getDriver();
|
|
20
|
+
this.#platform = this.#driver.getPlatform();
|
|
21
|
+
this.#config = this.#em.config;
|
|
22
|
+
this.#metadata = this.#em.getMetadata();
|
|
23
|
+
this.#hydrator = this.#config.getHydrator(this.#metadata);
|
|
24
|
+
this.#eventManager = this.#em.getEventManager();
|
|
25
|
+
this.#comparator = this.#em.getComparator();
|
|
26
26
|
}
|
|
27
27
|
create(entityName, data, options = {}) {
|
|
28
28
|
data = Reference.unwrapReference(data);
|
|
@@ -30,7 +30,7 @@ export class EntityFactory {
|
|
|
30
30
|
if (data.__entity) {
|
|
31
31
|
return data;
|
|
32
32
|
}
|
|
33
|
-
const meta = this
|
|
33
|
+
const meta = this.#metadata.get(entityName);
|
|
34
34
|
if (meta.virtual) {
|
|
35
35
|
data = { ...data };
|
|
36
36
|
const entity = this.createEntity(data, meta, options);
|
|
@@ -74,8 +74,8 @@ export class EntityFactory {
|
|
|
74
74
|
Utils.isPlainObject(data[prop.name])) {
|
|
75
75
|
data[prop.name] = Utils.getPrimaryKeyValues(data[prop.name], prop.targetMeta, true);
|
|
76
76
|
}
|
|
77
|
-
if (prop.customType instanceof JsonType && this
|
|
78
|
-
data[prop.name] = prop.customType.convertToDatabaseValue(data[prop.name], this
|
|
77
|
+
if (prop.customType instanceof JsonType && this.#platform.convertsJsonAutomatically()) {
|
|
78
|
+
data[prop.name] = prop.customType.convertToDatabaseValue(data[prop.name], this.#platform, {
|
|
79
79
|
key: prop.name,
|
|
80
80
|
mode: 'hydration',
|
|
81
81
|
});
|
|
@@ -99,11 +99,11 @@ export class EntityFactory {
|
|
|
99
99
|
loaded: options.initialized,
|
|
100
100
|
});
|
|
101
101
|
if (options.recomputeSnapshot) {
|
|
102
|
-
wrapped.__originalEntityData = this
|
|
102
|
+
wrapped.__originalEntityData = this.#comparator.prepareEntity(entity);
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
|
-
if (this
|
|
106
|
-
this
|
|
105
|
+
if (this.#eventManager.hasListeners(EventType.onInit, meta2)) {
|
|
106
|
+
this.#eventManager.dispatchEvent(EventType.onInit, { entity, meta: meta2, em: this.#em });
|
|
107
107
|
}
|
|
108
108
|
wrapped.__processing = false;
|
|
109
109
|
return entity;
|
|
@@ -111,16 +111,16 @@ export class EntityFactory {
|
|
|
111
111
|
mergeData(meta, entity, data, options = {}) {
|
|
112
112
|
// merge unchanged properties automatically
|
|
113
113
|
data = QueryHelper.processParams(data);
|
|
114
|
-
const existsData = this
|
|
114
|
+
const existsData = this.#comparator.prepareEntity(entity);
|
|
115
115
|
const originalEntityData = helper(entity).__originalEntityData ?? {};
|
|
116
|
-
const diff = this
|
|
116
|
+
const diff = this.#comparator.diffEntities(meta.class, originalEntityData, existsData);
|
|
117
117
|
// version properties are not part of entity snapshots
|
|
118
118
|
if (meta.versionProperty &&
|
|
119
119
|
data[meta.versionProperty] &&
|
|
120
120
|
data[meta.versionProperty] !== originalEntityData[meta.versionProperty]) {
|
|
121
121
|
diff[meta.versionProperty] = data[meta.versionProperty];
|
|
122
122
|
}
|
|
123
|
-
const diff2 = this
|
|
123
|
+
const diff2 = this.#comparator.diffEntities(meta.class, existsData, data, { includeInverseSides: true });
|
|
124
124
|
// do not override values changed by user
|
|
125
125
|
Utils.keys(diff).forEach(key => delete diff2[key]);
|
|
126
126
|
Utils.keys(diff2)
|
|
@@ -143,7 +143,7 @@ export class EntityFactory {
|
|
|
143
143
|
const initialized = options.initialized || helper(entity).__initialized;
|
|
144
144
|
this.hydrate(entity, meta, diff2, initialized ? { ...options, initialized } : options);
|
|
145
145
|
// we need to update the entity data only with keys that were not present before
|
|
146
|
-
const nullVal = this
|
|
146
|
+
const nullVal = this.#config.get('forceUndefined') ? undefined : null;
|
|
147
147
|
Utils.keys(diff2).forEach(key => {
|
|
148
148
|
const prop = meta.properties[key];
|
|
149
149
|
if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) &&
|
|
@@ -155,8 +155,8 @@ export class EntityFactory {
|
|
|
155
155
|
[ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE, ReferenceKind.SCALAR].includes(prop.kind) &&
|
|
156
156
|
prop.customType?.ensureComparable(meta, prop) &&
|
|
157
157
|
diff2[key] != null) {
|
|
158
|
-
const converted = prop.customType.convertToJSValue(diff2[key], this
|
|
159
|
-
diff2[key] = prop.customType.convertToDatabaseValue(converted, this
|
|
158
|
+
const converted = prop.customType.convertToJSValue(diff2[key], this.#platform, { force: true });
|
|
159
|
+
diff2[key] = prop.customType.convertToDatabaseValue(converted, this.#platform, { fromQuery: true });
|
|
160
160
|
}
|
|
161
161
|
originalEntityData[key] = diff2[key] === null ? nullVal : diff2[key];
|
|
162
162
|
helper(entity).__loadedProperties.add(key);
|
|
@@ -183,8 +183,8 @@ export class EntityFactory {
|
|
|
183
183
|
}
|
|
184
184
|
createReference(entityName, id, options = {}) {
|
|
185
185
|
options.convertCustomTypes ??= true;
|
|
186
|
-
const meta = this
|
|
187
|
-
const schema = this
|
|
186
|
+
const meta = this.#metadata.get(entityName);
|
|
187
|
+
const schema = this.#driver.getSchemaName(meta, options);
|
|
188
188
|
// Handle alternate key lookup
|
|
189
189
|
if (options.key) {
|
|
190
190
|
const value = '' + (Array.isArray(id) ? id[0] : Utils.isPlainObject(id) ? id[options.key] : id);
|
|
@@ -208,7 +208,7 @@ export class EntityFactory {
|
|
|
208
208
|
if (Array.isArray(id)) {
|
|
209
209
|
id = Utils.getPrimaryKeyCondFromArray(id, meta);
|
|
210
210
|
}
|
|
211
|
-
const pks = Utils.getOrderedPrimaryKeys(id, meta, this
|
|
211
|
+
const pks = Utils.getOrderedPrimaryKeys(id, meta, this.#platform);
|
|
212
212
|
const exists = this.unitOfWork.getById(entityName, pks, schema, options.convertCustomTypes);
|
|
213
213
|
if (exists) {
|
|
214
214
|
return exists;
|
|
@@ -220,15 +220,15 @@ export class EntityFactory {
|
|
|
220
220
|
}
|
|
221
221
|
createEmbeddable(entityName, data, options = {}) {
|
|
222
222
|
data = { ...data };
|
|
223
|
-
const meta = this
|
|
223
|
+
const meta = this.#metadata.get(entityName);
|
|
224
224
|
const meta2 = this.processDiscriminatorColumn(meta, data);
|
|
225
225
|
return this.createEntity(data, meta2, options);
|
|
226
226
|
}
|
|
227
227
|
getComparator() {
|
|
228
|
-
return this
|
|
228
|
+
return this.#comparator;
|
|
229
229
|
}
|
|
230
230
|
createEntity(data, meta, options) {
|
|
231
|
-
const schema = this
|
|
231
|
+
const schema = this.#driver.getSchemaName(meta, options);
|
|
232
232
|
if (options.newEntity || meta.forceConstructor || meta.virtual) {
|
|
233
233
|
if (meta.polymorphs) {
|
|
234
234
|
throw new Error(`Cannot create entity ${meta.className}, class prototype is unknown`);
|
|
@@ -239,7 +239,7 @@ export class EntityFactory {
|
|
|
239
239
|
const entity = new Entity(...params);
|
|
240
240
|
// creating managed entity instance when `forceEntityConstructor` is enabled,
|
|
241
241
|
// we need to wipe all the values as they would cause update queries on next flush
|
|
242
|
-
if (!options.newEntity && (meta.forceConstructor || this
|
|
242
|
+
if (!options.newEntity && (meta.forceConstructor || this.#config.get('forceEntityConstructor'))) {
|
|
243
243
|
meta.props
|
|
244
244
|
.filter(prop => prop.persist !== false && !prop.primary && data[prop.name] === undefined)
|
|
245
245
|
.forEach(prop => delete entity[prop.name]);
|
|
@@ -259,7 +259,7 @@ export class EntityFactory {
|
|
|
259
259
|
helper(entity).__processing = !meta.embeddable && !meta.virtual;
|
|
260
260
|
helper(entity).__schema = schema;
|
|
261
261
|
if (options.merge && !options.newEntity) {
|
|
262
|
-
this
|
|
262
|
+
this.#hydrator.hydrateReference(entity, meta, data, this, options.convertCustomTypes, options.schema, options.parentSchema);
|
|
263
263
|
this.unitOfWork.register(entity);
|
|
264
264
|
}
|
|
265
265
|
if (options.initialized) {
|
|
@@ -270,35 +270,35 @@ export class EntityFactory {
|
|
|
270
270
|
assignDefaultValues(entity, meta) {
|
|
271
271
|
for (const prop of meta.props) {
|
|
272
272
|
if (prop.onCreate) {
|
|
273
|
-
entity[prop.name] ??= prop.onCreate(entity, this
|
|
273
|
+
entity[prop.name] ??= prop.onCreate(entity, this.#em);
|
|
274
274
|
}
|
|
275
275
|
}
|
|
276
276
|
}
|
|
277
277
|
hydrate(entity, meta, data, options) {
|
|
278
278
|
if (options.initialized) {
|
|
279
|
-
this
|
|
279
|
+
this.#hydrator.hydrate(entity, meta, data, this, 'full', options.newEntity, options.convertCustomTypes, options.schema, this.#driver.getSchemaName(meta, options), options.normalizeAccessors);
|
|
280
280
|
}
|
|
281
281
|
else {
|
|
282
|
-
this
|
|
282
|
+
this.#hydrator.hydrateReference(entity, meta, data, this, options.convertCustomTypes, options.schema, this.#driver.getSchemaName(meta, options), options.normalizeAccessors);
|
|
283
283
|
}
|
|
284
284
|
Utils.keys(data).forEach(key => {
|
|
285
285
|
helper(entity)?.__loadedProperties.add(key);
|
|
286
286
|
helper(entity)?.__serializationContext.fields?.add(key);
|
|
287
287
|
});
|
|
288
|
-
const processOnCreateHooksEarly = options.processOnCreateHooksEarly ?? this
|
|
288
|
+
const processOnCreateHooksEarly = options.processOnCreateHooksEarly ?? this.#config.get('processOnCreateHooksEarly');
|
|
289
289
|
if (options.newEntity && processOnCreateHooksEarly) {
|
|
290
290
|
this.assignDefaultValues(entity, meta);
|
|
291
291
|
}
|
|
292
292
|
}
|
|
293
293
|
findEntity(data, meta, options) {
|
|
294
|
-
const schema = this
|
|
294
|
+
const schema = this.#driver.getSchemaName(meta, options);
|
|
295
295
|
if (meta.simplePK) {
|
|
296
296
|
return this.unitOfWork.getById(meta.class, data[meta.primaryKeys[0]], schema);
|
|
297
297
|
}
|
|
298
298
|
if (!Array.isArray(data) && meta.primaryKeys.some(pk => data[pk] == null)) {
|
|
299
299
|
return undefined;
|
|
300
300
|
}
|
|
301
|
-
const pks = Utils.getOrderedPrimaryKeys(data, meta, this
|
|
301
|
+
const pks = Utils.getOrderedPrimaryKeys(data, meta, this.#platform, options.convertCustomTypes);
|
|
302
302
|
return this.unitOfWork.getById(meta.class, pks, schema);
|
|
303
303
|
}
|
|
304
304
|
processDiscriminatorColumn(meta, data) {
|
|
@@ -307,7 +307,7 @@ export class EntityFactory {
|
|
|
307
307
|
const prop = meta.properties[meta.root.discriminatorColumn];
|
|
308
308
|
const value = data[prop.name];
|
|
309
309
|
const type = meta.root.discriminatorMap[value];
|
|
310
|
-
meta = type ? this
|
|
310
|
+
meta = type ? this.#metadata.get(type) : meta;
|
|
311
311
|
return meta;
|
|
312
312
|
}
|
|
313
313
|
// Handle TPT discriminator (computed at query time)
|
|
@@ -315,7 +315,7 @@ export class EntityFactory {
|
|
|
315
315
|
const value = data[meta.root.tptDiscriminatorColumn];
|
|
316
316
|
if (value) {
|
|
317
317
|
const type = meta.root.discriminatorMap[value];
|
|
318
|
-
meta = type ? this
|
|
318
|
+
meta = type ? this.#metadata.get(type) : meta;
|
|
319
319
|
}
|
|
320
320
|
}
|
|
321
321
|
return meta;
|
|
@@ -330,7 +330,7 @@ export class EntityFactory {
|
|
|
330
330
|
return;
|
|
331
331
|
}
|
|
332
332
|
if (pk.type === 'ObjectId' && (data[pk.name] != null || data[spk.name] != null)) {
|
|
333
|
-
data[pk.name] = this
|
|
333
|
+
data[pk.name] = this.#platform.denormalizePrimaryKey((data[spk.name] || data[pk.name]));
|
|
334
334
|
delete data[spk.name];
|
|
335
335
|
}
|
|
336
336
|
}
|
|
@@ -380,18 +380,18 @@ export class EntityFactory {
|
|
|
380
380
|
tmp[prop.name] = Reference.wrapReference(this.create(prop.targetMeta.class, tmp[prop.name], options), prop);
|
|
381
381
|
}
|
|
382
382
|
else if (prop.kind === ReferenceKind.SCALAR) {
|
|
383
|
-
tmp[prop.name] = prop.customType.convertToJSValue(tmp[prop.name], this
|
|
383
|
+
tmp[prop.name] = prop.customType.convertToJSValue(tmp[prop.name], this.#platform);
|
|
384
384
|
}
|
|
385
385
|
}
|
|
386
386
|
return tmp;
|
|
387
387
|
}
|
|
388
388
|
if (options.convertCustomTypes && prop.customType && value != null) {
|
|
389
|
-
return prop.customType.convertToJSValue(value, this
|
|
389
|
+
return prop.customType.convertToJSValue(value, this.#platform);
|
|
390
390
|
}
|
|
391
391
|
return value;
|
|
392
392
|
});
|
|
393
393
|
}
|
|
394
394
|
get unitOfWork() {
|
|
395
|
-
return this
|
|
395
|
+
return this.#em.getUnitOfWork(false);
|
|
396
396
|
}
|
|
397
397
|
}
|
package/entity/EntityLoader.d.ts
CHANGED
|
@@ -22,9 +22,7 @@ export interface EntityLoaderOptions<Entity, Fields extends string = PopulatePat
|
|
|
22
22
|
logging?: LoggingOptions;
|
|
23
23
|
}
|
|
24
24
|
export declare class EntityLoader {
|
|
25
|
-
private
|
|
26
|
-
private readonly metadata;
|
|
27
|
-
private readonly driver;
|
|
25
|
+
#private;
|
|
28
26
|
constructor(em: EntityManager);
|
|
29
27
|
/**
|
|
30
28
|
* Loads specified relations in batch.
|
package/entity/EntityLoader.js
CHANGED
|
@@ -7,13 +7,13 @@ import { helper } from './wrap.js';
|
|
|
7
7
|
import { expandDotPaths } from './utils.js';
|
|
8
8
|
import { Raw } from '../utils/RawQueryFragment.js';
|
|
9
9
|
export class EntityLoader {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
#metadata;
|
|
11
|
+
#driver;
|
|
12
|
+
#em;
|
|
13
13
|
constructor(em) {
|
|
14
|
-
this
|
|
15
|
-
this
|
|
16
|
-
this
|
|
14
|
+
this.#em = em;
|
|
15
|
+
this.#metadata = this.#em.getMetadata();
|
|
16
|
+
this.#driver = this.#em.getDriver();
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
19
19
|
* Loads specified relations in batch.
|
|
@@ -23,7 +23,7 @@ export class EntityLoader {
|
|
|
23
23
|
if (entities.length === 0 || Utils.isEmpty(populate)) {
|
|
24
24
|
return this.setSerializationContext(entities, populate, options);
|
|
25
25
|
}
|
|
26
|
-
const meta = this
|
|
26
|
+
const meta = this.#metadata.find(entityName);
|
|
27
27
|
if (entities.some(e => !e.__helper)) {
|
|
28
28
|
const entity = entities.find(e => !Utils.isEntity(e));
|
|
29
29
|
throw ValidationError.notDiscoveredEntity(entity, meta, 'populate');
|
|
@@ -40,7 +40,7 @@ export class EntityLoader {
|
|
|
40
40
|
await this.populateScalar(meta, references, { ...options, populateWhere: undefined });
|
|
41
41
|
}
|
|
42
42
|
populate = this.normalizePopulate(entityName, populate, options.strategy, options.lookup, options.exclude);
|
|
43
|
-
const invalid = populate.find(({ field }) => !this
|
|
43
|
+
const invalid = populate.find(({ field }) => !this.#em.canPopulate(entityName, field));
|
|
44
44
|
/* v8 ignore next */
|
|
45
45
|
if (options.validate && invalid) {
|
|
46
46
|
throw ValidationError.invalidPropertyName(entityName, invalid.field);
|
|
@@ -57,7 +57,7 @@ export class EntityLoader {
|
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
normalizePopulate(entityName, populate, strategy, lookup = true, exclude) {
|
|
60
|
-
const meta = this
|
|
60
|
+
const meta = this.#metadata.find(entityName);
|
|
61
61
|
let normalized = Utils.asArray(populate).map(field => {
|
|
62
62
|
// oxfmt-ignore
|
|
63
63
|
return typeof field === 'boolean' || field.field === PopulatePath.ALL ? { all: !!field, field: meta.primaryKeys[0] } : field;
|
|
@@ -118,9 +118,9 @@ export class EntityLoader {
|
|
|
118
118
|
*/
|
|
119
119
|
async populateMany(entityName, entities, populate, options) {
|
|
120
120
|
const [field, ref] = populate.field.split(':', 2);
|
|
121
|
-
const meta = this
|
|
121
|
+
const meta = this.#metadata.find(entityName);
|
|
122
122
|
const prop = meta.properties[field];
|
|
123
|
-
if (prop.kind === ReferenceKind.MANY_TO_MANY && prop.owner && !this
|
|
123
|
+
if (prop.kind === ReferenceKind.MANY_TO_MANY && prop.owner && !this.#driver.getPlatform().usesPivotTable()) {
|
|
124
124
|
const filtered = entities.filter(e => !e[prop.name]?.isInitialized());
|
|
125
125
|
if (filtered.length > 0) {
|
|
126
126
|
await this.populateScalar(meta, filtered, { ...options, fields: [prop.name] });
|
|
@@ -144,7 +144,7 @@ export class EntityLoader {
|
|
|
144
144
|
Utils.isObject(orderBy[prop.name]))
|
|
145
145
|
.flatMap(orderBy => orderBy[prop.name]);
|
|
146
146
|
const where = await this.extractChildCondition(options, prop);
|
|
147
|
-
if (prop.kind === ReferenceKind.MANY_TO_MANY && this
|
|
147
|
+
if (prop.kind === ReferenceKind.MANY_TO_MANY && this.#driver.getPlatform().usesPivotTable()) {
|
|
148
148
|
const pivotOrderBy = QueryHelper.mergeOrderBy(innerOrderBy, prop.orderBy, prop.targetMeta?.orderBy);
|
|
149
149
|
const res = await this.findChildrenFromPivotTable(filtered, prop, options, pivotOrderBy, populate, !!ref);
|
|
150
150
|
return Utils.flatten(res);
|
|
@@ -164,9 +164,9 @@ export class EntityLoader {
|
|
|
164
164
|
async populateScalar(meta, filtered, options) {
|
|
165
165
|
const pk = Utils.getPrimaryKeyHash(meta.primaryKeys);
|
|
166
166
|
const ids = Utils.unique(filtered.map(e => Utils.getPrimaryKeyValues(e, meta, true)));
|
|
167
|
-
const where = this.mergePrimaryCondition(ids, pk, options, meta, this
|
|
167
|
+
const where = this.mergePrimaryCondition(ids, pk, options, meta, this.#metadata, this.#driver.getPlatform());
|
|
168
168
|
const { filters, convertCustomTypes, lockMode, strategy, populateWhere, connectionType, logging, fields } = options;
|
|
169
|
-
await this
|
|
169
|
+
await this.#em.find(meta.class, where, {
|
|
170
170
|
filters,
|
|
171
171
|
convertCustomTypes,
|
|
172
172
|
lockMode,
|
|
@@ -179,7 +179,7 @@ export class EntityLoader {
|
|
|
179
179
|
});
|
|
180
180
|
}
|
|
181
181
|
async populatePolymorphic(entities, prop, options, ref) {
|
|
182
|
-
const ownerMeta = this
|
|
182
|
+
const ownerMeta = this.#metadata.get(entities[0].constructor);
|
|
183
183
|
// Separate entities: those with loaded refs vs those needing FK load
|
|
184
184
|
const toPopulate = [];
|
|
185
185
|
const needsFkLoad = [];
|
|
@@ -230,7 +230,7 @@ export class EntityLoader {
|
|
|
230
230
|
// Load each group concurrently - identity map handles merging with existing references
|
|
231
231
|
const allItems = [];
|
|
232
232
|
await Promise.all([...groups].map(async ([discriminator, children]) => {
|
|
233
|
-
const targetMeta = this
|
|
233
|
+
const targetMeta = this.#metadata.find(prop.discriminatorMap[discriminator]);
|
|
234
234
|
await this.populateScalar(targetMeta, children, options);
|
|
235
235
|
allItems.push(...children);
|
|
236
236
|
}));
|
|
@@ -240,7 +240,7 @@ export class EntityLoader {
|
|
|
240
240
|
if (prop.kind === ReferenceKind.ONE_TO_MANY) {
|
|
241
241
|
this.initializeOneToMany(filtered, children, prop, field, partial);
|
|
242
242
|
}
|
|
243
|
-
if (prop.kind === ReferenceKind.MANY_TO_MANY && !this
|
|
243
|
+
if (prop.kind === ReferenceKind.MANY_TO_MANY && !this.#driver.getPlatform().usesPivotTable()) {
|
|
244
244
|
this.initializeManyToMany(filtered, children, prop, field, customOrder, partial);
|
|
245
245
|
}
|
|
246
246
|
}
|
|
@@ -254,7 +254,7 @@ export class EntityLoader {
|
|
|
254
254
|
for (const child of children) {
|
|
255
255
|
const pk = child.__helper.__data[prop.mappedBy] ?? child[prop.mappedBy];
|
|
256
256
|
if (pk) {
|
|
257
|
-
const key = helper(mapToPk ? this
|
|
257
|
+
const key = helper(mapToPk ? this.#em.getReference(prop.targetMeta.class, pk) : pk).getSerializedPrimaryKey();
|
|
258
258
|
map[key]?.push(child);
|
|
259
259
|
}
|
|
260
260
|
}
|
|
@@ -322,10 +322,10 @@ export class EntityLoader {
|
|
|
322
322
|
where = (conditions.length === 1 ? conditions[0] : { $or: conditions });
|
|
323
323
|
}
|
|
324
324
|
else {
|
|
325
|
-
where = this.mergePrimaryCondition(ids, fk, options, meta, this
|
|
325
|
+
where = this.mergePrimaryCondition(ids, fk, options, meta, this.#metadata, this.#driver.getPlatform());
|
|
326
326
|
}
|
|
327
327
|
if (polymorphicOwnerProp) {
|
|
328
|
-
const parentMeta = this
|
|
328
|
+
const parentMeta = this.#metadata.find(entities[0].constructor);
|
|
329
329
|
const discriminatorValue = QueryHelper.findDiscriminatorValue(polymorphicOwnerProp.discriminatorMap, parentMeta.class) ??
|
|
330
330
|
parentMeta.tableName;
|
|
331
331
|
const discriminatorColumn = polymorphicOwnerProp.fieldNames[0];
|
|
@@ -342,7 +342,7 @@ export class EntityLoader {
|
|
|
342
342
|
where = { $and: [where, prop.where] };
|
|
343
343
|
}
|
|
344
344
|
const orderBy = QueryHelper.mergeOrderBy(options.orderBy, prop.orderBy);
|
|
345
|
-
const items = await this
|
|
345
|
+
const items = await this.#em.find(meta.class, where, {
|
|
346
346
|
filters,
|
|
347
347
|
convertCustomTypes,
|
|
348
348
|
lockMode,
|
|
@@ -385,7 +385,7 @@ export class EntityLoader {
|
|
|
385
385
|
}
|
|
386
386
|
}
|
|
387
387
|
if ([ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(prop.kind) && items.length !== children.length) {
|
|
388
|
-
const nullVal = this
|
|
388
|
+
const nullVal = this.#em.config.get('forceUndefined') ? undefined : null;
|
|
389
389
|
const itemsMap = new Set();
|
|
390
390
|
const childrenMap = new Set();
|
|
391
391
|
// Use targetKey value if set, otherwise use serialized PK
|
|
@@ -409,8 +409,7 @@ export class EntityLoader {
|
|
|
409
409
|
for (const item of items) {
|
|
410
410
|
if (ref && !helper(item).__onLoadFired) {
|
|
411
411
|
helper(item).__initialized = false;
|
|
412
|
-
|
|
413
|
-
this.em.getUnitOfWork()['loadedEntities'].delete(item);
|
|
412
|
+
this.#em.getUnitOfWork().unmarkAsLoaded(item);
|
|
414
413
|
}
|
|
415
414
|
}
|
|
416
415
|
return { items, partial };
|
|
@@ -429,7 +428,7 @@ export class EntityLoader {
|
|
|
429
428
|
}
|
|
430
429
|
async populateField(entityName, entities, populate, options) {
|
|
431
430
|
const field = populate.field.split(':')[0];
|
|
432
|
-
const prop = this
|
|
431
|
+
const prop = this.#metadata.find(entityName).properties[field];
|
|
433
432
|
if (prop.kind === ReferenceKind.SCALAR && !prop.lazy) {
|
|
434
433
|
return;
|
|
435
434
|
}
|
|
@@ -522,29 +521,27 @@ export class EntityLoader {
|
|
|
522
521
|
const options2 = { ...options, fields, exclude, populateFilter };
|
|
523
522
|
['limit', 'offset', 'first', 'last', 'before', 'after', 'overfetch'].forEach(prop => delete options2[prop]);
|
|
524
523
|
options2.populate = populate?.children ?? [];
|
|
525
|
-
if (prop.customType) {
|
|
526
|
-
ids.forEach((id, idx) => (ids[idx] = QueryHelper.processCustomType(prop, id, this.driver.getPlatform())));
|
|
527
|
-
}
|
|
528
524
|
if (!Utils.isEmpty(prop.where)) {
|
|
529
525
|
where = { $and: [where, prop.where] };
|
|
530
526
|
}
|
|
531
|
-
const map = await this
|
|
527
|
+
const map = await this.#driver.loadFromPivotTable(prop, ids, where, orderBy, this.#em.getTransactionContext(), options2, pivotJoin);
|
|
532
528
|
const children = [];
|
|
533
|
-
for (
|
|
534
|
-
const
|
|
529
|
+
for (let i = 0; i < filtered.length; i++) {
|
|
530
|
+
const entity = filtered[i];
|
|
531
|
+
const items = map[Utils.getPrimaryKeyHash(ids[i])].map(item => {
|
|
535
532
|
if (pivotJoin) {
|
|
536
|
-
return this
|
|
533
|
+
return this.#em.getReference(prop.targetMeta.class, item, {
|
|
537
534
|
convertCustomTypes: true,
|
|
538
|
-
schema: options.schema ?? this
|
|
535
|
+
schema: options.schema ?? this.#em.config.get('schema'),
|
|
539
536
|
});
|
|
540
537
|
}
|
|
541
|
-
const entity = this
|
|
538
|
+
const entity = this.#em.getEntityFactory().create(prop.targetMeta.class, item, {
|
|
542
539
|
refresh,
|
|
543
540
|
merge: true,
|
|
544
541
|
convertCustomTypes: true,
|
|
545
|
-
schema: options.schema ?? this
|
|
542
|
+
schema: options.schema ?? this.#em.config.get('schema'),
|
|
546
543
|
});
|
|
547
|
-
return this
|
|
544
|
+
return this.#em.getUnitOfWork().register(entity, item, { refresh, loaded: true });
|
|
548
545
|
});
|
|
549
546
|
entity[prop.name].hydrate(items, true);
|
|
550
547
|
children.push(items);
|
|
@@ -582,7 +579,7 @@ export class EntityLoader {
|
|
|
582
579
|
});
|
|
583
580
|
}
|
|
584
581
|
if (filters) {
|
|
585
|
-
return this
|
|
582
|
+
return this.#em.applyFilters(meta2.class, subCond, options.filters, 'read', options);
|
|
586
583
|
}
|
|
587
584
|
return subCond;
|
|
588
585
|
}
|
|
@@ -695,7 +692,7 @@ export class EntityLoader {
|
|
|
695
692
|
}
|
|
696
693
|
lookupAllRelationships(entityName) {
|
|
697
694
|
const ret = [];
|
|
698
|
-
const meta = this
|
|
695
|
+
const meta = this.#metadata.find(entityName);
|
|
699
696
|
meta.relations.forEach(prop => {
|
|
700
697
|
ret.push({
|
|
701
698
|
field: this.getRelationName(meta, prop),
|
|
@@ -714,7 +711,7 @@ export class EntityLoader {
|
|
|
714
711
|
return `${this.getRelationName(meta, meta.properties[prop.embedded[0]])}.${prop.embedded[1]}`;
|
|
715
712
|
}
|
|
716
713
|
lookupEagerLoadedRelationships(entityName, populate, strategy, prefix = '', visited = [], exclude) {
|
|
717
|
-
const meta = this
|
|
714
|
+
const meta = this.#metadata.find(entityName);
|
|
718
715
|
if (!meta && !prefix) {
|
|
719
716
|
return populate;
|
|
720
717
|
}
|
package/entity/Reference.d.ts
CHANGED
|
@@ -44,10 +44,9 @@ export declare class Reference<T extends object> {
|
|
|
44
44
|
toJSON(...args: any[]): Dictionary;
|
|
45
45
|
}
|
|
46
46
|
export declare class ScalarReference<Value> {
|
|
47
|
+
#private;
|
|
47
48
|
private value?;
|
|
48
|
-
private initialized;
|
|
49
49
|
private entity?;
|
|
50
|
-
private property?;
|
|
51
50
|
constructor(value?: Value | undefined, initialized?: boolean);
|
|
52
51
|
/**
|
|
53
52
|
* Ensures the underlying entity is loaded first (without reloading it if it already is loaded).
|
package/entity/Reference.js
CHANGED
|
@@ -162,12 +162,12 @@ export class Reference {
|
|
|
162
162
|
}
|
|
163
163
|
export class ScalarReference {
|
|
164
164
|
value;
|
|
165
|
-
initialized;
|
|
166
165
|
entity;
|
|
167
|
-
property;
|
|
166
|
+
#property;
|
|
167
|
+
#initialized;
|
|
168
168
|
constructor(value, initialized = value != null) {
|
|
169
169
|
this.value = value;
|
|
170
|
-
this
|
|
170
|
+
this.#initialized = initialized;
|
|
171
171
|
}
|
|
172
172
|
/**
|
|
173
173
|
* Ensures the underlying entity is loaded first (without reloading it if it already is loaded).
|
|
@@ -175,11 +175,11 @@ export class ScalarReference {
|
|
|
175
175
|
*/
|
|
176
176
|
async load(options) {
|
|
177
177
|
const opts = typeof options === 'object' ? options : { prop: options };
|
|
178
|
-
if (!this
|
|
179
|
-
if (this.entity == null || this
|
|
178
|
+
if (!this.#initialized || opts.refresh) {
|
|
179
|
+
if (this.entity == null || this.#property == null) {
|
|
180
180
|
throw new Error('Cannot load scalar reference that is not bound to an entity property.');
|
|
181
181
|
}
|
|
182
|
-
await helper(this.entity).populate([this
|
|
182
|
+
await helper(this.entity).populate([this.#property], opts);
|
|
183
183
|
}
|
|
184
184
|
return this.value;
|
|
185
185
|
}
|
|
@@ -193,29 +193,29 @@ export class ScalarReference {
|
|
|
193
193
|
const wrapped = helper(this.entity);
|
|
194
194
|
options.failHandler ??= wrapped.__em.config.get('findOneOrFailHandler');
|
|
195
195
|
const entityName = this.entity.constructor.name;
|
|
196
|
-
throw NotFoundError.failedToLoadProperty(entityName, this
|
|
196
|
+
throw NotFoundError.failedToLoadProperty(entityName, this.#property, wrapped.getPrimaryKey());
|
|
197
197
|
}
|
|
198
198
|
return ret;
|
|
199
199
|
}
|
|
200
200
|
set(value) {
|
|
201
201
|
this.value = value;
|
|
202
|
-
this
|
|
202
|
+
this.#initialized = true;
|
|
203
203
|
}
|
|
204
204
|
bind(entity, property) {
|
|
205
205
|
this.entity = entity;
|
|
206
|
-
this
|
|
206
|
+
this.#property = property;
|
|
207
207
|
Object.defineProperty(this, 'entity', { enumerable: false, value: entity });
|
|
208
208
|
}
|
|
209
209
|
unwrap() {
|
|
210
210
|
return this.value;
|
|
211
211
|
}
|
|
212
212
|
isInitialized() {
|
|
213
|
-
return this
|
|
213
|
+
return this.#initialized;
|
|
214
214
|
}
|
|
215
215
|
/** @ignore */
|
|
216
216
|
/* v8 ignore next */
|
|
217
217
|
[Symbol.for('nodejs.util.inspect.custom')]() {
|
|
218
|
-
return this
|
|
218
|
+
return this.#initialized ? `Ref<${inspect(this.value)}>` : `Ref<?>`;
|
|
219
219
|
}
|
|
220
220
|
}
|
|
221
221
|
Object.defineProperties(Reference.prototype, {
|
|
@@ -8,6 +8,8 @@ import type { EntityIdentifier } from './EntityIdentifier.js';
|
|
|
8
8
|
import type { SerializationContext } from '../serialization/SerializationContext.js';
|
|
9
9
|
import { type SerializeOptions } from '../serialization/EntitySerializer.js';
|
|
10
10
|
import type { FindOneOptions, LoadHint } from '../drivers/IDatabaseDriver.js';
|
|
11
|
+
import type { Platform } from '../platforms/Platform.js';
|
|
12
|
+
import type { Configuration } from '../utils/Configuration.js';
|
|
11
13
|
export declare class WrappedEntity<Entity extends object> {
|
|
12
14
|
__initialized: boolean;
|
|
13
15
|
__populated?: boolean;
|
|
@@ -58,7 +60,7 @@ export declare class WrappedEntity<Entity extends object> {
|
|
|
58
60
|
setPrimaryKey(id: Primary<Entity> | null): void;
|
|
59
61
|
getSerializedPrimaryKey(): string;
|
|
60
62
|
get __meta(): EntityMetadata<Entity>;
|
|
61
|
-
get __platform():
|
|
62
|
-
get __config():
|
|
63
|
+
get __platform(): Platform;
|
|
64
|
+
get __config(): Configuration;
|
|
63
65
|
get __primaryKeys(): Primary<Entity>[];
|
|
64
66
|
}
|