@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/EntityAssigner.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import { inspect } from 'node:util';
|
|
2
1
|
import { Collection } from './Collection.js';
|
|
3
2
|
import { Utils } from '../utils/Utils.js';
|
|
4
3
|
import { Reference } from './Reference.js';
|
|
5
4
|
import { ReferenceKind, SCALAR_TYPES } from '../enums.js';
|
|
6
|
-
import {
|
|
5
|
+
import { validateProperty } from './validators.js';
|
|
7
6
|
import { helper, wrap } from './wrap.js';
|
|
8
7
|
import { EntityHelper } from './EntityHelper.js';
|
|
9
|
-
|
|
8
|
+
import { ValidationError } from '../errors.js';
|
|
10
9
|
export class EntityAssigner {
|
|
11
10
|
static assign(entity, data, options = {}) {
|
|
12
11
|
let opts = options;
|
|
@@ -42,9 +41,17 @@ export class EntityAssigner {
|
|
|
42
41
|
}
|
|
43
42
|
const prop = { ...props[propName], name: propName };
|
|
44
43
|
if (prop && options.onlyOwnProperties) {
|
|
45
|
-
if ([ReferenceKind.
|
|
44
|
+
if ([ReferenceKind.ONE_TO_MANY].includes(prop.kind)) {
|
|
46
45
|
return;
|
|
47
46
|
}
|
|
47
|
+
if ([ReferenceKind.MANY_TO_MANY].includes(prop.kind)) {
|
|
48
|
+
if (!prop.owner) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
else if (value?.map) {
|
|
52
|
+
value = value.map((v) => Utils.extractPK(v, prop.targetMeta));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
48
55
|
if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind)) {
|
|
49
56
|
value = Utils.extractPK(value, prop.targetMeta);
|
|
50
57
|
}
|
|
@@ -70,7 +77,7 @@ export class EntityAssigner {
|
|
|
70
77
|
if (options.updateByPrimaryKey) {
|
|
71
78
|
const pk = Utils.extractPK(value, prop.targetMeta);
|
|
72
79
|
if (pk) {
|
|
73
|
-
const ref = options.em.getReference(prop.
|
|
80
|
+
const ref = options.em.getReference(prop.targetMeta.class, pk, options);
|
|
74
81
|
// if the PK differs, we want to change the target entity, not update it
|
|
75
82
|
const wrappedChild = helper(ref);
|
|
76
83
|
const sameTarget = wrappedChild.getSerializedPrimaryKey() === wrapped.getSerializedPrimaryKey();
|
|
@@ -86,8 +93,9 @@ export class EntityAssigner {
|
|
|
86
93
|
}
|
|
87
94
|
return EntityAssigner.assignReference(entity, value, prop, options.em, options);
|
|
88
95
|
}
|
|
89
|
-
if (prop.kind === ReferenceKind.SCALAR && SCALAR_TYPES.
|
|
90
|
-
|
|
96
|
+
if (prop.kind === ReferenceKind.SCALAR && SCALAR_TYPES.has(prop.runtimeType) && (prop.setter || !prop.getter)) {
|
|
97
|
+
validateProperty(prop, value, entity);
|
|
98
|
+
return entity[prop.name] = value;
|
|
91
99
|
}
|
|
92
100
|
if (prop.kind === ReferenceKind.EMBEDDED && EntityAssigner.validateEM(options.em)) {
|
|
93
101
|
return EntityAssigner.assignEmbeddable(entity, value, prop, options.em, options);
|
|
@@ -112,7 +120,7 @@ export class EntityAssigner {
|
|
|
112
120
|
}
|
|
113
121
|
const meta2 = helper(ref).__meta;
|
|
114
122
|
const prop2 = meta2.properties[prop.inversedBy || prop.mappedBy];
|
|
115
|
-
/* v8 ignore next
|
|
123
|
+
/* v8 ignore next */
|
|
116
124
|
if (prop2 && !ref[prop2.name]) {
|
|
117
125
|
if (Reference.isReference(ref)) {
|
|
118
126
|
ref.unwrap()[prop2.name] = Reference.wrapReference(entity, prop2);
|
|
@@ -133,13 +141,13 @@ export class EntityAssigner {
|
|
|
133
141
|
entity[prop.name] = Reference.wrapReference(value, prop);
|
|
134
142
|
}
|
|
135
143
|
else if (Utils.isPrimaryKey(value, true) && EntityAssigner.validateEM(em)) {
|
|
136
|
-
entity[prop.name] = prop.mapToPk ? value : Reference.wrapReference(em.getReference(prop.
|
|
144
|
+
entity[prop.name] = prop.mapToPk ? value : Reference.wrapReference(em.getReference(prop.targetMeta.class, value, options), prop);
|
|
137
145
|
}
|
|
138
146
|
else if (Utils.isPlainObject(value) && options.merge && EntityAssigner.validateEM(em)) {
|
|
139
|
-
entity[prop.name] = Reference.wrapReference(em.merge(prop.
|
|
147
|
+
entity[prop.name] = Reference.wrapReference(em.merge(prop.targetMeta.class, value, options), prop);
|
|
140
148
|
}
|
|
141
149
|
else if (Utils.isPlainObject(value) && EntityAssigner.validateEM(em)) {
|
|
142
|
-
entity[prop.name] = Reference.wrapReference(em.create(prop.
|
|
150
|
+
entity[prop.name] = Reference.wrapReference(em.create(prop.targetMeta.class, value, options), prop);
|
|
143
151
|
}
|
|
144
152
|
else {
|
|
145
153
|
const name = entity.constructor.name;
|
|
@@ -158,14 +166,14 @@ export class EntityAssigner {
|
|
|
158
166
|
if (options.updateNestedEntities && options.updateByPrimaryKey && Utils.isPlainObject(item)) {
|
|
159
167
|
const pk = Utils.extractPK(item, prop.targetMeta);
|
|
160
168
|
if (pk && EntityAssigner.validateEM(em)) {
|
|
161
|
-
const ref = em.getUnitOfWork().getById(prop.
|
|
169
|
+
const ref = em.getUnitOfWork().getById(prop.targetMeta.class, pk, options.schema);
|
|
162
170
|
if (ref) {
|
|
163
171
|
return EntityAssigner.assign(ref, item, options);
|
|
164
172
|
}
|
|
165
173
|
}
|
|
166
174
|
return this.createCollectionItem(item, em, prop, invalid, options);
|
|
167
175
|
}
|
|
168
|
-
/* v8 ignore next
|
|
176
|
+
/* v8 ignore next */
|
|
169
177
|
if (options.updateNestedEntities && !options.updateByPrimaryKey && collection[idx] && helper(collection[idx])?.isInitialized()) {
|
|
170
178
|
return EntityAssigner.assign(collection[idx], item, options);
|
|
171
179
|
}
|
|
@@ -173,7 +181,7 @@ export class EntityAssigner {
|
|
|
173
181
|
});
|
|
174
182
|
if (invalid.length > 0) {
|
|
175
183
|
const name = entity.constructor.name;
|
|
176
|
-
throw
|
|
184
|
+
throw ValidationError.invalidCollectionValues(name, prop.name, invalid);
|
|
177
185
|
}
|
|
178
186
|
if (Array.isArray(value)) {
|
|
179
187
|
collection.set(items);
|
|
@@ -199,7 +207,7 @@ export class EntityAssigner {
|
|
|
199
207
|
entity[propName].push(...Object.values(tmp));
|
|
200
208
|
});
|
|
201
209
|
}
|
|
202
|
-
const create = () => EntityAssigner.validateEM(em) && em.getEntityFactory().createEmbeddable(prop.
|
|
210
|
+
const create = () => EntityAssigner.validateEM(em) && em.getEntityFactory().createEmbeddable(prop.targetMeta.class, value, {
|
|
203
211
|
convertCustomTypes: options.convertCustomTypes,
|
|
204
212
|
newEntity: options.mergeEmbeddedProperties ? !('propName' in entity) : true,
|
|
205
213
|
});
|
|
@@ -213,13 +221,13 @@ export class EntityAssigner {
|
|
|
213
221
|
return item;
|
|
214
222
|
}
|
|
215
223
|
if (Utils.isPrimaryKey(item) && EntityAssigner.validateEM(em)) {
|
|
216
|
-
return em.getReference(prop.
|
|
224
|
+
return em.getReference(prop.targetMeta.class, item, options);
|
|
217
225
|
}
|
|
218
226
|
if (Utils.isPlainObject(item) && options.merge && EntityAssigner.validateEM(em)) {
|
|
219
|
-
return em.merge(prop.
|
|
227
|
+
return em.merge(prop.targetMeta.class, item, options);
|
|
220
228
|
}
|
|
221
229
|
if (Utils.isPlainObject(item) && EntityAssigner.validateEM(em)) {
|
|
222
|
-
return em.create(prop.
|
|
230
|
+
return em.create(prop.targetMeta.class, item, options);
|
|
223
231
|
}
|
|
224
232
|
invalid.push(item);
|
|
225
233
|
return item;
|
|
@@ -15,6 +15,12 @@ export interface FactoryOptions {
|
|
|
15
15
|
recomputeSnapshot?: boolean;
|
|
16
16
|
schema?: string;
|
|
17
17
|
parentSchema?: string;
|
|
18
|
+
normalizeAccessors?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Property name to use for identity map lookup instead of the primary key.
|
|
21
|
+
* This is useful for creating references by unique non-PK properties.
|
|
22
|
+
*/
|
|
23
|
+
key?: string;
|
|
18
24
|
}
|
|
19
25
|
export declare class EntityFactory {
|
|
20
26
|
private readonly em;
|
|
@@ -28,7 +34,7 @@ export declare class EntityFactory {
|
|
|
28
34
|
constructor(em: EntityManager);
|
|
29
35
|
create<T extends object, P extends string = string>(entityName: EntityName<T>, data: EntityData<T>, options?: FactoryOptions): New<T, P>;
|
|
30
36
|
mergeData<T extends object>(meta: EntityMetadata<T>, entity: T, data: EntityData<T>, options?: FactoryOptions): void;
|
|
31
|
-
createReference<T extends object>(entityName: EntityName<T>, id: Primary<T> | Primary<T>[] | Record<string, Primary<T>>, options?: Pick<FactoryOptions, 'merge' | 'convertCustomTypes' | 'schema'>): T;
|
|
37
|
+
createReference<T extends object>(entityName: EntityName<T>, id: Primary<T> | Primary<T>[] | Record<string, Primary<T>>, options?: Pick<FactoryOptions, 'merge' | 'convertCustomTypes' | 'schema' | 'key'>): T;
|
|
32
38
|
createEmbeddable<T extends object>(entityName: EntityName<T>, data: EntityData<T>, options?: Pick<FactoryOptions, 'newEntity' | 'convertCustomTypes'>): T;
|
|
33
39
|
getComparator(): EntityComparator;
|
|
34
40
|
private createEntity;
|
package/entity/EntityFactory.js
CHANGED
|
@@ -4,6 +4,7 @@ import { EventType, ReferenceKind } from '../enums.js';
|
|
|
4
4
|
import { Reference } from './Reference.js';
|
|
5
5
|
import { helper } from './wrap.js';
|
|
6
6
|
import { EntityHelper } from './EntityHelper.js';
|
|
7
|
+
import { JsonType } from '../types/JsonType.js';
|
|
7
8
|
export class EntityFactory {
|
|
8
9
|
em;
|
|
9
10
|
driver;
|
|
@@ -29,7 +30,6 @@ export class EntityFactory {
|
|
|
29
30
|
if (data.__entity) {
|
|
30
31
|
return data;
|
|
31
32
|
}
|
|
32
|
-
entityName = Utils.className(entityName);
|
|
33
33
|
const meta = this.metadata.get(entityName);
|
|
34
34
|
if (meta.virtual) {
|
|
35
35
|
data = { ...data };
|
|
@@ -37,8 +37,8 @@ export class EntityFactory {
|
|
|
37
37
|
this.hydrate(entity, meta, data, options);
|
|
38
38
|
return entity;
|
|
39
39
|
}
|
|
40
|
-
if (
|
|
41
|
-
|
|
40
|
+
if (meta.serializedPrimaryKey) {
|
|
41
|
+
this.denormalizePrimaryKey(meta, data);
|
|
42
42
|
}
|
|
43
43
|
const meta2 = this.processDiscriminatorColumn(meta, data);
|
|
44
44
|
const exists = this.findEntity(data, meta2, options);
|
|
@@ -59,7 +59,7 @@ export class EntityFactory {
|
|
|
59
59
|
wrapped.__initialized = options.initialized;
|
|
60
60
|
if (options.newEntity || meta.forceConstructor || meta.virtual) {
|
|
61
61
|
const tmp = { ...data };
|
|
62
|
-
meta.constructorParams
|
|
62
|
+
meta.constructorParams?.forEach(prop => delete tmp[prop]);
|
|
63
63
|
this.hydrate(entity, meta2, tmp, options);
|
|
64
64
|
// since we now process only a copy of the `data` via hydrator, but later we register the state with the full snapshot,
|
|
65
65
|
// we need to go through all props with custom types that have `ensureComparable: true` and ensure they are comparable
|
|
@@ -73,7 +73,9 @@ export class EntityFactory {
|
|
|
73
73
|
if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && Utils.isPlainObject(data[prop.name])) {
|
|
74
74
|
data[prop.name] = Utils.getPrimaryKeyValues(data[prop.name], prop.targetMeta, true);
|
|
75
75
|
}
|
|
76
|
-
|
|
76
|
+
if (prop.customType instanceof JsonType && this.platform.convertsJsonAutomatically()) {
|
|
77
|
+
data[prop.name] = prop.customType.convertToDatabaseValue(data[prop.name], this.platform, { key: prop.name, mode: 'hydration' });
|
|
78
|
+
}
|
|
77
79
|
}
|
|
78
80
|
}
|
|
79
81
|
}
|
|
@@ -81,8 +83,7 @@ export class EntityFactory {
|
|
|
81
83
|
else {
|
|
82
84
|
this.hydrate(entity, meta2, data, options);
|
|
83
85
|
}
|
|
84
|
-
|
|
85
|
-
if (exists && meta.discriminatorColumn && !(entity instanceof meta2.class)) {
|
|
86
|
+
if (exists && meta.root.inheritanceType && !(entity instanceof meta2.class)) {
|
|
86
87
|
Object.setPrototypeOf(entity, meta2.prototype);
|
|
87
88
|
}
|
|
88
89
|
if (options.merge && wrapped.hasPrimaryKey()) {
|
|
@@ -108,12 +109,12 @@ export class EntityFactory {
|
|
|
108
109
|
data = QueryHelper.processParams(data);
|
|
109
110
|
const existsData = this.comparator.prepareEntity(entity);
|
|
110
111
|
const originalEntityData = helper(entity).__originalEntityData ?? {};
|
|
111
|
-
const diff = this.comparator.diffEntities(meta.
|
|
112
|
+
const diff = this.comparator.diffEntities(meta.class, originalEntityData, existsData);
|
|
112
113
|
// version properties are not part of entity snapshots
|
|
113
114
|
if (meta.versionProperty && data[meta.versionProperty] && data[meta.versionProperty] !== originalEntityData[meta.versionProperty]) {
|
|
114
115
|
diff[meta.versionProperty] = data[meta.versionProperty];
|
|
115
116
|
}
|
|
116
|
-
const diff2 = this.comparator.diffEntities(meta.
|
|
117
|
+
const diff2 = this.comparator.diffEntities(meta.class, existsData, data, { includeInverseSides: true });
|
|
117
118
|
// do not override values changed by user
|
|
118
119
|
Utils.keys(diff).forEach(key => delete diff2[key]);
|
|
119
120
|
Utils.keys(diff2).filter(key => {
|
|
@@ -136,6 +137,10 @@ export class EntityFactory {
|
|
|
136
137
|
if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && Utils.isPlainObject(data[prop.name])) {
|
|
137
138
|
diff2[key] = entity[prop.name] ? helper(entity[prop.name]).getPrimaryKey(options.convertCustomTypes) : null;
|
|
138
139
|
}
|
|
140
|
+
if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE, ReferenceKind.SCALAR].includes(prop.kind) && prop.customType?.ensureComparable(meta, prop) && diff2[key] != null) {
|
|
141
|
+
const converted = prop.customType.convertToJSValue(diff2[key], this.platform, { force: true });
|
|
142
|
+
diff2[key] = prop.customType.convertToDatabaseValue(converted, this.platform, { fromQuery: true });
|
|
143
|
+
}
|
|
139
144
|
originalEntityData[key] = diff2[key] === null ? nullVal : diff2[key];
|
|
140
145
|
helper(entity).__loadedProperties.add(key);
|
|
141
146
|
});
|
|
@@ -146,20 +151,31 @@ export class EntityFactory {
|
|
|
146
151
|
// we just create the entity from scratch, which will automatically pick the right one from the identity map and call `mergeData` on it
|
|
147
152
|
data[prop.name]
|
|
148
153
|
.filter(child => Utils.isPlainObject(child)) // objects with prototype can be PKs (e.g. `ObjectId`)
|
|
149
|
-
.forEach(child => this.create(prop.
|
|
154
|
+
.forEach(child => this.create(prop.targetMeta.class, child, options)); // we can ignore the value, we just care about the `mergeData` call
|
|
150
155
|
return;
|
|
151
156
|
}
|
|
152
157
|
if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && Utils.isPlainObject(data[prop.name]) && entity[prop.name] && helper(entity[prop.name]).__initialized) {
|
|
153
|
-
this.create(prop.
|
|
158
|
+
this.create(prop.targetMeta.class, data[prop.name], options); // we can ignore the value, we just care about the `mergeData` call
|
|
154
159
|
}
|
|
155
160
|
});
|
|
156
|
-
|
|
161
|
+
this.unitOfWork.normalizeEntityData(meta, originalEntityData);
|
|
157
162
|
}
|
|
158
163
|
createReference(entityName, id, options = {}) {
|
|
159
164
|
options.convertCustomTypes ??= true;
|
|
160
|
-
entityName = Utils.className(entityName);
|
|
161
165
|
const meta = this.metadata.get(entityName);
|
|
162
166
|
const schema = this.driver.getSchemaName(meta, options);
|
|
167
|
+
// Handle alternate key lookup
|
|
168
|
+
if (options.key) {
|
|
169
|
+
const value = '' + (Array.isArray(id) ? id[0] : Utils.isPlainObject(id) ? id[options.key] : id);
|
|
170
|
+
const exists = this.unitOfWork.getByKey(entityName, options.key, value, schema, options.convertCustomTypes);
|
|
171
|
+
if (exists) {
|
|
172
|
+
return exists;
|
|
173
|
+
}
|
|
174
|
+
// Create entity stub - storeByKey will set the alternate key property and store in identity map
|
|
175
|
+
const entity = this.create(entityName, {}, { ...options, initialized: false });
|
|
176
|
+
this.unitOfWork.storeByKey(entity, options.key, value, schema, options.convertCustomTypes);
|
|
177
|
+
return entity;
|
|
178
|
+
}
|
|
163
179
|
if (meta.simplePK) {
|
|
164
180
|
const exists = this.unitOfWork.getById(entityName, id, schema);
|
|
165
181
|
if (exists) {
|
|
@@ -182,7 +198,6 @@ export class EntityFactory {
|
|
|
182
198
|
return this.create(entityName, id, { ...options, initialized: false });
|
|
183
199
|
}
|
|
184
200
|
createEmbeddable(entityName, data, options = {}) {
|
|
185
|
-
entityName = Utils.className(entityName);
|
|
186
201
|
data = { ...data };
|
|
187
202
|
const meta = this.metadata.get(entityName);
|
|
188
203
|
const meta2 = this.processDiscriminatorColumn(meta, data);
|
|
@@ -194,7 +209,7 @@ export class EntityFactory {
|
|
|
194
209
|
createEntity(data, meta, options) {
|
|
195
210
|
const schema = this.driver.getSchemaName(meta, options);
|
|
196
211
|
if (options.newEntity || meta.forceConstructor || meta.virtual) {
|
|
197
|
-
if (
|
|
212
|
+
if (meta.polymorphs) {
|
|
198
213
|
throw new Error(`Cannot create entity ${meta.className}, class prototype is unknown`);
|
|
199
214
|
}
|
|
200
215
|
const params = this.extractConstructorParams(meta, data, options);
|
|
@@ -240,10 +255,10 @@ export class EntityFactory {
|
|
|
240
255
|
}
|
|
241
256
|
hydrate(entity, meta, data, options) {
|
|
242
257
|
if (options.initialized) {
|
|
243
|
-
this.hydrator.hydrate(entity, meta, data, this, 'full', options.newEntity, options.convertCustomTypes, options.schema, this.driver.getSchemaName(meta, options));
|
|
258
|
+
this.hydrator.hydrate(entity, meta, data, this, 'full', options.newEntity, options.convertCustomTypes, options.schema, this.driver.getSchemaName(meta, options), options.normalizeAccessors);
|
|
244
259
|
}
|
|
245
260
|
else {
|
|
246
|
-
this.hydrator.hydrateReference(entity, meta, data, this, options.convertCustomTypes, options.schema, this.driver.getSchemaName(meta, options));
|
|
261
|
+
this.hydrator.hydrateReference(entity, meta, data, this, options.convertCustomTypes, options.schema, this.driver.getSchemaName(meta, options), options.normalizeAccessors);
|
|
247
262
|
}
|
|
248
263
|
Utils.keys(data).forEach(key => {
|
|
249
264
|
helper(entity)?.__loadedProperties.add(key);
|
|
@@ -257,75 +272,89 @@ export class EntityFactory {
|
|
|
257
272
|
findEntity(data, meta, options) {
|
|
258
273
|
const schema = this.driver.getSchemaName(meta, options);
|
|
259
274
|
if (meta.simplePK) {
|
|
260
|
-
return this.unitOfWork.getById(meta.
|
|
275
|
+
return this.unitOfWork.getById(meta.class, data[meta.primaryKeys[0]], schema);
|
|
261
276
|
}
|
|
262
277
|
if (!Array.isArray(data) && meta.primaryKeys.some(pk => data[pk] == null)) {
|
|
263
278
|
return undefined;
|
|
264
279
|
}
|
|
265
280
|
const pks = Utils.getOrderedPrimaryKeys(data, meta, this.platform, options.convertCustomTypes);
|
|
266
|
-
return this.unitOfWork.getById(meta.
|
|
281
|
+
return this.unitOfWork.getById(meta.class, pks, schema);
|
|
267
282
|
}
|
|
268
283
|
processDiscriminatorColumn(meta, data) {
|
|
269
|
-
|
|
284
|
+
// Handle STI discriminator (persisted column)
|
|
285
|
+
if (meta.root.inheritanceType === 'sti') {
|
|
286
|
+
const prop = meta.properties[meta.root.discriminatorColumn];
|
|
287
|
+
const value = data[prop.name];
|
|
288
|
+
const type = meta.root.discriminatorMap[value];
|
|
289
|
+
meta = type ? this.metadata.get(type) : meta;
|
|
270
290
|
return meta;
|
|
271
291
|
}
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
292
|
+
// Handle TPT discriminator (computed at query time)
|
|
293
|
+
if (meta.root.inheritanceType === 'tpt' && meta.root.discriminatorMap) {
|
|
294
|
+
const value = data[meta.root.tptDiscriminatorColumn];
|
|
295
|
+
if (value) {
|
|
296
|
+
const type = meta.root.discriminatorMap[value];
|
|
297
|
+
meta = type ? this.metadata.get(type) : meta;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
276
300
|
return meta;
|
|
277
301
|
}
|
|
278
302
|
/**
|
|
279
303
|
* denormalize PK to value required by driver (e.g. ObjectId)
|
|
280
304
|
*/
|
|
281
|
-
denormalizePrimaryKey(
|
|
282
|
-
const pk =
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
data[
|
|
305
|
+
denormalizePrimaryKey(meta, data) {
|
|
306
|
+
const pk = meta.getPrimaryProp();
|
|
307
|
+
const spk = meta.properties[meta.serializedPrimaryKey];
|
|
308
|
+
if (!spk?.serializedPrimaryKey) {
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
if (pk.type === 'ObjectId' && (data[pk.name] != null || data[spk.name] != null)) {
|
|
312
|
+
data[pk.name] = this.platform.denormalizePrimaryKey((data[spk.name] || data[pk.name]));
|
|
313
|
+
delete data[spk.name];
|
|
290
314
|
}
|
|
291
315
|
}
|
|
292
316
|
/**
|
|
293
317
|
* returns parameters for entity constructor, creating references from plain ids
|
|
294
318
|
*/
|
|
295
319
|
extractConstructorParams(meta, data, options) {
|
|
320
|
+
if (!meta.constructorParams) {
|
|
321
|
+
return [data];
|
|
322
|
+
}
|
|
296
323
|
return meta.constructorParams.map(k => {
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
324
|
+
const prop = meta.properties[k];
|
|
325
|
+
const value = data[k];
|
|
326
|
+
if (prop && [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && value) {
|
|
327
|
+
const pk = Reference.unwrapReference(value);
|
|
328
|
+
const entity = this.unitOfWork.getById(prop.targetMeta.class, pk, options.schema, true);
|
|
300
329
|
if (entity) {
|
|
301
330
|
return entity;
|
|
302
331
|
}
|
|
303
|
-
if (Utils.isEntity(
|
|
304
|
-
return
|
|
332
|
+
if (Utils.isEntity(value)) {
|
|
333
|
+
return value;
|
|
305
334
|
}
|
|
306
|
-
const nakedPk = Utils.extractPK(
|
|
307
|
-
if (Utils.isObject(
|
|
308
|
-
return this.create(
|
|
335
|
+
const nakedPk = Utils.extractPK(value, prop.targetMeta, true);
|
|
336
|
+
if (Utils.isObject(value) && !nakedPk) {
|
|
337
|
+
return this.create(prop.targetMeta.class, value, options);
|
|
309
338
|
}
|
|
310
339
|
const { newEntity, initialized, ...rest } = options;
|
|
311
|
-
const target = this.createReference(
|
|
312
|
-
return Reference.wrapReference(target,
|
|
340
|
+
const target = this.createReference(prop.targetMeta.class, nakedPk, rest);
|
|
341
|
+
return Reference.wrapReference(target, prop);
|
|
313
342
|
}
|
|
314
|
-
if (
|
|
315
|
-
/* v8 ignore next
|
|
316
|
-
if (Utils.isEntity(
|
|
317
|
-
return
|
|
343
|
+
if (prop?.kind === ReferenceKind.EMBEDDED && value) {
|
|
344
|
+
/* v8 ignore next */
|
|
345
|
+
if (Utils.isEntity(value)) {
|
|
346
|
+
return value;
|
|
318
347
|
}
|
|
319
|
-
return this.createEmbeddable(
|
|
348
|
+
return this.createEmbeddable(prop.targetMeta.class, value, options);
|
|
320
349
|
}
|
|
321
|
-
if (!
|
|
350
|
+
if (!prop) {
|
|
322
351
|
const tmp = { ...data };
|
|
323
352
|
for (const prop of meta.props) {
|
|
324
353
|
if (!options.convertCustomTypes || !prop.customType || tmp[prop.name] == null) {
|
|
325
354
|
continue;
|
|
326
355
|
}
|
|
327
|
-
if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && Utils.isPlainObject(tmp[prop.name]) && !Utils.extractPK(tmp[prop.name],
|
|
328
|
-
tmp[prop.name] = Reference.wrapReference(this.create(
|
|
356
|
+
if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && Utils.isPlainObject(tmp[prop.name]) && !Utils.extractPK(tmp[prop.name], prop.targetMeta, true)) {
|
|
357
|
+
tmp[prop.name] = Reference.wrapReference(this.create(prop.targetMeta.class, tmp[prop.name], options), prop);
|
|
329
358
|
}
|
|
330
359
|
else if (prop.kind === ReferenceKind.SCALAR) {
|
|
331
360
|
tmp[prop.name] = prop.customType.convertToJSValue(tmp[prop.name], this.platform);
|
|
@@ -333,10 +362,10 @@ export class EntityFactory {
|
|
|
333
362
|
}
|
|
334
363
|
return tmp;
|
|
335
364
|
}
|
|
336
|
-
if (options.convertCustomTypes &&
|
|
337
|
-
return
|
|
365
|
+
if (options.convertCustomTypes && prop.customType && value != null) {
|
|
366
|
+
return prop.customType.convertToJSValue(value, this.platform);
|
|
338
367
|
}
|
|
339
|
-
return
|
|
368
|
+
return value;
|
|
340
369
|
});
|
|
341
370
|
}
|
|
342
371
|
get unitOfWork() {
|
package/entity/EntityHelper.d.ts
CHANGED
|
@@ -6,9 +6,9 @@ import { type EntityMetadata, type EntityProperty, type IHydrator } from '../typ
|
|
|
6
6
|
export declare class EntityHelper {
|
|
7
7
|
static decorate<T extends object>(meta: EntityMetadata<T>, em: EntityManager): void;
|
|
8
8
|
/**
|
|
9
|
-
* As a performance optimization, we create entity state methods
|
|
9
|
+
* As a performance optimization, we create entity state methods lazily. We first add
|
|
10
10
|
* the `null` value to the prototype to reserve space in memory. Then we define a setter on the
|
|
11
|
-
* prototype
|
|
11
|
+
* prototype that will be executed exactly once per entity instance. There we redefine the given
|
|
12
12
|
* property on the entity instance, so shadowing the prototype setter.
|
|
13
13
|
*/
|
|
14
14
|
private static defineBaseProperties;
|
package/entity/EntityHelper.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { inspect } from 'node:util';
|
|
2
1
|
import { EagerProps, EntityRepositoryType, HiddenProps, OptionalProps, PrimaryKeyProp, } from '../typings.js';
|
|
3
2
|
import { EntityTransformer } from '../serialization/EntityTransformer.js';
|
|
4
3
|
import { Reference } from './Reference.js';
|
|
@@ -6,6 +5,8 @@ import { Utils } from '../utils/Utils.js';
|
|
|
6
5
|
import { WrappedEntity } from './WrappedEntity.js';
|
|
7
6
|
import { ReferenceKind } from '../enums.js';
|
|
8
7
|
import { helper } from './wrap.js';
|
|
8
|
+
import { inspect } from '../logging/inspect.js';
|
|
9
|
+
import { getEnv } from '../utils/env-vars.js';
|
|
9
10
|
/**
|
|
10
11
|
* @internal
|
|
11
12
|
*/
|
|
@@ -32,14 +33,19 @@ export class EntityHelper {
|
|
|
32
33
|
const prototype = meta.prototype;
|
|
33
34
|
if (!prototype.toJSON) { // toJSON can be overridden
|
|
34
35
|
prototype.toJSON = function (...args) {
|
|
35
|
-
|
|
36
|
+
// Guard against being called on the prototype itself (e.g. by serializers
|
|
37
|
+
// walking the object graph and calling toJSON on prototype objects)
|
|
38
|
+
if (this === prototype) {
|
|
39
|
+
return {};
|
|
40
|
+
}
|
|
41
|
+
return EntityTransformer.toObject(this, ...args);
|
|
36
42
|
};
|
|
37
43
|
}
|
|
38
44
|
}
|
|
39
45
|
/**
|
|
40
|
-
* As a performance optimization, we create entity state methods
|
|
46
|
+
* As a performance optimization, we create entity state methods lazily. We first add
|
|
41
47
|
* the `null` value to the prototype to reserve space in memory. Then we define a setter on the
|
|
42
|
-
* prototype
|
|
48
|
+
* prototype that will be executed exactly once per entity instance. There we redefine the given
|
|
43
49
|
* property on the entity instance, so shadowing the prototype setter.
|
|
44
50
|
*/
|
|
45
51
|
static defineBaseProperties(meta, prototype, em) {
|
|
@@ -87,7 +93,7 @@ export class EntityHelper {
|
|
|
87
93
|
});
|
|
88
94
|
return;
|
|
89
95
|
}
|
|
90
|
-
if (prop.inherited || prop.primary || prop.
|
|
96
|
+
if (prop.inherited || prop.primary || prop.accessor || prop.persist === false || prop.embedded || isCollection) {
|
|
91
97
|
return;
|
|
92
98
|
}
|
|
93
99
|
Object.defineProperty(meta.prototype, prop.name, {
|
|
@@ -98,13 +104,11 @@ export class EntityHelper {
|
|
|
98
104
|
},
|
|
99
105
|
set(val) {
|
|
100
106
|
this.__helper.__data[prop.name] = val;
|
|
101
|
-
this.__helper.__touched = !this.__helper.hydrator.isRunning();
|
|
102
107
|
},
|
|
103
108
|
enumerable: true,
|
|
104
109
|
configurable: true,
|
|
105
110
|
});
|
|
106
111
|
this.__helper.__data[prop.name] = val;
|
|
107
|
-
this.__helper.__touched = !this.__helper.hydrator.isRunning();
|
|
108
112
|
},
|
|
109
113
|
configurable: true,
|
|
110
114
|
});
|
|
@@ -112,16 +116,27 @@ export class EntityHelper {
|
|
|
112
116
|
}
|
|
113
117
|
static defineCustomInspect(meta) {
|
|
114
118
|
// @ts-ignore
|
|
115
|
-
meta.prototype[inspect.custom] ??= function (depth = 2) {
|
|
116
|
-
const object = {
|
|
119
|
+
meta.prototype[Symbol.for('nodejs.util.inspect.custom')] ??= function (depth = 2) {
|
|
120
|
+
const object = {};
|
|
121
|
+
const keys = new Set(Utils.keys(this));
|
|
122
|
+
for (const prop of meta.props) {
|
|
123
|
+
if (keys.has(prop.name) || (prop.getter && prop.accessor === prop.name)) {
|
|
124
|
+
object[prop.name] = this[prop.name];
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
for (const key of keys) {
|
|
128
|
+
if (!meta.properties[key]) {
|
|
129
|
+
object[key] = this[key];
|
|
130
|
+
}
|
|
131
|
+
}
|
|
117
132
|
// ensure we dont have internal symbols in the POJO
|
|
118
133
|
[OptionalProps, EntityRepositoryType, PrimaryKeyProp, EagerProps, HiddenProps].forEach(sym => delete object[sym]);
|
|
119
134
|
meta.props
|
|
120
135
|
.filter(prop => object[prop.name] === undefined)
|
|
121
136
|
.forEach(prop => delete object[prop.name]);
|
|
122
137
|
const ret = inspect(object, { depth });
|
|
123
|
-
let name =
|
|
124
|
-
const showEM = ['true', 't', '1'].includes(
|
|
138
|
+
let name = this.constructor.name;
|
|
139
|
+
const showEM = ['true', 't', '1'].includes(getEnv('MIKRO_ORM_LOG_EM_ID')?.toLowerCase() ?? '');
|
|
125
140
|
if (showEM) {
|
|
126
141
|
if (helper(this).__em) {
|
|
127
142
|
name += ` [managed by ${helper(this).__em.id}]`;
|
|
@@ -154,9 +169,6 @@ export class EntityHelper {
|
|
|
154
169
|
if (val && hydrator.isRunning() && wrapped.__originalEntityData && prop.owner) {
|
|
155
170
|
wrapped.__originalEntityData[prop.name] = Utils.getPrimaryKeyValues(wrapped.__data[prop.name], prop.targetMeta, true);
|
|
156
171
|
}
|
|
157
|
-
else {
|
|
158
|
-
wrapped.__touched = !hydrator.isRunning();
|
|
159
|
-
}
|
|
160
172
|
EntityHelper.propagate(meta, entity, this, prop, Reference.unwrapReference(val), old);
|
|
161
173
|
},
|
|
162
174
|
enumerable: true,
|
|
@@ -164,7 +176,19 @@ export class EntityHelper {
|
|
|
164
176
|
});
|
|
165
177
|
}
|
|
166
178
|
static propagate(meta, entity, owner, prop, value, old) {
|
|
167
|
-
|
|
179
|
+
// For polymorphic relations, get bidirectional relations from the actual entity's metadata
|
|
180
|
+
let bidirectionalRelations;
|
|
181
|
+
if (prop.polymorphic && prop.polymorphTargets?.length) {
|
|
182
|
+
// For polymorphic relations, we need to get the bidirectional relations from the actual value's metadata
|
|
183
|
+
if (!value) {
|
|
184
|
+
return; // No value means no propagation needed
|
|
185
|
+
}
|
|
186
|
+
bidirectionalRelations = helper(value).__meta.bidirectionalRelations;
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
bidirectionalRelations = prop.targetMeta.bidirectionalRelations;
|
|
190
|
+
}
|
|
191
|
+
for (const prop2 of bidirectionalRelations) {
|
|
168
192
|
if ((prop2.inversedBy || prop2.mappedBy) !== prop.name) {
|
|
169
193
|
continue;
|
|
170
194
|
}
|
|
@@ -172,6 +196,10 @@ export class EntityHelper {
|
|
|
172
196
|
continue;
|
|
173
197
|
}
|
|
174
198
|
const inverse = value?.[prop2.name];
|
|
199
|
+
if (prop.ref && owner[prop.name]) {
|
|
200
|
+
// eslint-disable-next-line dot-notation
|
|
201
|
+
owner[prop.name]['property'] = prop;
|
|
202
|
+
}
|
|
175
203
|
if (Utils.isCollection(inverse) && inverse.isPartial()) {
|
|
176
204
|
continue;
|
|
177
205
|
}
|
|
@@ -202,6 +230,11 @@ export class EntityHelper {
|
|
|
202
230
|
helper(other).__em?.getUnitOfWork().scheduleOrphanRemoval(other);
|
|
203
231
|
}
|
|
204
232
|
}
|
|
233
|
+
// Skip setting the inverse side to null if it's a primary key - the entity will be removed via orphan removal
|
|
234
|
+
// Setting a primary key to null would corrupt the entity and cause validation errors
|
|
235
|
+
if (value == null && prop.orphanRemoval && prop2.primary) {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
205
238
|
if (value == null) {
|
|
206
239
|
entity[prop2.name] = value;
|
|
207
240
|
}
|
package/entity/EntityLoader.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { AnyEntity, ConnectionType,
|
|
1
|
+
import type { AnyEntity, ConnectionType, EntityName, EntityProperty, FilterQuery, PopulateOptions } from '../typings.js';
|
|
2
2
|
import type { EntityManager } from '../EntityManager.js';
|
|
3
3
|
import { LoadStrategy, type LockMode, type PopulateHint, PopulatePath, type QueryOrderMap } from '../enums.js';
|
|
4
|
-
import type { EntityField } from '../drivers/IDatabaseDriver.js';
|
|
4
|
+
import type { EntityField, FilterOptions } from '../drivers/IDatabaseDriver.js';
|
|
5
5
|
import type { LoggingOptions } from '../logging/Logger.js';
|
|
6
6
|
export type EntityLoaderOptions<Entity, Fields extends string = PopulatePath.ALL, Excludes extends string = never> = {
|
|
7
7
|
where?: FilterQuery<Entity>;
|
|
@@ -14,8 +14,8 @@ export type EntityLoaderOptions<Entity, Fields extends string = PopulatePath.ALL
|
|
|
14
14
|
lookup?: boolean;
|
|
15
15
|
convertCustomTypes?: boolean;
|
|
16
16
|
ignoreLazyScalarProperties?: boolean;
|
|
17
|
-
filters?:
|
|
18
|
-
strategy?: LoadStrategy
|
|
17
|
+
filters?: FilterOptions;
|
|
18
|
+
strategy?: LoadStrategy | `${LoadStrategy}`;
|
|
19
19
|
lockMode?: Exclude<LockMode, LockMode.OPTIMISTIC>;
|
|
20
20
|
schema?: string;
|
|
21
21
|
connectionType?: ConnectionType;
|
|
@@ -30,8 +30,8 @@ export declare class EntityLoader {
|
|
|
30
30
|
* Loads specified relations in batch.
|
|
31
31
|
* This will execute one query for each relation, that will populate it on all the specified entities.
|
|
32
32
|
*/
|
|
33
|
-
populate<Entity extends object, Fields extends string = PopulatePath.ALL>(entityName:
|
|
34
|
-
normalizePopulate<Entity>(entityName:
|
|
33
|
+
populate<Entity extends object, Fields extends string = PopulatePath.ALL>(entityName: EntityName<Entity>, entities: Entity[], populate: PopulateOptions<Entity>[] | boolean, options: EntityLoaderOptions<Entity, Fields>): Promise<void>;
|
|
34
|
+
normalizePopulate<Entity>(entityName: EntityName<Entity>, populate: (PopulateOptions<Entity> | boolean)[] | PopulateOptions<Entity> | boolean, strategy?: LoadStrategy, lookup?: boolean, exclude?: string[]): PopulateOptions<Entity>[];
|
|
35
35
|
private setSerializationContext;
|
|
36
36
|
/**
|
|
37
37
|
* Merge multiple populates for the same entity with different children. Also skips `*` fields, those can come from
|
|
@@ -43,6 +43,7 @@ export declare class EntityLoader {
|
|
|
43
43
|
*/
|
|
44
44
|
private populateMany;
|
|
45
45
|
private populateScalar;
|
|
46
|
+
private populatePolymorphic;
|
|
46
47
|
private initializeCollections;
|
|
47
48
|
private initializeOneToMany;
|
|
48
49
|
private initializeManyToMany;
|