@mikro-orm/core 7.0.0-dev.1 → 7.0.0-dev.100
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 +96 -58
- package/EntityManager.js +465 -395
- package/MikroORM.d.ts +45 -35
- package/MikroORM.js +109 -160
- package/README.md +3 -2
- package/cache/CacheAdapter.js +1 -2
- package/cache/FileCacheAdapter.d.ts +2 -2
- package/cache/FileCacheAdapter.js +20 -27
- package/cache/GeneratedCacheAdapter.d.ts +2 -3
- package/cache/GeneratedCacheAdapter.js +1 -7
- package/cache/MemoryCacheAdapter.d.ts +1 -1
- package/cache/MemoryCacheAdapter.js +1 -5
- package/cache/NullCacheAdapter.d.ts +1 -1
- package/cache/NullCacheAdapter.js +1 -5
- package/cache/index.d.ts +4 -5
- package/cache/index.js +4 -21
- package/connections/Connection.d.ts +22 -14
- package/connections/Connection.js +27 -23
- package/connections/index.d.ts +1 -1
- package/connections/index.js +1 -17
- package/drivers/DatabaseDriver.d.ts +25 -15
- package/drivers/DatabaseDriver.js +77 -64
- package/drivers/IDatabaseDriver.d.ts +40 -16
- package/drivers/IDatabaseDriver.js +1 -4
- package/drivers/index.d.ts +2 -2
- package/drivers/index.js +2 -18
- package/entity/BaseEntity.d.ts +6 -7
- package/entity/BaseEntity.js +16 -23
- package/entity/Collection.d.ts +98 -34
- package/entity/Collection.js +466 -131
- package/entity/EntityAssigner.d.ts +3 -3
- package/entity/EntityAssigner.js +67 -64
- package/entity/EntityFactory.d.ts +10 -3
- package/entity/EntityFactory.js +112 -91
- package/entity/EntityHelper.d.ts +2 -2
- package/entity/EntityHelper.js +66 -53
- package/entity/EntityIdentifier.d.ts +1 -1
- package/entity/EntityIdentifier.js +1 -5
- package/entity/EntityLoader.d.ts +8 -7
- package/entity/EntityLoader.js +161 -128
- package/entity/EntityRepository.d.ts +8 -8
- package/entity/EntityRepository.js +7 -11
- package/entity/Reference.d.ts +10 -13
- package/entity/Reference.js +64 -46
- package/entity/WrappedEntity.d.ts +12 -17
- package/entity/WrappedEntity.js +22 -31
- package/entity/defineEntity.d.ts +568 -0
- package/entity/defineEntity.js +529 -0
- package/entity/index.d.ts +14 -13
- package/entity/index.js +14 -29
- package/entity/utils.d.ts +8 -1
- package/entity/utils.js +22 -13
- package/entity/validators.d.ts +11 -0
- package/entity/validators.js +65 -0
- package/entity/wrap.d.ts +1 -1
- package/entity/wrap.js +2 -6
- package/enums.d.ts +24 -9
- package/enums.js +50 -41
- package/errors.d.ts +11 -3
- package/errors.js +42 -32
- package/events/EventManager.d.ts +5 -4
- package/events/EventManager.js +26 -22
- package/events/EventSubscriber.d.ts +8 -5
- package/events/EventSubscriber.js +1 -2
- package/events/TransactionEventBroadcaster.d.ts +3 -3
- package/events/TransactionEventBroadcaster.js +1 -5
- package/events/index.d.ts +3 -3
- package/events/index.js +3 -19
- package/exceptions.js +18 -39
- package/hydration/Hydrator.d.ts +5 -5
- package/hydration/Hydrator.js +2 -6
- package/hydration/ObjectHydrator.d.ts +7 -7
- package/hydration/ObjectHydrator.js +58 -50
- package/hydration/index.d.ts +2 -2
- package/hydration/index.js +2 -18
- package/index.d.ts +21 -21
- package/index.js +20 -46
- package/logging/DefaultLogger.d.ts +2 -2
- package/logging/DefaultLogger.js +10 -13
- package/logging/Logger.d.ts +1 -1
- package/logging/Logger.js +1 -2
- package/logging/SimpleLogger.d.ts +3 -3
- package/logging/SimpleLogger.js +2 -6
- package/logging/colors.js +1 -5
- package/logging/index.d.ts +5 -4
- package/logging/index.js +5 -20
- package/logging/inspect.d.ts +2 -0
- package/logging/inspect.js +16 -0
- package/metadata/EntitySchema.d.ts +14 -10
- package/metadata/EntitySchema.js +78 -64
- package/metadata/MetadataDiscovery.d.ts +11 -14
- package/metadata/MetadataDiscovery.js +278 -317
- package/metadata/MetadataProvider.d.ts +13 -4
- package/metadata/MetadataProvider.js +47 -8
- package/metadata/MetadataStorage.d.ts +2 -7
- package/metadata/MetadataStorage.js +19 -35
- package/metadata/MetadataValidator.d.ts +3 -10
- package/metadata/MetadataValidator.js +51 -64
- package/metadata/discover-entities.d.ts +5 -0
- package/metadata/discover-entities.js +40 -0
- package/metadata/index.d.ts +6 -6
- package/metadata/index.js +6 -22
- package/metadata/types.d.ts +480 -0
- package/metadata/types.js +1 -0
- package/naming-strategy/AbstractNamingStrategy.d.ts +7 -3
- package/naming-strategy/AbstractNamingStrategy.js +11 -9
- package/naming-strategy/EntityCaseNamingStrategy.d.ts +1 -1
- package/naming-strategy/EntityCaseNamingStrategy.js +2 -6
- package/naming-strategy/MongoNamingStrategy.d.ts +1 -1
- package/naming-strategy/MongoNamingStrategy.js +2 -6
- package/naming-strategy/NamingStrategy.d.ts +12 -2
- package/naming-strategy/NamingStrategy.js +1 -2
- package/naming-strategy/UnderscoreNamingStrategy.d.ts +1 -1
- package/naming-strategy/UnderscoreNamingStrategy.js +2 -6
- package/naming-strategy/index.d.ts +5 -5
- package/naming-strategy/index.js +5 -21
- package/not-supported.d.ts +2 -0
- package/not-supported.js +4 -0
- package/package.json +19 -20
- package/platforms/ExceptionConverter.d.ts +2 -2
- package/platforms/ExceptionConverter.js +4 -8
- package/platforms/Platform.d.ts +15 -22
- package/platforms/Platform.js +58 -88
- package/platforms/index.d.ts +2 -2
- package/platforms/index.js +2 -18
- package/serialization/EntitySerializer.d.ts +4 -2
- package/serialization/EntitySerializer.js +64 -51
- package/serialization/EntityTransformer.d.ts +1 -1
- package/serialization/EntityTransformer.js +48 -42
- package/serialization/SerializationContext.d.ts +2 -2
- package/serialization/SerializationContext.js +24 -25
- package/serialization/index.d.ts +3 -3
- package/serialization/index.js +3 -19
- package/types/ArrayType.d.ts +3 -3
- package/types/ArrayType.js +6 -11
- package/types/BigIntType.d.ts +12 -9
- package/types/BigIntType.js +6 -6
- package/types/BlobType.d.ts +3 -4
- package/types/BlobType.js +2 -11
- package/types/BooleanType.d.ts +5 -4
- package/types/BooleanType.js +5 -6
- package/types/CharacterType.d.ts +3 -3
- package/types/CharacterType.js +2 -6
- package/types/DateTimeType.d.ts +3 -3
- package/types/DateTimeType.js +2 -6
- package/types/DateType.d.ts +3 -3
- package/types/DateType.js +2 -6
- package/types/DecimalType.d.ts +9 -7
- package/types/DecimalType.js +5 -8
- package/types/DoubleType.d.ts +3 -3
- package/types/DoubleType.js +4 -7
- package/types/EnumArrayType.d.ts +4 -4
- package/types/EnumArrayType.js +4 -10
- package/types/EnumType.d.ts +3 -3
- package/types/EnumType.js +2 -6
- package/types/FloatType.d.ts +3 -3
- package/types/FloatType.js +2 -6
- package/types/IntegerType.d.ts +3 -3
- package/types/IntegerType.js +2 -6
- package/types/IntervalType.d.ts +3 -3
- package/types/IntervalType.js +2 -6
- package/types/JsonType.d.ts +4 -4
- package/types/JsonType.js +9 -8
- package/types/MediumIntType.d.ts +3 -3
- package/types/MediumIntType.js +2 -6
- package/types/SmallIntType.d.ts +3 -3
- package/types/SmallIntType.js +2 -6
- package/types/StringType.d.ts +3 -3
- package/types/StringType.js +2 -6
- package/types/TextType.d.ts +3 -3
- package/types/TextType.js +2 -6
- package/types/TimeType.d.ts +3 -3
- package/types/TimeType.js +4 -8
- package/types/TinyIntType.d.ts +3 -3
- package/types/TinyIntType.js +3 -6
- package/types/Type.d.ts +4 -6
- package/types/Type.js +6 -10
- package/types/Uint8ArrayType.d.ts +3 -4
- package/types/Uint8ArrayType.js +3 -12
- package/types/UnknownType.d.ts +3 -3
- package/types/UnknownType.js +2 -6
- package/types/UuidType.d.ts +3 -3
- package/types/UuidType.js +2 -6
- package/types/index.d.ts +25 -25
- package/types/index.js +52 -79
- package/typings.d.ts +134 -93
- package/typings.js +67 -65
- package/unit-of-work/ChangeSet.d.ts +1 -4
- package/unit-of-work/ChangeSet.js +13 -17
- package/unit-of-work/ChangeSetComputer.d.ts +8 -9
- package/unit-of-work/ChangeSetComputer.js +36 -38
- package/unit-of-work/ChangeSetPersister.d.ts +11 -9
- package/unit-of-work/ChangeSetPersister.js +100 -65
- package/unit-of-work/CommitOrderCalculator.d.ts +1 -1
- package/unit-of-work/CommitOrderCalculator.js +6 -10
- package/unit-of-work/IdentityMap.d.ts +1 -1
- package/unit-of-work/IdentityMap.js +1 -5
- package/unit-of-work/UnitOfWork.d.ts +16 -8
- package/unit-of-work/UnitOfWork.js +266 -209
- package/unit-of-work/index.d.ts +6 -6
- package/unit-of-work/index.js +6 -22
- package/utils/AbstractSchemaGenerator.d.ts +11 -11
- package/utils/AbstractSchemaGenerator.js +21 -20
- package/utils/Configuration.d.ts +774 -224
- package/utils/Configuration.js +166 -216
- package/utils/ConfigurationLoader.d.ts +1 -53
- package/utils/ConfigurationLoader.js +1 -367
- package/utils/Cursor.d.ts +6 -9
- package/utils/Cursor.js +25 -25
- package/utils/DataloaderUtils.d.ts +18 -8
- package/utils/DataloaderUtils.js +63 -21
- package/utils/EntityComparator.d.ts +9 -5
- package/utils/EntityComparator.js +155 -108
- package/utils/NullHighlighter.d.ts +1 -1
- package/utils/NullHighlighter.js +1 -5
- package/utils/QueryHelper.d.ts +12 -4
- package/utils/QueryHelper.js +110 -53
- package/utils/RawQueryFragment.d.ts +37 -14
- package/utils/RawQueryFragment.js +50 -33
- package/utils/RequestContext.d.ts +2 -2
- package/utils/RequestContext.js +3 -7
- package/utils/TransactionContext.d.ts +1 -1
- package/utils/TransactionContext.js +4 -8
- package/utils/TransactionManager.d.ts +65 -0
- package/utils/TransactionManager.js +223 -0
- package/utils/Utils.d.ts +16 -100
- package/utils/Utils.js +114 -332
- package/utils/clone.js +7 -11
- package/utils/env-vars.d.ts +3 -0
- package/utils/env-vars.js +87 -0
- package/utils/fs-utils.d.ts +12 -0
- package/utils/fs-utils.js +97 -0
- package/utils/index.d.ts +14 -13
- package/utils/index.js +14 -29
- package/utils/upsert-utils.d.ts +8 -3
- package/utils/upsert-utils.js +57 -10
- package/decorators/Check.d.ts +0 -3
- package/decorators/Check.js +0 -16
- package/decorators/CreateRequestContext.d.ts +0 -3
- package/decorators/CreateRequestContext.js +0 -33
- package/decorators/Embeddable.d.ts +0 -8
- package/decorators/Embeddable.js +0 -14
- package/decorators/Embedded.d.ts +0 -18
- package/decorators/Embedded.js +0 -20
- package/decorators/Entity.d.ts +0 -18
- package/decorators/Entity.js +0 -16
- package/decorators/Enum.d.ts +0 -9
- package/decorators/Enum.js +0 -19
- package/decorators/Filter.d.ts +0 -2
- package/decorators/Filter.js +0 -11
- package/decorators/Formula.d.ts +0 -5
- package/decorators/Formula.js +0 -18
- package/decorators/Indexed.d.ts +0 -17
- package/decorators/Indexed.js +0 -24
- package/decorators/ManyToMany.d.ts +0 -40
- package/decorators/ManyToMany.js +0 -16
- package/decorators/ManyToOne.d.ts +0 -30
- package/decorators/ManyToOne.js +0 -16
- package/decorators/OneToMany.d.ts +0 -28
- package/decorators/OneToMany.js +0 -20
- package/decorators/OneToOne.d.ts +0 -24
- package/decorators/OneToOne.js +0 -10
- package/decorators/PrimaryKey.d.ts +0 -9
- package/decorators/PrimaryKey.js +0 -23
- package/decorators/Property.d.ts +0 -250
- package/decorators/Property.js +0 -34
- package/decorators/Transactional.d.ts +0 -13
- package/decorators/Transactional.js +0 -31
- package/decorators/hooks.d.ts +0 -16
- package/decorators/hooks.js +0 -59
- package/decorators/index.d.ts +0 -17
- package/decorators/index.js +0 -36
- package/entity/ArrayCollection.d.ts +0 -116
- package/entity/ArrayCollection.js +0 -399
- package/entity/EntityValidator.d.ts +0 -19
- package/entity/EntityValidator.js +0 -154
- package/index.mjs +0 -199
- package/metadata/ReflectMetadataProvider.d.ts +0 -8
- package/metadata/ReflectMetadataProvider.js +0 -48
- package/utils/resolveContextProvider.d.ts +0 -10
- package/utils/resolveContextProvider.js +0 -31
|
@@ -1,20 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
|
+
import { Collection } from '../entity/Collection.js';
|
|
3
|
+
import { EntityHelper } from '../entity/EntityHelper.js';
|
|
4
|
+
import { helper } from '../entity/wrap.js';
|
|
5
|
+
import { Reference } from '../entity/Reference.js';
|
|
6
|
+
import { EntityIdentifier } from '../entity/EntityIdentifier.js';
|
|
7
|
+
import { ChangeSet, ChangeSetType } from './ChangeSet.js';
|
|
8
|
+
import { ChangeSetComputer } from './ChangeSetComputer.js';
|
|
9
|
+
import { ChangeSetPersister } from './ChangeSetPersister.js';
|
|
10
|
+
import { CommitOrderCalculator } from './CommitOrderCalculator.js';
|
|
11
|
+
import { Utils } from '../utils/Utils.js';
|
|
12
|
+
import { Cascade, DeferMode, EventType, LockMode, ReferenceKind } from '../enums.js';
|
|
13
|
+
import { OptimisticLockError, ValidationError } from '../errors.js';
|
|
14
|
+
import { TransactionEventBroadcaster } from '../events/TransactionEventBroadcaster.js';
|
|
15
|
+
import { IdentityMap } from './IdentityMap.js';
|
|
15
16
|
// to deal with validation for flush inside flush hooks and `Promise.all`
|
|
16
|
-
const insideFlush = new
|
|
17
|
-
class UnitOfWork {
|
|
17
|
+
const insideFlush = new AsyncLocalStorage();
|
|
18
|
+
export class UnitOfWork {
|
|
18
19
|
em;
|
|
19
20
|
/** map of references to managed entities */
|
|
20
21
|
identityMap;
|
|
@@ -38,14 +39,14 @@ class UnitOfWork {
|
|
|
38
39
|
this.em = em;
|
|
39
40
|
this.metadata = this.em.getMetadata();
|
|
40
41
|
this.platform = this.em.getPlatform();
|
|
41
|
-
this.identityMap = new
|
|
42
|
+
this.identityMap = new IdentityMap(this.platform.getDefaultSchemaName());
|
|
42
43
|
this.eventManager = this.em.getEventManager();
|
|
43
44
|
this.comparator = this.em.getComparator();
|
|
44
|
-
this.changeSetComputer = new
|
|
45
|
-
this.changeSetPersister = new
|
|
45
|
+
this.changeSetComputer = new ChangeSetComputer(this.collectionUpdates, this.metadata, this.platform, this.em.config, this.em);
|
|
46
|
+
this.changeSetPersister = new ChangeSetPersister(this.em.getDriver(), this.metadata, this.em.config.getHydrator(this.metadata), this.em.getEntityFactory(), this.em.config, this.em);
|
|
46
47
|
}
|
|
47
48
|
merge(entity, visited) {
|
|
48
|
-
const wrapped =
|
|
49
|
+
const wrapped = helper(entity);
|
|
49
50
|
wrapped.__em = this.em;
|
|
50
51
|
if (!wrapped.hasPrimaryKey()) {
|
|
51
52
|
return;
|
|
@@ -60,52 +61,68 @@ class UnitOfWork {
|
|
|
60
61
|
// as there can be some entity with already changed state that is not yet flushed
|
|
61
62
|
if (wrapped.__initialized && (!visited || !wrapped.__originalEntityData)) {
|
|
62
63
|
wrapped.__originalEntityData = this.comparator.prepareEntity(entity);
|
|
63
|
-
wrapped.__touched = false;
|
|
64
64
|
}
|
|
65
|
-
this.cascade(entity,
|
|
65
|
+
this.cascade(entity, Cascade.MERGE, visited ?? new Set());
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Entity data can wary in its shape, e.g. we might get a deep relation graph with joined strategy, but for diffing,
|
|
69
|
+
* we need to normalize the shape, so relation values are only raw FKs. This method handles that.
|
|
70
|
+
* @internal
|
|
71
|
+
*/
|
|
72
|
+
normalizeEntityData(meta, data) {
|
|
73
|
+
const forceUndefined = this.em.config.get('forceUndefined');
|
|
74
|
+
for (const key of Utils.keys(data)) {
|
|
75
|
+
const prop = meta.properties[key];
|
|
76
|
+
if (!prop) {
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && Utils.isPlainObject(data[prop.name])) {
|
|
80
|
+
data[prop.name] = Utils.getPrimaryKeyValues(data[prop.name], prop.targetMeta, true);
|
|
81
|
+
}
|
|
82
|
+
else if (prop.kind === ReferenceKind.EMBEDDED && !prop.object && Utils.isPlainObject(data[prop.name])) {
|
|
83
|
+
for (const p of prop.targetMeta.props) {
|
|
84
|
+
/* v8 ignore next */
|
|
85
|
+
const prefix = prop.prefix === false ? '' : prop.prefix === true ? prop.name + '_' : prop.prefix;
|
|
86
|
+
data[prefix + p.name] = data[prop.name][p.name];
|
|
87
|
+
}
|
|
88
|
+
data[prop.name] = Utils.getPrimaryKeyValues(data[prop.name], prop.targetMeta, true);
|
|
89
|
+
}
|
|
90
|
+
if (prop.hydrate === false && prop.customType?.ensureComparable(meta, prop)) {
|
|
91
|
+
const converted = prop.customType.convertToJSValue(data[key], this.platform, { key, mode: 'hydration', force: true });
|
|
92
|
+
data[key] = prop.customType.convertToDatabaseValue(converted, this.platform, { key, mode: 'hydration' });
|
|
93
|
+
}
|
|
94
|
+
if (forceUndefined) {
|
|
95
|
+
if (data[key] === null) {
|
|
96
|
+
data[key] = undefined;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
66
100
|
}
|
|
67
101
|
/**
|
|
68
102
|
* @internal
|
|
69
103
|
*/
|
|
70
104
|
register(entity, data, options) {
|
|
71
105
|
this.identityMap.store(entity);
|
|
72
|
-
|
|
106
|
+
EntityHelper.ensurePropagation(entity);
|
|
73
107
|
if (options?.newEntity) {
|
|
74
108
|
return entity;
|
|
75
109
|
}
|
|
76
110
|
const forceUndefined = this.em.config.get('forceUndefined');
|
|
77
|
-
const wrapped =
|
|
111
|
+
const wrapped = helper(entity);
|
|
78
112
|
if (options?.loaded && wrapped.__initialized && !wrapped.__onLoadFired) {
|
|
79
113
|
this.loadedEntities.add(entity);
|
|
80
114
|
}
|
|
81
115
|
wrapped.__em ??= this.em;
|
|
82
116
|
wrapped.__managed = true;
|
|
83
117
|
if (data && (options?.refresh || !wrapped.__originalEntityData)) {
|
|
84
|
-
|
|
118
|
+
this.normalizeEntityData(wrapped.__meta, data);
|
|
119
|
+
for (const key of Utils.keys(data)) {
|
|
85
120
|
const prop = wrapped.__meta.properties[key];
|
|
86
|
-
if (
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
wrapped.__loadedProperties.add(key);
|
|
90
|
-
if ([enums_1.ReferenceKind.MANY_TO_ONE, enums_1.ReferenceKind.ONE_TO_ONE].includes(prop.kind) && Utils_1.Utils.isPlainObject(data[prop.name])) {
|
|
91
|
-
data[prop.name] = Utils_1.Utils.getPrimaryKeyValues(data[prop.name], prop.targetMeta.primaryKeys, true);
|
|
92
|
-
}
|
|
93
|
-
else if (prop.kind === enums_1.ReferenceKind.EMBEDDED && !prop.object && Utils_1.Utils.isPlainObject(data[prop.name])) {
|
|
94
|
-
for (const p of prop.targetMeta.props) {
|
|
95
|
-
/* istanbul ignore next */
|
|
96
|
-
const prefix = prop.prefix === false ? '' : prop.prefix === true ? prop.name + '_' : prop.prefix;
|
|
97
|
-
data[prefix + p.name] = data[prop.name][p.name];
|
|
98
|
-
}
|
|
99
|
-
data[prop.name] = Utils_1.Utils.getPrimaryKeyValues(data[prop.name], prop.targetMeta.primaryKeys, true);
|
|
100
|
-
}
|
|
101
|
-
if (forceUndefined) {
|
|
102
|
-
if (data[key] === null) {
|
|
103
|
-
data[key] = undefined;
|
|
104
|
-
}
|
|
121
|
+
if (prop) {
|
|
122
|
+
wrapped.__loadedProperties.add(key);
|
|
105
123
|
}
|
|
106
124
|
}
|
|
107
125
|
wrapped.__originalEntityData = data;
|
|
108
|
-
wrapped.__touched = false;
|
|
109
126
|
}
|
|
110
127
|
return entity;
|
|
111
128
|
}
|
|
@@ -114,9 +131,9 @@ class UnitOfWork {
|
|
|
114
131
|
*/
|
|
115
132
|
async dispatchOnLoadEvent() {
|
|
116
133
|
for (const entity of this.loadedEntities) {
|
|
117
|
-
if (this.eventManager.hasListeners(
|
|
118
|
-
await this.eventManager.dispatchEvent(
|
|
119
|
-
|
|
134
|
+
if (this.eventManager.hasListeners(EventType.onLoad, entity.__meta)) {
|
|
135
|
+
await this.eventManager.dispatchEvent(EventType.onLoad, { entity, meta: entity.__meta, em: this.em });
|
|
136
|
+
helper(entity).__onLoadFired = true;
|
|
120
137
|
}
|
|
121
138
|
}
|
|
122
139
|
this.loadedEntities.clear();
|
|
@@ -124,7 +141,7 @@ class UnitOfWork {
|
|
|
124
141
|
/**
|
|
125
142
|
* Returns entity from the identity map. For composite keys, you need to pass an array of PKs in the same order as they are defined in `meta.primaryKeys`.
|
|
126
143
|
*/
|
|
127
|
-
getById(entityName, id, schema) {
|
|
144
|
+
getById(entityName, id, schema, convertCustomTypes) {
|
|
128
145
|
if (id == null || (Array.isArray(id) && id.length === 0)) {
|
|
129
146
|
return undefined;
|
|
130
147
|
}
|
|
@@ -134,8 +151,17 @@ class UnitOfWork {
|
|
|
134
151
|
hash = '' + id;
|
|
135
152
|
}
|
|
136
153
|
else {
|
|
137
|
-
|
|
138
|
-
|
|
154
|
+
let keys = Array.isArray(id) ? Utils.flatten(id) : [id];
|
|
155
|
+
keys = meta.getPrimaryProps(true).map((p, i) => {
|
|
156
|
+
if (!convertCustomTypes && p.customType) {
|
|
157
|
+
return p.customType.convertToDatabaseValue(keys[i], this.platform, {
|
|
158
|
+
key: p.name,
|
|
159
|
+
mode: 'hydration',
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
return keys[i];
|
|
163
|
+
});
|
|
164
|
+
hash = Utils.getPrimaryKeyHash(keys);
|
|
139
165
|
}
|
|
140
166
|
schema ??= meta.schema ?? this.em.config.getSchema();
|
|
141
167
|
if (schema) {
|
|
@@ -144,7 +170,7 @@ class UnitOfWork {
|
|
|
144
170
|
return this.identityMap.getByHash(meta, hash);
|
|
145
171
|
}
|
|
146
172
|
tryGetById(entityName, where, schema, strict = true) {
|
|
147
|
-
const pk =
|
|
173
|
+
const pk = Utils.extractPK(where, this.metadata.find(entityName), strict);
|
|
148
174
|
if (!pk) {
|
|
149
175
|
return null;
|
|
150
176
|
}
|
|
@@ -160,7 +186,7 @@ class UnitOfWork {
|
|
|
160
186
|
* Returns stored snapshot of entity state that is used for change set computation.
|
|
161
187
|
*/
|
|
162
188
|
getOriginalEntityData(entity) {
|
|
163
|
-
return
|
|
189
|
+
return helper(entity).__originalEntityData;
|
|
164
190
|
}
|
|
165
191
|
getPersistStack() {
|
|
166
192
|
return this.persistStack;
|
|
@@ -184,10 +210,8 @@ class UnitOfWork {
|
|
|
184
210
|
if (this.queuedActions.has(meta.className) || this.queuedActions.has(meta.root.className)) {
|
|
185
211
|
return true;
|
|
186
212
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
return true;
|
|
190
|
-
}
|
|
213
|
+
if (meta.discriminatorMap && Object.values(meta.discriminatorMap).some(v => this.queuedActions.has(v))) {
|
|
214
|
+
return true;
|
|
191
215
|
}
|
|
192
216
|
return false;
|
|
193
217
|
}
|
|
@@ -195,9 +219,9 @@ class UnitOfWork {
|
|
|
195
219
|
this.queuedActions.clear();
|
|
196
220
|
}
|
|
197
221
|
computeChangeSet(entity, type) {
|
|
198
|
-
const wrapped =
|
|
222
|
+
const wrapped = helper(entity);
|
|
199
223
|
if (type) {
|
|
200
|
-
this.changeSets.set(entity, new
|
|
224
|
+
this.changeSets.set(entity, new ChangeSet(entity, type, {}, wrapped.__meta));
|
|
201
225
|
return;
|
|
202
226
|
}
|
|
203
227
|
const cs = this.changeSetComputer.computeChangeSet(entity);
|
|
@@ -208,7 +232,6 @@ class UnitOfWork {
|
|
|
208
232
|
this.changeSets.set(entity, cs);
|
|
209
233
|
this.persistStack.delete(entity);
|
|
210
234
|
wrapped.__originalEntityData = this.comparator.prepareEntity(entity);
|
|
211
|
-
wrapped.__touched = false;
|
|
212
235
|
}
|
|
213
236
|
recomputeSingleChangeSet(entity) {
|
|
214
237
|
const changeSet = this.changeSets.get(entity);
|
|
@@ -216,19 +239,17 @@ class UnitOfWork {
|
|
|
216
239
|
return;
|
|
217
240
|
}
|
|
218
241
|
const cs = this.changeSetComputer.computeChangeSet(entity);
|
|
219
|
-
/* istanbul ignore else */
|
|
220
242
|
if (cs && !this.checkUniqueProps(cs)) {
|
|
221
243
|
Object.assign(changeSet.payload, cs.payload);
|
|
222
|
-
|
|
223
|
-
(0, entity_1.helper)(entity).__touched = false;
|
|
244
|
+
helper(entity).__originalEntityData = this.comparator.prepareEntity(entity);
|
|
224
245
|
}
|
|
225
246
|
}
|
|
226
247
|
persist(entity, visited, options = {}) {
|
|
227
|
-
|
|
248
|
+
EntityHelper.ensurePropagation(entity);
|
|
228
249
|
if (options.checkRemoveStack && this.removeStack.has(entity)) {
|
|
229
250
|
return;
|
|
230
251
|
}
|
|
231
|
-
const wrapped =
|
|
252
|
+
const wrapped = helper(entity);
|
|
232
253
|
this.persistStack.add(entity);
|
|
233
254
|
this.queuedActions.add(wrapped.__meta.className);
|
|
234
255
|
this.removeStack.delete(entity);
|
|
@@ -236,43 +257,43 @@ class UnitOfWork {
|
|
|
236
257
|
this.identityMap.store(entity);
|
|
237
258
|
}
|
|
238
259
|
if (options.cascade ?? true) {
|
|
239
|
-
this.cascade(entity,
|
|
260
|
+
this.cascade(entity, Cascade.PERSIST, visited, options);
|
|
240
261
|
}
|
|
241
262
|
}
|
|
242
263
|
remove(entity, visited, options = {}) {
|
|
243
264
|
// allow removing not managed entities if they are not part of the persist stack
|
|
244
|
-
if (
|
|
265
|
+
if (helper(entity).__managed || !this.persistStack.has(entity)) {
|
|
245
266
|
this.removeStack.add(entity);
|
|
246
|
-
this.queuedActions.add(
|
|
267
|
+
this.queuedActions.add(helper(entity).__meta.className);
|
|
247
268
|
}
|
|
248
269
|
else {
|
|
249
270
|
this.persistStack.delete(entity);
|
|
250
271
|
this.identityMap.delete(entity);
|
|
251
272
|
}
|
|
252
273
|
// remove from referencing relations that are nullable
|
|
253
|
-
for (const prop of
|
|
274
|
+
for (const prop of helper(entity).__meta.bidirectionalRelations) {
|
|
254
275
|
const inverseProp = prop.mappedBy || prop.inversedBy;
|
|
255
|
-
const relation =
|
|
276
|
+
const relation = Reference.unwrapReference(entity[prop.name]);
|
|
256
277
|
const prop2 = prop.targetMeta.properties[inverseProp];
|
|
257
|
-
if (prop.kind ===
|
|
278
|
+
if (prop.kind === ReferenceKind.ONE_TO_MANY && prop2.nullable && Utils.isCollection(relation)) {
|
|
258
279
|
for (const item of relation.getItems(false)) {
|
|
259
280
|
delete item[inverseProp];
|
|
260
281
|
}
|
|
261
282
|
continue;
|
|
262
283
|
}
|
|
263
284
|
const target = relation && relation[inverseProp];
|
|
264
|
-
if (relation &&
|
|
285
|
+
if (relation && Utils.isCollection(target)) {
|
|
265
286
|
target.removeWithoutPropagation(entity);
|
|
266
287
|
}
|
|
267
288
|
}
|
|
268
289
|
if (options.cascade ?? true) {
|
|
269
|
-
this.cascade(entity,
|
|
290
|
+
this.cascade(entity, Cascade.REMOVE, visited);
|
|
270
291
|
}
|
|
271
292
|
}
|
|
272
293
|
async commit() {
|
|
273
294
|
if (this.working) {
|
|
274
295
|
if (insideFlush.getStore()) {
|
|
275
|
-
throw
|
|
296
|
+
throw ValidationError.cannotCommit();
|
|
276
297
|
}
|
|
277
298
|
return new Promise((resolve, reject) => {
|
|
278
299
|
this.flushQueue.push(() => {
|
|
@@ -297,23 +318,27 @@ class UnitOfWork {
|
|
|
297
318
|
async doCommit() {
|
|
298
319
|
const oldTx = this.em.getTransactionContext();
|
|
299
320
|
try {
|
|
300
|
-
await this.eventManager.dispatchEvent(
|
|
321
|
+
await this.eventManager.dispatchEvent(EventType.beforeFlush, { em: this.em, uow: this });
|
|
301
322
|
this.computeChangeSets();
|
|
302
323
|
for (const cs of this.changeSets.values()) {
|
|
303
324
|
cs.entity.__helper.__processing = true;
|
|
304
325
|
}
|
|
305
|
-
await this.eventManager.dispatchEvent(
|
|
326
|
+
await this.eventManager.dispatchEvent(EventType.onFlush, { em: this.em, uow: this });
|
|
327
|
+
this.filterCollectionUpdates();
|
|
306
328
|
// nothing to do, do not start transaction
|
|
307
329
|
if (this.changeSets.size === 0 && this.collectionUpdates.size === 0 && this.extraUpdates.size === 0) {
|
|
308
|
-
|
|
330
|
+
await this.eventManager.dispatchEvent(EventType.afterFlush, { em: this.em, uow: this });
|
|
331
|
+
return;
|
|
309
332
|
}
|
|
310
333
|
const groups = this.getChangeSetGroups();
|
|
311
334
|
const platform = this.em.getPlatform();
|
|
312
335
|
const runInTransaction = !this.em.isInTransaction() && platform.supportsTransactions() && this.em.config.get('implicitTransactions');
|
|
313
336
|
if (runInTransaction) {
|
|
337
|
+
const loggerContext = Utils.merge({ id: this.em._id }, this.em.getLoggerContext({ disableContextResolution: true }));
|
|
314
338
|
await this.em.getConnection('write').transactional(trx => this.persistToDatabase(groups, trx), {
|
|
315
339
|
ctx: oldTx,
|
|
316
|
-
eventBroadcaster: new
|
|
340
|
+
eventBroadcaster: new TransactionEventBroadcaster(this.em),
|
|
341
|
+
loggerContext,
|
|
317
342
|
});
|
|
318
343
|
}
|
|
319
344
|
else {
|
|
@@ -323,18 +348,18 @@ class UnitOfWork {
|
|
|
323
348
|
for (const cs of this.changeSets.values()) {
|
|
324
349
|
cs.entity.__helper.__processing = false;
|
|
325
350
|
}
|
|
326
|
-
await this.eventManager.dispatchEvent(
|
|
351
|
+
await this.eventManager.dispatchEvent(EventType.afterFlush, { em: this.em, uow: this });
|
|
327
352
|
}
|
|
328
353
|
finally {
|
|
329
354
|
this.resetTransaction(oldTx);
|
|
330
355
|
}
|
|
331
356
|
}
|
|
332
357
|
async lock(entity, options) {
|
|
333
|
-
if (!this.getById(entity.constructor.name,
|
|
334
|
-
throw
|
|
358
|
+
if (!this.getById(entity.constructor.name, helper(entity).__primaryKeys, helper(entity).__schema)) {
|
|
359
|
+
throw ValidationError.entityNotManaged(entity);
|
|
335
360
|
}
|
|
336
361
|
const meta = this.metadata.find(entity.constructor.name);
|
|
337
|
-
if (options.lockMode ===
|
|
362
|
+
if (options.lockMode === LockMode.OPTIMISTIC) {
|
|
338
363
|
await this.lockOptimistic(entity, meta, options.lockVersion);
|
|
339
364
|
}
|
|
340
365
|
else if (options.lockMode != null) {
|
|
@@ -348,78 +373,77 @@ class UnitOfWork {
|
|
|
348
373
|
}
|
|
349
374
|
unsetIdentity(entity) {
|
|
350
375
|
this.identityMap.delete(entity);
|
|
351
|
-
const wrapped =
|
|
376
|
+
const wrapped = helper(entity);
|
|
352
377
|
const serializedPK = wrapped.getSerializedPrimaryKey();
|
|
353
378
|
// remove references of this entity in all managed entities, otherwise flushing could reinsert the entity
|
|
354
379
|
for (const { meta, prop } of wrapped.__meta.referencingProperties) {
|
|
355
380
|
for (const referrer of this.identityMap.getStore(meta).values()) {
|
|
356
|
-
const rel =
|
|
357
|
-
if (
|
|
381
|
+
const rel = Reference.unwrapReference(referrer[prop.name]);
|
|
382
|
+
if (Utils.isCollection(rel)) {
|
|
358
383
|
rel.removeWithoutPropagation(entity);
|
|
359
384
|
}
|
|
360
|
-
else if (rel && (prop.mapToPk ?
|
|
385
|
+
else if (rel && (prop.mapToPk ? helper(this.em.getReference(prop.type, rel)).getSerializedPrimaryKey() === serializedPK : rel === entity)) {
|
|
361
386
|
if (prop.formula) {
|
|
362
387
|
delete referrer[prop.name];
|
|
363
388
|
}
|
|
364
389
|
else {
|
|
365
|
-
delete
|
|
390
|
+
delete helper(referrer).__data[prop.name];
|
|
366
391
|
}
|
|
367
392
|
}
|
|
368
393
|
}
|
|
369
394
|
}
|
|
370
395
|
delete wrapped.__identifier;
|
|
371
396
|
delete wrapped.__originalEntityData;
|
|
372
|
-
wrapped.__touched = false;
|
|
373
397
|
wrapped.__managed = false;
|
|
374
398
|
}
|
|
375
399
|
computeChangeSets() {
|
|
376
400
|
this.changeSets.clear();
|
|
377
401
|
const visited = new Set();
|
|
378
402
|
for (const entity of this.removeStack) {
|
|
379
|
-
this.cascade(entity,
|
|
403
|
+
this.cascade(entity, Cascade.REMOVE, visited);
|
|
380
404
|
}
|
|
381
405
|
visited.clear();
|
|
382
|
-
for (const entity of this.persistStack) {
|
|
383
|
-
this.cascade(entity, enums_1.Cascade.PERSIST, visited, { checkRemoveStack: true });
|
|
384
|
-
}
|
|
385
406
|
for (const entity of this.identityMap) {
|
|
386
407
|
if (!this.removeStack.has(entity) && !this.persistStack.has(entity) && !this.orphanRemoveStack.has(entity)) {
|
|
387
|
-
this.cascade(entity,
|
|
408
|
+
this.cascade(entity, Cascade.PERSIST, visited, { checkRemoveStack: true });
|
|
388
409
|
}
|
|
389
410
|
}
|
|
411
|
+
for (const entity of this.persistStack) {
|
|
412
|
+
this.cascade(entity, Cascade.PERSIST, visited, { checkRemoveStack: true });
|
|
413
|
+
}
|
|
390
414
|
visited.clear();
|
|
391
415
|
for (const entity of this.persistStack) {
|
|
392
416
|
this.findNewEntities(entity, visited);
|
|
393
417
|
}
|
|
394
418
|
for (const entity of this.orphanRemoveStack) {
|
|
395
|
-
if (!
|
|
419
|
+
if (!helper(entity).__processing) {
|
|
396
420
|
this.removeStack.add(entity);
|
|
397
421
|
}
|
|
398
422
|
}
|
|
399
423
|
// Check insert stack if there are any entities matching something from delete stack. This can happen when recreating entities.
|
|
400
424
|
const inserts = {};
|
|
401
425
|
for (const cs of this.changeSets.values()) {
|
|
402
|
-
if (cs.type ===
|
|
426
|
+
if (cs.type === ChangeSetType.CREATE) {
|
|
403
427
|
inserts[cs.meta.className] ??= [];
|
|
404
428
|
inserts[cs.meta.className].push(cs);
|
|
405
429
|
}
|
|
406
430
|
}
|
|
407
431
|
for (const cs of this.changeSets.values()) {
|
|
408
|
-
if (cs.type ===
|
|
432
|
+
if (cs.type === ChangeSetType.UPDATE) {
|
|
409
433
|
this.findEarlyUpdates(cs, inserts[cs.meta.className]);
|
|
410
434
|
}
|
|
411
435
|
}
|
|
412
436
|
for (const entity of this.removeStack) {
|
|
413
|
-
const wrapped =
|
|
414
|
-
/*
|
|
437
|
+
const wrapped = helper(entity);
|
|
438
|
+
/* v8 ignore next */
|
|
415
439
|
if (wrapped.__processing) {
|
|
416
440
|
continue;
|
|
417
441
|
}
|
|
418
442
|
const deletePkHash = [wrapped.getSerializedPrimaryKey(), ...this.expandUniqueProps(entity)];
|
|
419
|
-
let type =
|
|
443
|
+
let type = ChangeSetType.DELETE;
|
|
420
444
|
for (const cs of inserts[wrapped.__meta.className] ?? []) {
|
|
421
445
|
if (deletePkHash.some(hash => hash === cs.getSerializedPrimaryKey() || this.expandUniqueProps(cs.entity).find(child => hash === child))) {
|
|
422
|
-
type =
|
|
446
|
+
type = ChangeSetType.DELETE_EARLY;
|
|
423
447
|
}
|
|
424
448
|
}
|
|
425
449
|
this.computeChangeSet(entity, type);
|
|
@@ -430,7 +454,7 @@ class UnitOfWork {
|
|
|
430
454
|
return;
|
|
431
455
|
}
|
|
432
456
|
let conflicts = false;
|
|
433
|
-
let type =
|
|
457
|
+
let type = ChangeSetType.UPDATE;
|
|
434
458
|
if (!props.some(prop => prop.name in changeSet.payload)) {
|
|
435
459
|
return;
|
|
436
460
|
}
|
|
@@ -439,7 +463,7 @@ class UnitOfWork {
|
|
|
439
463
|
if (prop.name in cs.payload && cs.rootName === changeSet.rootName && cs.type === changeSet.type) {
|
|
440
464
|
conflicts = true;
|
|
441
465
|
if (changeSet.payload[prop.name] == null) {
|
|
442
|
-
type =
|
|
466
|
+
type = ChangeSetType.UPDATE_EARLY;
|
|
443
467
|
}
|
|
444
468
|
}
|
|
445
469
|
}
|
|
@@ -455,15 +479,15 @@ class UnitOfWork {
|
|
|
455
479
|
}
|
|
456
480
|
scheduleOrphanRemoval(entity, visited) {
|
|
457
481
|
if (entity) {
|
|
458
|
-
|
|
482
|
+
helper(entity).__em = this.em;
|
|
459
483
|
this.orphanRemoveStack.add(entity);
|
|
460
484
|
this.queuedActions.add(entity.__meta.className);
|
|
461
|
-
this.cascade(entity,
|
|
485
|
+
this.cascade(entity, Cascade.SCHEDULE_ORPHAN_REMOVAL, visited);
|
|
462
486
|
}
|
|
463
487
|
}
|
|
464
488
|
cancelOrphanRemoval(entity, visited) {
|
|
465
489
|
this.orphanRemoveStack.delete(entity);
|
|
466
|
-
this.cascade(entity,
|
|
490
|
+
this.cascade(entity, Cascade.CANCEL_ORPHAN_REMOVAL, visited);
|
|
467
491
|
}
|
|
468
492
|
getOrphanRemoveStack() {
|
|
469
493
|
return this.orphanRemoveStack;
|
|
@@ -477,7 +501,7 @@ class UnitOfWork {
|
|
|
477
501
|
}
|
|
478
502
|
visited.add(entity);
|
|
479
503
|
processed.add(entity);
|
|
480
|
-
const wrapped =
|
|
504
|
+
const wrapped = helper(entity);
|
|
481
505
|
if (wrapped.__processing || this.removeStack.has(entity) || this.orphanRemoveStack.has(entity)) {
|
|
482
506
|
return;
|
|
483
507
|
}
|
|
@@ -485,9 +509,9 @@ class UnitOfWork {
|
|
|
485
509
|
wrapped.__schema ??= this.em.schema;
|
|
486
510
|
this.initIdentifier(entity);
|
|
487
511
|
for (const prop of wrapped.__meta.relations) {
|
|
488
|
-
const targets =
|
|
512
|
+
const targets = Utils.unwrapProperty(entity, wrapped.__meta, prop);
|
|
489
513
|
for (const [target] of targets) {
|
|
490
|
-
const kind =
|
|
514
|
+
const kind = Reference.unwrapReference(target);
|
|
491
515
|
this.processReference(entity, prop, kind, visited, processed, idx);
|
|
492
516
|
}
|
|
493
517
|
}
|
|
@@ -500,37 +524,37 @@ class UnitOfWork {
|
|
|
500
524
|
* Returns `true` when the change set should be skipped as it will be empty after the extra update.
|
|
501
525
|
*/
|
|
502
526
|
checkUniqueProps(changeSet) {
|
|
503
|
-
if (changeSet.type !==
|
|
527
|
+
if (changeSet.type !== ChangeSetType.UPDATE) {
|
|
504
528
|
return false;
|
|
505
529
|
}
|
|
506
530
|
// when changing a unique nullable property (or a 1:1 relation), we can't do it in a single
|
|
507
531
|
// query as it would cause unique constraint violations
|
|
508
532
|
const uniqueProps = changeSet.meta.uniqueProps.filter(prop => {
|
|
509
|
-
return (prop.nullable || changeSet.type !==
|
|
533
|
+
return (prop.nullable || changeSet.type !== ChangeSetType.CREATE);
|
|
510
534
|
});
|
|
511
535
|
this.scheduleExtraUpdate(changeSet, uniqueProps);
|
|
512
|
-
return changeSet.type ===
|
|
536
|
+
return changeSet.type === ChangeSetType.UPDATE && !Utils.hasObjectKeys(changeSet.payload);
|
|
513
537
|
}
|
|
514
538
|
expandUniqueProps(entity) {
|
|
515
|
-
const wrapped =
|
|
539
|
+
const wrapped = helper(entity);
|
|
516
540
|
if (!wrapped.__meta.hasUniqueProps) {
|
|
517
541
|
return [];
|
|
518
542
|
}
|
|
519
543
|
const simpleUniqueHashes = wrapped.__meta.uniqueProps.map(prop => {
|
|
520
544
|
if (entity[prop.name] != null) {
|
|
521
|
-
return prop.kind ===
|
|
545
|
+
return prop.kind === ReferenceKind.SCALAR || prop.mapToPk ? entity[prop.name] : helper(entity[prop.name]).getSerializedPrimaryKey();
|
|
522
546
|
}
|
|
523
547
|
if (wrapped.__originalEntityData?.[prop.name] != null) {
|
|
524
|
-
return
|
|
548
|
+
return Utils.getPrimaryKeyHash(Utils.asArray(wrapped.__originalEntityData[prop.name]));
|
|
525
549
|
}
|
|
526
550
|
return undefined;
|
|
527
551
|
}).filter(i => i);
|
|
528
552
|
const compoundUniqueHashes = wrapped.__meta.uniques.map(unique => {
|
|
529
|
-
const props =
|
|
553
|
+
const props = Utils.asArray(unique.properties);
|
|
530
554
|
if (props.every(prop => entity[prop] != null)) {
|
|
531
|
-
return
|
|
555
|
+
return Utils.getPrimaryKeyHash(props.map(p => {
|
|
532
556
|
const prop = wrapped.__meta.properties[p];
|
|
533
|
-
return prop.kind ===
|
|
557
|
+
return prop.kind === ReferenceKind.SCALAR || prop.mapToPk ? entity[prop.name] : helper(entity[prop.name]).getSerializedPrimaryKey();
|
|
534
558
|
}));
|
|
535
559
|
}
|
|
536
560
|
return undefined;
|
|
@@ -538,32 +562,41 @@ class UnitOfWork {
|
|
|
538
562
|
return simpleUniqueHashes.concat(compoundUniqueHashes);
|
|
539
563
|
}
|
|
540
564
|
initIdentifier(entity) {
|
|
541
|
-
const wrapped = entity &&
|
|
565
|
+
const wrapped = entity && helper(entity);
|
|
542
566
|
if (!wrapped || wrapped.__identifier || wrapped.hasPrimaryKey()) {
|
|
543
567
|
return;
|
|
544
568
|
}
|
|
545
|
-
const
|
|
546
|
-
|
|
547
|
-
|
|
569
|
+
const pks = wrapped.__meta.getPrimaryProps();
|
|
570
|
+
const idents = [];
|
|
571
|
+
for (const pk of pks) {
|
|
572
|
+
if (pk.kind === ReferenceKind.SCALAR) {
|
|
573
|
+
idents.push(new EntityIdentifier(entity[pk.name]));
|
|
574
|
+
}
|
|
575
|
+
else if (entity[pk.name]) {
|
|
576
|
+
this.initIdentifier(entity[pk.name]);
|
|
577
|
+
idents.push(helper(entity[pk.name])?.__identifier);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
if (pks.length === 1) {
|
|
581
|
+
wrapped.__identifier = idents[0];
|
|
548
582
|
}
|
|
549
|
-
else
|
|
550
|
-
|
|
551
|
-
wrapped.__identifier = (0, entity_1.helper)(entity[pk.name])?.__identifier;
|
|
583
|
+
else {
|
|
584
|
+
wrapped.__identifier = idents;
|
|
552
585
|
}
|
|
553
586
|
}
|
|
554
587
|
processReference(parent, prop, kind, visited, processed, idx) {
|
|
555
|
-
const isToOne = prop.kind ===
|
|
556
|
-
if (isToOne &&
|
|
588
|
+
const isToOne = prop.kind === ReferenceKind.MANY_TO_ONE || prop.kind === ReferenceKind.ONE_TO_ONE;
|
|
589
|
+
if (isToOne && Utils.isEntity(kind)) {
|
|
557
590
|
return this.processToOneReference(kind, visited, processed, idx);
|
|
558
591
|
}
|
|
559
|
-
if (
|
|
592
|
+
if (Utils.isCollection(kind)) {
|
|
560
593
|
kind.getItems(false)
|
|
561
594
|
.filter(item => !item.__helper.__originalEntityData)
|
|
562
595
|
.forEach(item => {
|
|
563
596
|
// propagate schema from parent
|
|
564
|
-
item.__helper.__schema ??=
|
|
597
|
+
item.__helper.__schema ??= helper(parent).__schema;
|
|
565
598
|
});
|
|
566
|
-
if (prop.kind ===
|
|
599
|
+
if (prop.kind === ReferenceKind.MANY_TO_MANY && kind.isDirty()) {
|
|
567
600
|
this.processToManyReference(kind, visited, processed, parent, prop);
|
|
568
601
|
}
|
|
569
602
|
}
|
|
@@ -575,8 +608,8 @@ class UnitOfWork {
|
|
|
575
608
|
}
|
|
576
609
|
processToManyReference(collection, visited, processed, parent, prop) {
|
|
577
610
|
if (this.isCollectionSelfReferenced(collection, processed)) {
|
|
578
|
-
this.extraUpdates.add([parent, prop.name, collection, undefined,
|
|
579
|
-
const coll = new
|
|
611
|
+
this.extraUpdates.add([parent, prop.name, collection, undefined, ChangeSetType.UPDATE]);
|
|
612
|
+
const coll = new Collection(parent);
|
|
580
613
|
coll.property = prop;
|
|
581
614
|
parent[prop.name] = coll;
|
|
582
615
|
return;
|
|
@@ -599,14 +632,21 @@ class UnitOfWork {
|
|
|
599
632
|
const current = this.comparator.prepareEntity(changeSet.entity);
|
|
600
633
|
const diff = this.comparator.diffEntities(changeSet.name, copy, current);
|
|
601
634
|
Object.assign(changeSet.payload, diff);
|
|
602
|
-
const wrapped =
|
|
603
|
-
if (wrapped.__identifier
|
|
604
|
-
|
|
635
|
+
const wrapped = helper(changeSet.entity);
|
|
636
|
+
if (wrapped.__identifier) {
|
|
637
|
+
const idents = Utils.asArray(wrapped.__identifier);
|
|
638
|
+
let i = 0;
|
|
639
|
+
for (const pk of wrapped.__meta.primaryKeys) {
|
|
640
|
+
if (diff[pk]) {
|
|
641
|
+
idents[i].setValue(diff[pk]);
|
|
642
|
+
}
|
|
643
|
+
i++;
|
|
644
|
+
}
|
|
605
645
|
}
|
|
606
646
|
}
|
|
607
647
|
postCommitCleanup() {
|
|
608
648
|
for (const cs of this.changeSets.values()) {
|
|
609
|
-
const wrapped =
|
|
649
|
+
const wrapped = helper(cs.entity);
|
|
610
650
|
wrapped.__processing = false;
|
|
611
651
|
delete wrapped.__pk;
|
|
612
652
|
}
|
|
@@ -625,23 +665,23 @@ class UnitOfWork {
|
|
|
625
665
|
}
|
|
626
666
|
visited.add(entity);
|
|
627
667
|
switch (type) {
|
|
628
|
-
case
|
|
668
|
+
case Cascade.PERSIST:
|
|
629
669
|
this.persist(entity, visited, options);
|
|
630
670
|
break;
|
|
631
|
-
case
|
|
671
|
+
case Cascade.MERGE:
|
|
632
672
|
this.merge(entity, visited);
|
|
633
673
|
break;
|
|
634
|
-
case
|
|
674
|
+
case Cascade.REMOVE:
|
|
635
675
|
this.remove(entity, visited, options);
|
|
636
676
|
break;
|
|
637
|
-
case
|
|
677
|
+
case Cascade.SCHEDULE_ORPHAN_REMOVAL:
|
|
638
678
|
this.scheduleOrphanRemoval(entity, visited);
|
|
639
679
|
break;
|
|
640
|
-
case
|
|
680
|
+
case Cascade.CANCEL_ORPHAN_REMOVAL:
|
|
641
681
|
this.cancelOrphanRemoval(entity, visited);
|
|
642
682
|
break;
|
|
643
683
|
}
|
|
644
|
-
for (const prop of
|
|
684
|
+
for (const prop of helper(entity).__meta.relations) {
|
|
645
685
|
this.cascadeReference(entity, prop, type, visited, options);
|
|
646
686
|
}
|
|
647
687
|
}
|
|
@@ -650,72 +690,72 @@ class UnitOfWork {
|
|
|
650
690
|
if (!this.shouldCascade(prop, type)) {
|
|
651
691
|
return;
|
|
652
692
|
}
|
|
653
|
-
const kind =
|
|
654
|
-
if ([
|
|
693
|
+
const kind = Reference.unwrapReference(entity[prop.name]);
|
|
694
|
+
if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && Utils.isEntity(kind)) {
|
|
655
695
|
return this.cascade(kind, type, visited, options);
|
|
656
696
|
}
|
|
657
697
|
const collection = kind;
|
|
658
|
-
if ([
|
|
698
|
+
if ([ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(prop.kind) && collection) {
|
|
659
699
|
for (const item of collection.getItems(false)) {
|
|
660
700
|
this.cascade(item, type, visited, options);
|
|
661
701
|
}
|
|
662
702
|
}
|
|
663
703
|
}
|
|
664
704
|
isCollectionSelfReferenced(collection, processed) {
|
|
665
|
-
const filtered = collection.getItems(false).filter(item => !
|
|
705
|
+
const filtered = collection.getItems(false).filter(item => !helper(item).__originalEntityData);
|
|
666
706
|
return filtered.some(items => processed.has(items));
|
|
667
707
|
}
|
|
668
708
|
shouldCascade(prop, type) {
|
|
669
|
-
if ([
|
|
709
|
+
if ([Cascade.REMOVE, Cascade.SCHEDULE_ORPHAN_REMOVAL, Cascade.CANCEL_ORPHAN_REMOVAL, Cascade.ALL].includes(type) && prop.orphanRemoval) {
|
|
670
710
|
return true;
|
|
671
711
|
}
|
|
672
712
|
// ignore user settings for merge, it is kept only for back compatibility, this should have never been configurable
|
|
673
|
-
if (type ===
|
|
713
|
+
if (type === Cascade.MERGE) {
|
|
674
714
|
return true;
|
|
675
715
|
}
|
|
676
|
-
return prop.cascade && (prop.cascade.includes(type) || prop.cascade.includes(
|
|
716
|
+
return prop.cascade && (prop.cascade.includes(type) || prop.cascade.includes(Cascade.ALL));
|
|
677
717
|
}
|
|
678
718
|
async lockPessimistic(entity, options) {
|
|
679
719
|
if (!this.em.isInTransaction()) {
|
|
680
|
-
throw
|
|
720
|
+
throw ValidationError.transactionRequired();
|
|
681
721
|
}
|
|
682
722
|
await this.em.getDriver().lockPessimistic(entity, { ctx: this.em.getTransactionContext(), ...options });
|
|
683
723
|
}
|
|
684
724
|
async lockOptimistic(entity, meta, version) {
|
|
685
725
|
if (!meta.versionProperty) {
|
|
686
|
-
throw
|
|
726
|
+
throw OptimisticLockError.notVersioned(meta);
|
|
687
727
|
}
|
|
688
|
-
if (
|
|
728
|
+
if (typeof version === 'undefined') {
|
|
689
729
|
return;
|
|
690
730
|
}
|
|
691
|
-
const wrapped =
|
|
731
|
+
const wrapped = helper(entity);
|
|
692
732
|
if (!wrapped.__initialized) {
|
|
693
733
|
await wrapped.init();
|
|
694
734
|
}
|
|
695
735
|
const previousVersion = entity[meta.versionProperty];
|
|
696
736
|
if (previousVersion !== version) {
|
|
697
|
-
throw
|
|
737
|
+
throw OptimisticLockError.lockFailedVersionMismatch(entity, version, previousVersion);
|
|
698
738
|
}
|
|
699
739
|
}
|
|
700
740
|
fixMissingReference(entity, prop) {
|
|
701
741
|
const reference = entity[prop.name];
|
|
702
|
-
const kind =
|
|
703
|
-
if ([
|
|
704
|
-
if (!
|
|
742
|
+
const kind = Reference.unwrapReference(reference);
|
|
743
|
+
if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && kind && !prop.mapToPk) {
|
|
744
|
+
if (!Utils.isEntity(kind)) {
|
|
705
745
|
entity[prop.name] = this.em.getReference(prop.type, kind, { wrapped: !!prop.ref });
|
|
706
746
|
}
|
|
707
|
-
else if (!
|
|
708
|
-
const pk =
|
|
747
|
+
else if (!helper(kind).__initialized && !helper(kind).__em) {
|
|
748
|
+
const pk = helper(kind).getPrimaryKey();
|
|
709
749
|
entity[prop.name] = this.em.getReference(prop.type, pk, { wrapped: !!prop.ref });
|
|
710
750
|
}
|
|
711
751
|
}
|
|
712
752
|
// perf: set the `Collection._property` to skip the getter, as it can be slow when there is a lot of relations
|
|
713
|
-
if (
|
|
753
|
+
if (Utils.isCollection(kind)) {
|
|
714
754
|
kind.property = prop;
|
|
715
755
|
}
|
|
716
|
-
const isCollection = [
|
|
756
|
+
const isCollection = [ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(prop.kind);
|
|
717
757
|
if (isCollection && Array.isArray(kind)) {
|
|
718
|
-
const collection = new
|
|
758
|
+
const collection = new Collection(entity);
|
|
719
759
|
collection.property = prop;
|
|
720
760
|
entity[prop.name] = collection;
|
|
721
761
|
collection.set(kind);
|
|
@@ -729,29 +769,29 @@ class UnitOfWork {
|
|
|
729
769
|
const commitOrderReversed = [...commitOrder].reverse();
|
|
730
770
|
// early delete - when we recreate entity in the same UoW, we need to issue those delete queries before inserts
|
|
731
771
|
for (const name of commitOrderReversed) {
|
|
732
|
-
await this.commitDeleteChangeSets(groups[
|
|
772
|
+
await this.commitDeleteChangeSets(groups[ChangeSetType.DELETE_EARLY].get(name) ?? [], ctx);
|
|
733
773
|
}
|
|
734
774
|
// early update - when we recreate entity in the same UoW, we need to issue those delete queries before inserts
|
|
735
775
|
for (const name of commitOrder) {
|
|
736
|
-
await this.commitUpdateChangeSets(groups[
|
|
776
|
+
await this.commitUpdateChangeSets(groups[ChangeSetType.UPDATE_EARLY].get(name) ?? [], ctx);
|
|
737
777
|
}
|
|
738
778
|
// extra updates
|
|
739
|
-
await this.commitExtraUpdates(
|
|
779
|
+
await this.commitExtraUpdates(ChangeSetType.UPDATE_EARLY, ctx);
|
|
740
780
|
// create
|
|
741
781
|
for (const name of commitOrder) {
|
|
742
|
-
await this.commitCreateChangeSets(groups[
|
|
782
|
+
await this.commitCreateChangeSets(groups[ChangeSetType.CREATE].get(name) ?? [], ctx);
|
|
743
783
|
}
|
|
744
784
|
// update
|
|
745
785
|
for (const name of commitOrder) {
|
|
746
|
-
await this.commitUpdateChangeSets(groups[
|
|
786
|
+
await this.commitUpdateChangeSets(groups[ChangeSetType.UPDATE].get(name) ?? [], ctx);
|
|
747
787
|
}
|
|
748
788
|
// extra updates
|
|
749
|
-
await this.commitExtraUpdates(
|
|
789
|
+
await this.commitExtraUpdates(ChangeSetType.UPDATE, ctx);
|
|
750
790
|
// collection updates
|
|
751
791
|
await this.commitCollectionUpdates(ctx);
|
|
752
792
|
// delete - entity deletions need to be in reverse commit order
|
|
753
793
|
for (const name of commitOrderReversed) {
|
|
754
|
-
await this.commitDeleteChangeSets(groups[
|
|
794
|
+
await this.commitDeleteChangeSets(groups[ChangeSetType.DELETE].get(name) ?? [], ctx);
|
|
755
795
|
}
|
|
756
796
|
// take snapshots of all persisted collections
|
|
757
797
|
const visited = new Set();
|
|
@@ -764,30 +804,30 @@ class UnitOfWork {
|
|
|
764
804
|
return;
|
|
765
805
|
}
|
|
766
806
|
const props = changeSets[0].meta.root.relations.filter(prop => {
|
|
767
|
-
return (prop.kind ===
|
|
768
|
-
|| prop.kind ===
|
|
769
|
-
|| (prop.kind ===
|
|
807
|
+
return (prop.kind === ReferenceKind.ONE_TO_ONE && prop.owner)
|
|
808
|
+
|| prop.kind === ReferenceKind.MANY_TO_ONE
|
|
809
|
+
|| (prop.kind === ReferenceKind.MANY_TO_MANY && prop.owner && !this.platform.usesPivotTable());
|
|
770
810
|
});
|
|
771
811
|
for (const changeSet of changeSets) {
|
|
772
812
|
this.findExtraUpdates(changeSet, props);
|
|
773
|
-
await this.runHooks(
|
|
813
|
+
await this.runHooks(EventType.beforeCreate, changeSet, true);
|
|
774
814
|
}
|
|
775
815
|
await this.changeSetPersister.executeInserts(changeSets, { ctx });
|
|
776
816
|
for (const changeSet of changeSets) {
|
|
777
817
|
this.register(changeSet.entity, changeSet.payload, { refresh: true });
|
|
778
|
-
await this.runHooks(
|
|
818
|
+
await this.runHooks(EventType.afterCreate, changeSet);
|
|
779
819
|
}
|
|
780
820
|
}
|
|
781
821
|
findExtraUpdates(changeSet, props) {
|
|
782
822
|
for (const prop of props) {
|
|
783
823
|
const ref = changeSet.entity[prop.name];
|
|
784
|
-
if (!ref || prop.deferMode ===
|
|
824
|
+
if (!ref || prop.deferMode === DeferMode.INITIALLY_DEFERRED) {
|
|
785
825
|
continue;
|
|
786
826
|
}
|
|
787
|
-
if (
|
|
827
|
+
if (Utils.isCollection(ref)) {
|
|
788
828
|
ref.getItems(false).some(item => {
|
|
789
|
-
const cs = this.changeSets.get(
|
|
790
|
-
const isScheduledForInsert = cs && cs.type ===
|
|
829
|
+
const cs = this.changeSets.get(Reference.unwrapReference(item));
|
|
830
|
+
const isScheduledForInsert = cs && cs.type === ChangeSetType.CREATE && !cs.persisted;
|
|
791
831
|
if (isScheduledForInsert) {
|
|
792
832
|
this.scheduleExtraUpdate(changeSet, [prop]);
|
|
793
833
|
return true;
|
|
@@ -795,8 +835,8 @@ class UnitOfWork {
|
|
|
795
835
|
return false;
|
|
796
836
|
});
|
|
797
837
|
}
|
|
798
|
-
const cs = this.changeSets.get(
|
|
799
|
-
const isScheduledForInsert = cs && cs.type ===
|
|
838
|
+
const cs = this.changeSets.get(Reference.unwrapReference(ref));
|
|
839
|
+
const isScheduledForInsert = cs && cs.type === ChangeSetType.CREATE && !cs.persisted;
|
|
800
840
|
if (isScheduledForInsert) {
|
|
801
841
|
this.scheduleExtraUpdate(changeSet, [prop]);
|
|
802
842
|
}
|
|
@@ -805,14 +845,14 @@ class UnitOfWork {
|
|
|
805
845
|
findEarlyUpdates(changeSet, inserts = []) {
|
|
806
846
|
const props = changeSet.meta.uniqueProps;
|
|
807
847
|
for (const prop of props) {
|
|
808
|
-
const insert = inserts.find(c =>
|
|
848
|
+
const insert = inserts.find(c => Utils.equals(c.payload[prop.name], changeSet.originalEntity[prop.name]));
|
|
809
849
|
const propEmpty = changeSet.payload[prop.name] === null || changeSet.payload[prop.name] === undefined;
|
|
810
850
|
if (prop.name in changeSet.payload &&
|
|
811
851
|
insert &&
|
|
812
852
|
// We only want to update early if the unique property on the changeset is going to be empty, so that
|
|
813
853
|
// the previous unique value can be set on a different entity without constraint issues
|
|
814
854
|
propEmpty) {
|
|
815
|
-
changeSet.type =
|
|
855
|
+
changeSet.type = ChangeSetType.UPDATE_EARLY;
|
|
816
856
|
}
|
|
817
857
|
}
|
|
818
858
|
}
|
|
@@ -821,14 +861,21 @@ class UnitOfWork {
|
|
|
821
861
|
return;
|
|
822
862
|
}
|
|
823
863
|
for (const changeSet of changeSets) {
|
|
824
|
-
await this.runHooks(
|
|
864
|
+
await this.runHooks(EventType.beforeUpdate, changeSet, true);
|
|
825
865
|
}
|
|
826
866
|
await this.changeSetPersister.executeUpdates(changeSets, batched, { ctx });
|
|
827
867
|
for (const changeSet of changeSets) {
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
868
|
+
const wrapped = helper(changeSet.entity);
|
|
869
|
+
wrapped.__originalEntityData = this.comparator.prepareEntity(changeSet.entity);
|
|
870
|
+
if (!wrapped.__initialized) {
|
|
871
|
+
for (const prop of changeSet.meta.relations) {
|
|
872
|
+
if ([ReferenceKind.MANY_TO_MANY, ReferenceKind.ONE_TO_MANY].includes(prop.kind) && changeSet.entity[prop.name] == null) {
|
|
873
|
+
changeSet.entity[prop.name] = Collection.create(changeSet.entity, prop.name, undefined, wrapped.isInitialized());
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
wrapped.__initialized = true;
|
|
877
|
+
}
|
|
878
|
+
await this.runHooks(EventType.afterUpdate, changeSet);
|
|
832
879
|
}
|
|
833
880
|
}
|
|
834
881
|
async commitDeleteChangeSets(changeSets, ctx) {
|
|
@@ -836,12 +883,12 @@ class UnitOfWork {
|
|
|
836
883
|
return;
|
|
837
884
|
}
|
|
838
885
|
for (const changeSet of changeSets) {
|
|
839
|
-
await this.runHooks(
|
|
886
|
+
await this.runHooks(EventType.beforeDelete, changeSet, true);
|
|
840
887
|
}
|
|
841
888
|
await this.changeSetPersister.executeDeletes(changeSets, { ctx });
|
|
842
889
|
for (const changeSet of changeSets) {
|
|
843
890
|
this.unsetIdentity(changeSet.entity);
|
|
844
|
-
await this.runHooks(
|
|
891
|
+
await this.runHooks(EventType.afterDelete, changeSet);
|
|
845
892
|
}
|
|
846
893
|
}
|
|
847
894
|
async commitExtraUpdates(type, ctx) {
|
|
@@ -870,23 +917,34 @@ class UnitOfWork {
|
|
|
870
917
|
}
|
|
871
918
|
}
|
|
872
919
|
async commitCollectionUpdates(ctx) {
|
|
873
|
-
|
|
920
|
+
this.filterCollectionUpdates();
|
|
921
|
+
const loggerContext = Utils.merge({ id: this.em._id }, this.em.getLoggerContext({ disableContextResolution: true }));
|
|
922
|
+
await this.em.getDriver().syncCollections(this.collectionUpdates, {
|
|
923
|
+
ctx,
|
|
924
|
+
schema: this.em.schema,
|
|
925
|
+
loggerContext,
|
|
926
|
+
});
|
|
874
927
|
for (const coll of this.collectionUpdates) {
|
|
928
|
+
coll.takeSnapshot();
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
filterCollectionUpdates() {
|
|
932
|
+
for (const coll of this.collectionUpdates) {
|
|
933
|
+
let skip = true;
|
|
875
934
|
if (coll.property.owner || coll.getItems(false).filter(item => !item.__helper.__initialized).length > 0) {
|
|
876
935
|
if (this.platform.usesPivotTable()) {
|
|
877
|
-
|
|
936
|
+
skip = false;
|
|
878
937
|
}
|
|
879
938
|
}
|
|
880
|
-
else if (coll.property.kind ===
|
|
881
|
-
|
|
939
|
+
else if (coll.property.kind === ReferenceKind.ONE_TO_MANY && coll.getSnapshot() === undefined) {
|
|
940
|
+
skip = false;
|
|
882
941
|
}
|
|
883
|
-
else if (coll.property.kind ===
|
|
884
|
-
|
|
942
|
+
else if (coll.property.kind === ReferenceKind.MANY_TO_MANY && !coll.property.owner) {
|
|
943
|
+
skip = false;
|
|
944
|
+
}
|
|
945
|
+
if (skip) {
|
|
946
|
+
this.collectionUpdates.delete(coll);
|
|
885
947
|
}
|
|
886
|
-
}
|
|
887
|
-
await this.em.getDriver().syncCollections(collectionUpdates, { ctx });
|
|
888
|
-
for (const coll of this.collectionUpdates) {
|
|
889
|
-
coll.takeSnapshot();
|
|
890
948
|
}
|
|
891
949
|
}
|
|
892
950
|
/**
|
|
@@ -894,11 +952,11 @@ class UnitOfWork {
|
|
|
894
952
|
*/
|
|
895
953
|
getChangeSetGroups() {
|
|
896
954
|
const groups = {
|
|
897
|
-
[
|
|
898
|
-
[
|
|
899
|
-
[
|
|
900
|
-
[
|
|
901
|
-
[
|
|
955
|
+
[ChangeSetType.CREATE]: new Map(),
|
|
956
|
+
[ChangeSetType.UPDATE]: new Map(),
|
|
957
|
+
[ChangeSetType.DELETE]: new Map(),
|
|
958
|
+
[ChangeSetType.UPDATE_EARLY]: new Map(),
|
|
959
|
+
[ChangeSetType.DELETE_EARLY]: new Map(),
|
|
902
960
|
};
|
|
903
961
|
for (const cs of this.changeSets.values()) {
|
|
904
962
|
const group = groups[cs.type];
|
|
@@ -911,7 +969,7 @@ class UnitOfWork {
|
|
|
911
969
|
return groups;
|
|
912
970
|
}
|
|
913
971
|
getCommitOrder() {
|
|
914
|
-
const calc = new
|
|
972
|
+
const calc = new CommitOrderCalculator();
|
|
915
973
|
const set = new Set();
|
|
916
974
|
this.changeSets.forEach(cs => set.add(cs.rootName));
|
|
917
975
|
set.forEach(entityName => calc.addNode(entityName));
|
|
@@ -938,16 +996,15 @@ class UnitOfWork {
|
|
|
938
996
|
return;
|
|
939
997
|
}
|
|
940
998
|
visited.add(entity);
|
|
941
|
-
|
|
999
|
+
helper(entity)?.__meta.relations.forEach(prop => {
|
|
942
1000
|
const value = entity[prop.name];
|
|
943
|
-
if (
|
|
1001
|
+
if (Utils.isCollection(value)) {
|
|
944
1002
|
value.takeSnapshot();
|
|
945
1003
|
}
|
|
946
1004
|
// cascade to m:1 relations as we need to snapshot the 1:m inverse side (for `removeAll()` with orphan removal)
|
|
947
|
-
if (prop.kind ===
|
|
948
|
-
this.takeCollectionSnapshots(
|
|
1005
|
+
if (prop.kind === ReferenceKind.MANY_TO_ONE && value) {
|
|
1006
|
+
this.takeCollectionSnapshots(Reference.unwrapReference(value), visited);
|
|
949
1007
|
}
|
|
950
1008
|
});
|
|
951
1009
|
}
|
|
952
1010
|
}
|
|
953
|
-
exports.UnitOfWork = UnitOfWork;
|