@mikro-orm/core 7.0.0-dev.2 → 7.0.0-dev.200
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 +111 -61
- package/EntityManager.js +346 -300
- package/MikroORM.d.ts +44 -35
- package/MikroORM.js +103 -143
- package/README.md +3 -2
- package/cache/FileCacheAdapter.d.ts +1 -1
- package/cache/FileCacheAdapter.js +8 -7
- 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 +16 -7
- package/connections/Connection.js +23 -14
- package/drivers/DatabaseDriver.d.ts +25 -16
- package/drivers/DatabaseDriver.js +80 -35
- package/drivers/IDatabaseDriver.d.ts +47 -17
- package/entity/BaseEntity.d.ts +2 -2
- package/entity/BaseEntity.js +0 -3
- package/entity/Collection.d.ts +95 -31
- package/entity/Collection.js +444 -102
- package/entity/EntityAssigner.d.ts +1 -1
- package/entity/EntityAssigner.js +26 -18
- package/entity/EntityFactory.d.ts +13 -1
- package/entity/EntityFactory.js +88 -54
- package/entity/EntityHelper.d.ts +2 -2
- package/entity/EntityHelper.js +38 -15
- package/entity/EntityLoader.d.ts +8 -7
- package/entity/EntityLoader.js +134 -80
- package/entity/EntityRepository.d.ts +24 -4
- package/entity/EntityRepository.js +8 -2
- package/entity/Reference.d.ts +9 -12
- package/entity/Reference.js +34 -9
- package/entity/WrappedEntity.d.ts +2 -7
- package/entity/WrappedEntity.js +3 -8
- package/entity/defineEntity.d.ts +585 -0
- package/entity/defineEntity.js +533 -0
- package/entity/index.d.ts +3 -2
- package/entity/index.js +3 -2
- package/entity/utils.d.ts +7 -0
- package/entity/utils.js +16 -4
- package/entity/validators.d.ts +11 -0
- package/entity/validators.js +65 -0
- package/enums.d.ts +22 -6
- package/enums.js +15 -1
- package/errors.d.ts +23 -9
- package/errors.js +59 -21
- package/events/EventManager.d.ts +2 -1
- package/events/EventManager.js +19 -11
- package/events/EventSubscriber.d.ts +3 -1
- package/hydration/Hydrator.js +1 -2
- package/hydration/ObjectHydrator.d.ts +4 -4
- package/hydration/ObjectHydrator.js +53 -33
- 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 +26 -26
- package/metadata/EntitySchema.js +82 -51
- package/metadata/MetadataDiscovery.d.ts +7 -10
- package/metadata/MetadataDiscovery.js +408 -335
- 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 +17 -9
- package/metadata/MetadataValidator.js +100 -42
- 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 +502 -0
- package/metadata/types.js +1 -0
- package/naming-strategy/AbstractNamingStrategy.d.ts +12 -4
- package/naming-strategy/AbstractNamingStrategy.js +14 -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 +24 -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 -13
- 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 +16 -13
- package/types/ArrayType.d.ts +1 -1
- package/types/ArrayType.js +2 -3
- package/types/BigIntType.d.ts +9 -6
- package/types/BigIntType.js +4 -1
- package/types/BlobType.d.ts +0 -1
- package/types/BlobType.js +0 -3
- package/types/BooleanType.d.ts +2 -1
- package/types/BooleanType.js +3 -0
- package/types/DecimalType.d.ts +6 -4
- package/types/DecimalType.js +3 -3
- package/types/DoubleType.js +2 -2
- package/types/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 +300 -140
- package/typings.js +62 -44
- package/unit-of-work/ChangeSet.d.ts +2 -6
- package/unit-of-work/ChangeSet.js +4 -5
- package/unit-of-work/ChangeSetComputer.d.ts +1 -3
- package/unit-of-work/ChangeSetComputer.js +26 -13
- package/unit-of-work/ChangeSetPersister.d.ts +5 -4
- package/unit-of-work/ChangeSetPersister.js +77 -35
- 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 +23 -3
- package/unit-of-work/UnitOfWork.js +199 -106
- package/utils/AbstractSchemaGenerator.d.ts +5 -5
- package/utils/AbstractSchemaGenerator.js +22 -17
- package/utils/AsyncContext.d.ts +6 -0
- package/utils/AsyncContext.js +42 -0
- package/utils/Configuration.d.ts +779 -207
- package/utils/Configuration.js +146 -190
- package/utils/ConfigurationLoader.d.ts +1 -54
- package/utils/ConfigurationLoader.js +1 -352
- package/utils/Cursor.d.ts +3 -6
- package/utils/Cursor.js +27 -11
- package/utils/DataloaderUtils.d.ts +15 -5
- package/utils/DataloaderUtils.js +65 -17
- package/utils/EntityComparator.d.ts +13 -9
- package/utils/EntityComparator.js +164 -89
- package/utils/QueryHelper.d.ts +14 -6
- package/utils/QueryHelper.js +88 -26
- package/utils/RawQueryFragment.d.ts +48 -25
- package/utils/RawQueryFragment.js +67 -66
- package/utils/RequestContext.js +2 -2
- package/utils/TransactionContext.js +2 -2
- package/utils/TransactionManager.d.ts +65 -0
- package/utils/TransactionManager.js +223 -0
- package/utils/Utils.d.ts +13 -120
- package/utils/Utils.js +104 -375
- 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 +32 -0
- package/utils/fs-utils.js +178 -0
- package/utils/index.d.ts +2 -1
- package/utils/index.js +2 -1
- package/utils/upsert-utils.d.ts +9 -4
- package/utils/upsert-utils.js +55 -4
- package/decorators/Check.d.ts +0 -3
- package/decorators/Check.js +0 -13
- package/decorators/CreateRequestContext.d.ts +0 -3
- package/decorators/CreateRequestContext.js +0 -29
- package/decorators/Embeddable.d.ts +0 -8
- package/decorators/Embeddable.js +0 -11
- package/decorators/Embedded.d.ts +0 -18
- package/decorators/Embedded.js +0 -18
- package/decorators/Entity.d.ts +0 -18
- package/decorators/Entity.js +0 -13
- 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 -5
- package/decorators/Formula.js +0 -15
- package/decorators/Indexed.d.ts +0 -17
- package/decorators/Indexed.js +0 -20
- package/decorators/ManyToMany.d.ts +0 -40
- package/decorators/ManyToMany.js +0 -14
- package/decorators/ManyToOne.d.ts +0 -30
- package/decorators/ManyToOne.js +0 -14
- package/decorators/OneToMany.d.ts +0 -28
- package/decorators/OneToMany.js +0 -17
- package/decorators/OneToOne.d.ts +0 -24
- package/decorators/OneToOne.js +0 -7
- package/decorators/PrimaryKey.d.ts +0 -9
- package/decorators/PrimaryKey.js +0 -20
- package/decorators/Property.d.ts +0 -250
- package/decorators/Property.js +0 -32
- package/decorators/Transactional.d.ts +0 -13
- package/decorators/Transactional.js +0 -28
- package/decorators/hooks.d.ts +0 -16
- package/decorators/hooks.js +0 -47
- package/decorators/index.d.ts +0 -17
- package/decorators/index.js +0 -17
- package/entity/ArrayCollection.d.ts +0 -116
- package/entity/ArrayCollection.js +0 -395
- 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;
|
|
@@ -4,12 +4,23 @@ import type { EntityComparator } from '../utils/EntityComparator.js';
|
|
|
4
4
|
export interface FactoryOptions {
|
|
5
5
|
initialized?: boolean;
|
|
6
6
|
newEntity?: boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Property `onCreate` hooks are normally executed during `flush` operation.
|
|
9
|
+
* With this option, they will be processed early inside `em.create()` method.
|
|
10
|
+
*/
|
|
11
|
+
processOnCreateHooksEarly?: boolean;
|
|
7
12
|
merge?: boolean;
|
|
8
13
|
refresh?: boolean;
|
|
9
14
|
convertCustomTypes?: boolean;
|
|
10
15
|
recomputeSnapshot?: boolean;
|
|
11
16
|
schema?: string;
|
|
12
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;
|
|
13
24
|
}
|
|
14
25
|
export declare class EntityFactory {
|
|
15
26
|
private readonly em;
|
|
@@ -23,10 +34,11 @@ export declare class EntityFactory {
|
|
|
23
34
|
constructor(em: EntityManager);
|
|
24
35
|
create<T extends object, P extends string = string>(entityName: EntityName<T>, data: EntityData<T>, options?: FactoryOptions): New<T, P>;
|
|
25
36
|
mergeData<T extends object>(meta: EntityMetadata<T>, entity: T, data: EntityData<T>, options?: FactoryOptions): void;
|
|
26
|
-
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;
|
|
27
38
|
createEmbeddable<T extends object>(entityName: EntityName<T>, data: EntityData<T>, options?: Pick<FactoryOptions, 'newEntity' | 'convertCustomTypes'>): T;
|
|
28
39
|
getComparator(): EntityComparator;
|
|
29
40
|
private createEntity;
|
|
41
|
+
private assignDefaultValues;
|
|
30
42
|
private hydrate;
|
|
31
43
|
private findEntity;
|
|
32
44
|
private processDiscriminatorColumn;
|
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,14 +37,15 @@ 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);
|
|
45
45
|
let wrapped = exists && helper(exists);
|
|
46
46
|
if (wrapped && !options.refresh) {
|
|
47
47
|
wrapped.__processing = true;
|
|
48
|
+
Utils.dropUndefinedProperties(data);
|
|
48
49
|
this.mergeData(meta2, exists, data, options);
|
|
49
50
|
wrapped.__processing = false;
|
|
50
51
|
if (wrapped.isInitialized()) {
|
|
@@ -58,7 +59,7 @@ export class EntityFactory {
|
|
|
58
59
|
wrapped.__initialized = options.initialized;
|
|
59
60
|
if (options.newEntity || meta.forceConstructor || meta.virtual) {
|
|
60
61
|
const tmp = { ...data };
|
|
61
|
-
meta.constructorParams
|
|
62
|
+
meta.constructorParams?.forEach(prop => delete tmp[prop]);
|
|
62
63
|
this.hydrate(entity, meta2, tmp, options);
|
|
63
64
|
// since we now process only a copy of the `data` via hydrator, but later we register the state with the full snapshot,
|
|
64
65
|
// we need to go through all props with custom types that have `ensureComparable: true` and ensure they are comparable
|
|
@@ -70,9 +71,11 @@ export class EntityFactory {
|
|
|
70
71
|
continue;
|
|
71
72
|
}
|
|
72
73
|
if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && Utils.isPlainObject(data[prop.name])) {
|
|
73
|
-
data[prop.name] = Utils.getPrimaryKeyValues(data[prop.name], prop.targetMeta
|
|
74
|
+
data[prop.name] = Utils.getPrimaryKeyValues(data[prop.name], prop.targetMeta, true);
|
|
75
|
+
}
|
|
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' });
|
|
74
78
|
}
|
|
75
|
-
data[prop.name] = prop.customType.convertToDatabaseValue(data[prop.name], this.platform, { key: prop.name, mode: 'hydration' });
|
|
76
79
|
}
|
|
77
80
|
}
|
|
78
81
|
}
|
|
@@ -80,13 +83,14 @@ export class EntityFactory {
|
|
|
80
83
|
else {
|
|
81
84
|
this.hydrate(entity, meta2, data, options);
|
|
82
85
|
}
|
|
83
|
-
wrapped.__touched = false;
|
|
84
86
|
if (exists && meta.discriminatorColumn && !(entity instanceof meta2.class)) {
|
|
85
87
|
Object.setPrototypeOf(entity, meta2.prototype);
|
|
86
88
|
}
|
|
87
89
|
if (options.merge && wrapped.hasPrimaryKey()) {
|
|
88
90
|
this.unitOfWork.register(entity, data, {
|
|
89
|
-
refresh
|
|
91
|
+
// Always refresh to ensure the payload is in correct shape for joined strategy. When loading nested relations,
|
|
92
|
+
// they will be created early without `Type.ensureComparable` being properly handled, resulting in extra updates.
|
|
93
|
+
refresh: options.initialized,
|
|
90
94
|
newEntity: options.newEntity,
|
|
91
95
|
loaded: options.initialized,
|
|
92
96
|
});
|
|
@@ -105,12 +109,12 @@ export class EntityFactory {
|
|
|
105
109
|
data = QueryHelper.processParams(data);
|
|
106
110
|
const existsData = this.comparator.prepareEntity(entity);
|
|
107
111
|
const originalEntityData = helper(entity).__originalEntityData ?? {};
|
|
108
|
-
const diff = this.comparator.diffEntities(meta.
|
|
112
|
+
const diff = this.comparator.diffEntities(meta.class, originalEntityData, existsData);
|
|
109
113
|
// version properties are not part of entity snapshots
|
|
110
114
|
if (meta.versionProperty && data[meta.versionProperty] && data[meta.versionProperty] !== originalEntityData[meta.versionProperty]) {
|
|
111
115
|
diff[meta.versionProperty] = data[meta.versionProperty];
|
|
112
116
|
}
|
|
113
|
-
const diff2 = this.comparator.diffEntities(meta.
|
|
117
|
+
const diff2 = this.comparator.diffEntities(meta.class, existsData, data, { includeInverseSides: true });
|
|
114
118
|
// do not override values changed by user
|
|
115
119
|
Utils.keys(diff).forEach(key => delete diff2[key]);
|
|
116
120
|
Utils.keys(diff2).filter(key => {
|
|
@@ -133,6 +137,10 @@ export class EntityFactory {
|
|
|
133
137
|
if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && Utils.isPlainObject(data[prop.name])) {
|
|
134
138
|
diff2[key] = entity[prop.name] ? helper(entity[prop.name]).getPrimaryKey(options.convertCustomTypes) : null;
|
|
135
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
|
+
}
|
|
136
144
|
originalEntityData[key] = diff2[key] === null ? nullVal : diff2[key];
|
|
137
145
|
helper(entity).__loadedProperties.add(key);
|
|
138
146
|
});
|
|
@@ -143,20 +151,31 @@ export class EntityFactory {
|
|
|
143
151
|
// we just create the entity from scratch, which will automatically pick the right one from the identity map and call `mergeData` on it
|
|
144
152
|
data[prop.name]
|
|
145
153
|
.filter(child => Utils.isPlainObject(child)) // objects with prototype can be PKs (e.g. `ObjectId`)
|
|
146
|
-
.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
|
|
147
155
|
return;
|
|
148
156
|
}
|
|
149
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) {
|
|
150
|
-
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
|
|
151
159
|
}
|
|
152
160
|
});
|
|
153
|
-
|
|
161
|
+
this.unitOfWork.normalizeEntityData(meta, originalEntityData);
|
|
154
162
|
}
|
|
155
163
|
createReference(entityName, id, options = {}) {
|
|
156
164
|
options.convertCustomTypes ??= true;
|
|
157
|
-
entityName = Utils.className(entityName);
|
|
158
165
|
const meta = this.metadata.get(entityName);
|
|
159
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
|
+
}
|
|
160
179
|
if (meta.simplePK) {
|
|
161
180
|
const exists = this.unitOfWork.getById(entityName, id, schema);
|
|
162
181
|
if (exists) {
|
|
@@ -168,8 +187,8 @@ export class EntityFactory {
|
|
|
168
187
|
if (Array.isArray(id)) {
|
|
169
188
|
id = Utils.getPrimaryKeyCondFromArray(id, meta);
|
|
170
189
|
}
|
|
171
|
-
const pks = Utils.getOrderedPrimaryKeys(id, meta, this.platform
|
|
172
|
-
const exists = this.unitOfWork.getById(entityName, pks, schema);
|
|
190
|
+
const pks = Utils.getOrderedPrimaryKeys(id, meta, this.platform);
|
|
191
|
+
const exists = this.unitOfWork.getById(entityName, pks, schema, options.convertCustomTypes);
|
|
173
192
|
if (exists) {
|
|
174
193
|
return exists;
|
|
175
194
|
}
|
|
@@ -179,7 +198,6 @@ export class EntityFactory {
|
|
|
179
198
|
return this.create(entityName, id, { ...options, initialized: false });
|
|
180
199
|
}
|
|
181
200
|
createEmbeddable(entityName, data, options = {}) {
|
|
182
|
-
entityName = Utils.className(entityName);
|
|
183
201
|
data = { ...data };
|
|
184
202
|
const meta = this.metadata.get(entityName);
|
|
185
203
|
const meta2 = this.processDiscriminatorColumn(meta, data);
|
|
@@ -191,7 +209,7 @@ export class EntityFactory {
|
|
|
191
209
|
createEntity(data, meta, options) {
|
|
192
210
|
const schema = this.driver.getSchemaName(meta, options);
|
|
193
211
|
if (options.newEntity || meta.forceConstructor || meta.virtual) {
|
|
194
|
-
if (
|
|
212
|
+
if (meta.polymorphs) {
|
|
195
213
|
throw new Error(`Cannot create entity ${meta.className}, class prototype is unknown`);
|
|
196
214
|
}
|
|
197
215
|
const params = this.extractConstructorParams(meta, data, options);
|
|
@@ -228,28 +246,39 @@ export class EntityFactory {
|
|
|
228
246
|
}
|
|
229
247
|
return entity;
|
|
230
248
|
}
|
|
249
|
+
assignDefaultValues(entity, meta) {
|
|
250
|
+
for (const prop of meta.props) {
|
|
251
|
+
if (prop.onCreate) {
|
|
252
|
+
entity[prop.name] ??= prop.onCreate(entity, this.em);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
231
256
|
hydrate(entity, meta, data, options) {
|
|
232
257
|
if (options.initialized) {
|
|
233
|
-
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);
|
|
234
259
|
}
|
|
235
260
|
else {
|
|
236
|
-
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);
|
|
237
262
|
}
|
|
238
263
|
Utils.keys(data).forEach(key => {
|
|
239
264
|
helper(entity)?.__loadedProperties.add(key);
|
|
240
265
|
helper(entity)?.__serializationContext.fields?.add(key);
|
|
241
266
|
});
|
|
267
|
+
const processOnCreateHooksEarly = options.processOnCreateHooksEarly ?? this.config.get('processOnCreateHooksEarly');
|
|
268
|
+
if (options.newEntity && processOnCreateHooksEarly) {
|
|
269
|
+
this.assignDefaultValues(entity, meta);
|
|
270
|
+
}
|
|
242
271
|
}
|
|
243
272
|
findEntity(data, meta, options) {
|
|
244
273
|
const schema = this.driver.getSchemaName(meta, options);
|
|
245
274
|
if (meta.simplePK) {
|
|
246
|
-
return this.unitOfWork.getById(meta.
|
|
275
|
+
return this.unitOfWork.getById(meta.class, data[meta.primaryKeys[0]], schema);
|
|
247
276
|
}
|
|
248
277
|
if (!Array.isArray(data) && meta.primaryKeys.some(pk => data[pk] == null)) {
|
|
249
278
|
return undefined;
|
|
250
279
|
}
|
|
251
|
-
const pks = Utils.getOrderedPrimaryKeys(data, meta, this.platform);
|
|
252
|
-
return this.unitOfWork.getById(meta.
|
|
280
|
+
const pks = Utils.getOrderedPrimaryKeys(data, meta, this.platform, options.convertCustomTypes);
|
|
281
|
+
return this.unitOfWork.getById(meta.class, pks, schema);
|
|
253
282
|
}
|
|
254
283
|
processDiscriminatorColumn(meta, data) {
|
|
255
284
|
if (!meta.root.discriminatorColumn) {
|
|
@@ -258,60 +287,65 @@ export class EntityFactory {
|
|
|
258
287
|
const prop = meta.properties[meta.root.discriminatorColumn];
|
|
259
288
|
const value = data[prop.name];
|
|
260
289
|
const type = meta.root.discriminatorMap[value];
|
|
261
|
-
meta = type ? this.metadata.
|
|
290
|
+
meta = type ? this.metadata.get(type) : meta;
|
|
262
291
|
return meta;
|
|
263
292
|
}
|
|
264
293
|
/**
|
|
265
294
|
* denormalize PK to value required by driver (e.g. ObjectId)
|
|
266
295
|
*/
|
|
267
|
-
denormalizePrimaryKey(
|
|
268
|
-
const pk =
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
data[
|
|
296
|
+
denormalizePrimaryKey(meta, data) {
|
|
297
|
+
const pk = meta.getPrimaryProp();
|
|
298
|
+
const spk = meta.properties[meta.serializedPrimaryKey];
|
|
299
|
+
if (!spk?.serializedPrimaryKey) {
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
if (pk.type === 'ObjectId' && (data[pk.name] != null || data[spk.name] != null)) {
|
|
303
|
+
data[pk.name] = this.platform.denormalizePrimaryKey((data[spk.name] || data[pk.name]));
|
|
304
|
+
delete data[spk.name];
|
|
276
305
|
}
|
|
277
306
|
}
|
|
278
307
|
/**
|
|
279
308
|
* returns parameters for entity constructor, creating references from plain ids
|
|
280
309
|
*/
|
|
281
310
|
extractConstructorParams(meta, data, options) {
|
|
311
|
+
if (!meta.constructorParams) {
|
|
312
|
+
return [data];
|
|
313
|
+
}
|
|
282
314
|
return meta.constructorParams.map(k => {
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
315
|
+
const prop = meta.properties[k];
|
|
316
|
+
const value = data[k];
|
|
317
|
+
if (prop && [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && value) {
|
|
318
|
+
const pk = Reference.unwrapReference(value);
|
|
319
|
+
const entity = this.unitOfWork.getById(prop.targetMeta.class, pk, options.schema, true);
|
|
286
320
|
if (entity) {
|
|
287
321
|
return entity;
|
|
288
322
|
}
|
|
289
|
-
if (Utils.isEntity(
|
|
290
|
-
return
|
|
323
|
+
if (Utils.isEntity(value)) {
|
|
324
|
+
return value;
|
|
291
325
|
}
|
|
292
|
-
const nakedPk = Utils.extractPK(
|
|
293
|
-
if (Utils.isObject(
|
|
294
|
-
return this.create(
|
|
326
|
+
const nakedPk = Utils.extractPK(value, prop.targetMeta, true);
|
|
327
|
+
if (Utils.isObject(value) && !nakedPk) {
|
|
328
|
+
return this.create(prop.targetMeta.class, value, options);
|
|
295
329
|
}
|
|
296
330
|
const { newEntity, initialized, ...rest } = options;
|
|
297
|
-
const target = this.createReference(
|
|
298
|
-
return Reference.wrapReference(target,
|
|
331
|
+
const target = this.createReference(prop.targetMeta.class, nakedPk, rest);
|
|
332
|
+
return Reference.wrapReference(target, prop);
|
|
299
333
|
}
|
|
300
|
-
if (
|
|
301
|
-
/* v8 ignore next
|
|
302
|
-
if (Utils.isEntity(
|
|
303
|
-
return
|
|
334
|
+
if (prop?.kind === ReferenceKind.EMBEDDED && value) {
|
|
335
|
+
/* v8 ignore next */
|
|
336
|
+
if (Utils.isEntity(value)) {
|
|
337
|
+
return value;
|
|
304
338
|
}
|
|
305
|
-
return this.createEmbeddable(
|
|
339
|
+
return this.createEmbeddable(prop.targetMeta.class, value, options);
|
|
306
340
|
}
|
|
307
|
-
if (!
|
|
341
|
+
if (!prop) {
|
|
308
342
|
const tmp = { ...data };
|
|
309
343
|
for (const prop of meta.props) {
|
|
310
344
|
if (!options.convertCustomTypes || !prop.customType || tmp[prop.name] == null) {
|
|
311
345
|
continue;
|
|
312
346
|
}
|
|
313
|
-
if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && Utils.isPlainObject(tmp[prop.name]) && !Utils.extractPK(tmp[prop.name],
|
|
314
|
-
tmp[prop.name] = Reference.wrapReference(this.create(
|
|
347
|
+
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)) {
|
|
348
|
+
tmp[prop.name] = Reference.wrapReference(this.create(prop.targetMeta.class, tmp[prop.name], options), prop);
|
|
315
349
|
}
|
|
316
350
|
else if (prop.kind === ReferenceKind.SCALAR) {
|
|
317
351
|
tmp[prop.name] = prop.customType.convertToJSValue(tmp[prop.name], this.platform);
|
|
@@ -319,10 +353,10 @@ export class EntityFactory {
|
|
|
319
353
|
}
|
|
320
354
|
return tmp;
|
|
321
355
|
}
|
|
322
|
-
if (options.convertCustomTypes &&
|
|
323
|
-
return
|
|
356
|
+
if (options.convertCustomTypes && prop.customType && value != null) {
|
|
357
|
+
return prop.customType.convertToJSValue(value, this.platform);
|
|
324
358
|
}
|
|
325
|
-
return
|
|
359
|
+
return value;
|
|
326
360
|
});
|
|
327
361
|
}
|
|
328
362
|
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,14 @@ 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
|
-
return EntityTransformer.toObject(this, ...args
|
|
36
|
+
return EntityTransformer.toObject(this, ...args);
|
|
36
37
|
};
|
|
37
38
|
}
|
|
38
39
|
}
|
|
39
40
|
/**
|
|
40
|
-
* As a performance optimization, we create entity state methods
|
|
41
|
+
* As a performance optimization, we create entity state methods lazily. We first add
|
|
41
42
|
* the `null` value to the prototype to reserve space in memory. Then we define a setter on the
|
|
42
|
-
* prototype
|
|
43
|
+
* prototype that will be executed exactly once per entity instance. There we redefine the given
|
|
43
44
|
* property on the entity instance, so shadowing the prototype setter.
|
|
44
45
|
*/
|
|
45
46
|
static defineBaseProperties(meta, prototype, em) {
|
|
@@ -87,7 +88,7 @@ export class EntityHelper {
|
|
|
87
88
|
});
|
|
88
89
|
return;
|
|
89
90
|
}
|
|
90
|
-
if (prop.inherited || prop.primary || prop.
|
|
91
|
+
if (prop.inherited || prop.primary || prop.accessor || prop.persist === false || prop.embedded || isCollection) {
|
|
91
92
|
return;
|
|
92
93
|
}
|
|
93
94
|
Object.defineProperty(meta.prototype, prop.name, {
|
|
@@ -98,13 +99,11 @@ export class EntityHelper {
|
|
|
98
99
|
},
|
|
99
100
|
set(val) {
|
|
100
101
|
this.__helper.__data[prop.name] = val;
|
|
101
|
-
this.__helper.__touched = !this.__helper.hydrator.isRunning();
|
|
102
102
|
},
|
|
103
103
|
enumerable: true,
|
|
104
104
|
configurable: true,
|
|
105
105
|
});
|
|
106
106
|
this.__helper.__data[prop.name] = val;
|
|
107
|
-
this.__helper.__touched = !this.__helper.hydrator.isRunning();
|
|
108
107
|
},
|
|
109
108
|
configurable: true,
|
|
110
109
|
});
|
|
@@ -112,16 +111,27 @@ export class EntityHelper {
|
|
|
112
111
|
}
|
|
113
112
|
static defineCustomInspect(meta) {
|
|
114
113
|
// @ts-ignore
|
|
115
|
-
meta.prototype[inspect.custom] ??= function (depth = 2) {
|
|
116
|
-
const object = {
|
|
114
|
+
meta.prototype[Symbol.for('nodejs.util.inspect.custom')] ??= function (depth = 2) {
|
|
115
|
+
const object = {};
|
|
116
|
+
const keys = new Set(Utils.keys(this));
|
|
117
|
+
for (const prop of meta.props) {
|
|
118
|
+
if (keys.has(prop.name) || (prop.getter && prop.accessor === prop.name)) {
|
|
119
|
+
object[prop.name] = this[prop.name];
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
for (const key of keys) {
|
|
123
|
+
if (!meta.properties[key]) {
|
|
124
|
+
object[key] = this[key];
|
|
125
|
+
}
|
|
126
|
+
}
|
|
117
127
|
// ensure we dont have internal symbols in the POJO
|
|
118
128
|
[OptionalProps, EntityRepositoryType, PrimaryKeyProp, EagerProps, HiddenProps].forEach(sym => delete object[sym]);
|
|
119
129
|
meta.props
|
|
120
130
|
.filter(prop => object[prop.name] === undefined)
|
|
121
131
|
.forEach(prop => delete object[prop.name]);
|
|
122
132
|
const ret = inspect(object, { depth });
|
|
123
|
-
let name =
|
|
124
|
-
const showEM = ['true', 't', '1'].includes(
|
|
133
|
+
let name = this.constructor.name;
|
|
134
|
+
const showEM = ['true', 't', '1'].includes(getEnv('MIKRO_ORM_LOG_EM_ID')?.toLowerCase() ?? '');
|
|
125
135
|
if (showEM) {
|
|
126
136
|
if (helper(this).__em) {
|
|
127
137
|
name += ` [managed by ${helper(this).__em.id}]`;
|
|
@@ -146,13 +156,13 @@ export class EntityHelper {
|
|
|
146
156
|
set(val) {
|
|
147
157
|
const entity = Reference.unwrapReference(val ?? wrapped.__data[prop.name]);
|
|
148
158
|
const old = Reference.unwrapReference(wrapped.__data[prop.name]);
|
|
159
|
+
if (old && old !== entity && prop.kind === ReferenceKind.MANY_TO_ONE && prop.inversedBy && old[prop.inversedBy]) {
|
|
160
|
+
old[prop.inversedBy].removeWithoutPropagation(this);
|
|
161
|
+
}
|
|
149
162
|
wrapped.__data[prop.name] = Reference.wrapReference(val, prop);
|
|
150
163
|
// when propagation from inside hydration, we set the FK to the entity data immediately
|
|
151
164
|
if (val && hydrator.isRunning() && wrapped.__originalEntityData && prop.owner) {
|
|
152
|
-
wrapped.__originalEntityData[prop.name] = Utils.getPrimaryKeyValues(wrapped.__data[prop.name], prop.targetMeta
|
|
153
|
-
}
|
|
154
|
-
else {
|
|
155
|
-
wrapped.__touched = !hydrator.isRunning();
|
|
165
|
+
wrapped.__originalEntityData[prop.name] = Utils.getPrimaryKeyValues(wrapped.__data[prop.name], prop.targetMeta, true);
|
|
156
166
|
}
|
|
157
167
|
EntityHelper.propagate(meta, entity, this, prop, Reference.unwrapReference(val), old);
|
|
158
168
|
},
|
|
@@ -169,6 +179,13 @@ export class EntityHelper {
|
|
|
169
179
|
continue;
|
|
170
180
|
}
|
|
171
181
|
const inverse = value?.[prop2.name];
|
|
182
|
+
if (prop.ref && owner[prop.name]) {
|
|
183
|
+
// eslint-disable-next-line dot-notation
|
|
184
|
+
owner[prop.name]['property'] = prop;
|
|
185
|
+
}
|
|
186
|
+
if (Utils.isCollection(inverse) && inverse.isPartial()) {
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
172
189
|
if (prop.kind === ReferenceKind.MANY_TO_ONE && Utils.isCollection(inverse) && inverse.isInitialized()) {
|
|
173
190
|
inverse.addWithoutPropagation(owner);
|
|
174
191
|
helper(owner).__em?.getUnitOfWork().cancelOrphanRemoval(owner);
|
|
@@ -196,6 +213,11 @@ export class EntityHelper {
|
|
|
196
213
|
helper(other).__em?.getUnitOfWork().scheduleOrphanRemoval(other);
|
|
197
214
|
}
|
|
198
215
|
}
|
|
216
|
+
// Skip setting the inverse side to null if it's a primary key - the entity will be removed via orphan removal
|
|
217
|
+
// Setting a primary key to null would corrupt the entity and cause validation errors
|
|
218
|
+
if (value == null && prop.orphanRemoval && prop2.primary) {
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
199
221
|
if (value == null) {
|
|
200
222
|
entity[prop2.name] = value;
|
|
201
223
|
}
|
|
@@ -207,6 +229,7 @@ export class EntityHelper {
|
|
|
207
229
|
}
|
|
208
230
|
if (old?.[prop2.name] != null) {
|
|
209
231
|
delete helper(old).__data[prop2.name];
|
|
232
|
+
old[prop2.name] = null;
|
|
210
233
|
}
|
|
211
234
|
}
|
|
212
235
|
static ensurePropagation(entity) {
|