@mikro-orm/core 7.0.0-dev.33 → 7.0.0-dev.331
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 +70 -75
- package/EntityManager.js +487 -402
- package/MikroORM.d.ts +45 -38
- package/MikroORM.js +123 -156
- package/README.md +7 -4
- package/cache/FileCacheAdapter.d.ts +2 -7
- package/cache/FileCacheAdapter.js +35 -30
- package/cache/GeneratedCacheAdapter.d.ts +1 -2
- package/cache/GeneratedCacheAdapter.js +6 -8
- package/cache/MemoryCacheAdapter.d.ts +1 -2
- package/cache/MemoryCacheAdapter.js +8 -8
- package/cache/index.d.ts +1 -2
- package/cache/index.js +0 -2
- package/connections/Connection.d.ts +12 -5
- package/connections/Connection.js +37 -15
- package/drivers/DatabaseDriver.d.ts +25 -18
- package/drivers/DatabaseDriver.js +144 -45
- package/drivers/IDatabaseDriver.d.ts +118 -23
- package/entity/BaseEntity.d.ts +63 -4
- package/entity/BaseEntity.js +0 -3
- package/entity/Collection.d.ts +95 -31
- package/entity/Collection.js +487 -139
- package/entity/EntityAssigner.js +37 -25
- package/entity/EntityFactory.d.ts +8 -9
- package/entity/EntityFactory.js +152 -100
- package/entity/EntityHelper.d.ts +2 -2
- package/entity/EntityHelper.js +69 -27
- package/entity/EntityLoader.d.ts +12 -13
- package/entity/EntityLoader.js +286 -125
- package/entity/EntityRepository.d.ts +28 -8
- package/entity/EntityRepository.js +8 -2
- package/entity/PolymorphicRef.d.ts +12 -0
- package/entity/PolymorphicRef.js +18 -0
- package/entity/Reference.d.ts +3 -8
- package/entity/Reference.js +62 -29
- package/entity/WrappedEntity.d.ts +7 -10
- package/entity/WrappedEntity.js +6 -7
- package/entity/defineEntity.d.ts +472 -313
- package/entity/defineEntity.js +134 -290
- package/entity/index.d.ts +2 -2
- package/entity/index.js +2 -2
- package/entity/utils.d.ts +6 -1
- package/entity/utils.js +46 -11
- package/entity/validators.d.ts +11 -0
- package/entity/validators.js +66 -0
- package/enums.d.ts +8 -6
- package/enums.js +13 -17
- package/errors.d.ts +26 -16
- package/errors.js +63 -31
- package/events/EventManager.d.ts +3 -5
- package/events/EventManager.js +37 -26
- package/events/index.d.ts +1 -1
- package/events/index.js +0 -1
- package/exceptions.js +9 -2
- package/hydration/Hydrator.js +1 -2
- package/hydration/ObjectHydrator.d.ts +5 -6
- package/hydration/ObjectHydrator.js +109 -50
- package/index.d.ts +2 -2
- package/index.js +1 -2
- package/logging/DefaultLogger.d.ts +1 -1
- package/logging/DefaultLogger.js +3 -4
- package/logging/SimpleLogger.d.ts +1 -1
- package/logging/colors.d.ts +1 -1
- package/logging/colors.js +4 -6
- package/logging/index.d.ts +2 -1
- package/logging/index.js +1 -1
- package/logging/inspect.d.ts +2 -0
- package/logging/inspect.js +11 -0
- package/metadata/EntitySchema.d.ts +47 -23
- package/metadata/EntitySchema.js +103 -34
- package/metadata/MetadataDiscovery.d.ts +65 -18
- package/metadata/MetadataDiscovery.js +940 -424
- package/metadata/MetadataProvider.d.ts +11 -2
- package/metadata/MetadataProvider.js +71 -2
- package/metadata/MetadataStorage.d.ts +11 -13
- package/metadata/MetadataStorage.js +79 -48
- package/metadata/MetadataValidator.d.ts +32 -9
- package/metadata/MetadataValidator.js +214 -44
- 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 +0 -1
- package/metadata/types.d.ts +577 -0
- package/metadata/types.js +1 -0
- package/naming-strategy/AbstractNamingStrategy.d.ts +16 -4
- package/naming-strategy/AbstractNamingStrategy.js +26 -5
- package/naming-strategy/EntityCaseNamingStrategy.d.ts +3 -3
- package/naming-strategy/EntityCaseNamingStrategy.js +7 -6
- package/naming-strategy/MongoNamingStrategy.d.ts +3 -3
- package/naming-strategy/MongoNamingStrategy.js +6 -6
- package/naming-strategy/NamingStrategy.d.ts +28 -4
- package/naming-strategy/UnderscoreNamingStrategy.d.ts +3 -3
- package/naming-strategy/UnderscoreNamingStrategy.js +6 -6
- package/naming-strategy/index.d.ts +1 -1
- package/naming-strategy/index.js +0 -1
- package/not-supported.d.ts +2 -0
- package/not-supported.js +8 -0
- package/package.json +47 -36
- package/platforms/ExceptionConverter.js +1 -1
- package/platforms/Platform.d.ts +33 -15
- package/platforms/Platform.js +125 -69
- package/serialization/EntitySerializer.d.ts +6 -3
- package/serialization/EntitySerializer.js +54 -30
- package/serialization/EntityTransformer.js +37 -22
- package/serialization/SerializationContext.d.ts +10 -14
- package/serialization/SerializationContext.js +24 -19
- package/types/ArrayType.d.ts +1 -1
- package/types/ArrayType.js +2 -3
- package/types/BigIntType.js +1 -1
- package/types/BlobType.d.ts +0 -1
- package/types/BlobType.js +0 -3
- package/types/BooleanType.d.ts +1 -0
- package/types/BooleanType.js +3 -0
- package/types/DecimalType.js +2 -2
- package/types/DoubleType.js +1 -1
- package/types/EnumArrayType.js +1 -2
- package/types/JsonType.d.ts +1 -1
- package/types/JsonType.js +7 -2
- package/types/TinyIntType.js +1 -1
- package/types/Type.d.ts +2 -4
- package/types/Type.js +3 -3
- package/types/Uint8ArrayType.d.ts +0 -1
- package/types/Uint8ArrayType.js +1 -4
- package/types/UuidType.d.ts +2 -0
- package/types/UuidType.js +14 -2
- package/types/index.d.ts +3 -2
- package/typings.d.ts +427 -170
- package/typings.js +100 -45
- package/unit-of-work/ChangeSet.d.ts +4 -6
- package/unit-of-work/ChangeSet.js +8 -9
- package/unit-of-work/ChangeSetComputer.d.ts +2 -12
- package/unit-of-work/ChangeSetComputer.js +61 -38
- package/unit-of-work/ChangeSetPersister.d.ts +10 -17
- package/unit-of-work/ChangeSetPersister.js +136 -73
- package/unit-of-work/CommitOrderCalculator.d.ts +13 -14
- package/unit-of-work/CommitOrderCalculator.js +22 -20
- package/unit-of-work/IdentityMap.d.ts +12 -3
- package/unit-of-work/IdentityMap.js +51 -13
- package/unit-of-work/UnitOfWork.d.ts +39 -23
- package/unit-of-work/UnitOfWork.js +441 -246
- package/utils/AbstractMigrator.d.ts +101 -0
- package/utils/AbstractMigrator.js +303 -0
- package/utils/AbstractSchemaGenerator.d.ts +5 -5
- package/utils/AbstractSchemaGenerator.js +30 -18
- package/utils/AsyncContext.d.ts +6 -0
- package/utils/AsyncContext.js +42 -0
- package/utils/Configuration.d.ts +647 -185
- package/utils/Configuration.js +215 -252
- package/utils/ConfigurationLoader.d.ts +1 -52
- package/utils/ConfigurationLoader.js +1 -330
- package/utils/Cursor.d.ts +3 -6
- package/utils/Cursor.js +32 -17
- package/utils/DataloaderUtils.d.ts +10 -5
- package/utils/DataloaderUtils.js +42 -22
- package/utils/EntityComparator.d.ts +21 -21
- package/utils/EntityComparator.js +224 -118
- package/utils/QueryHelper.d.ts +34 -7
- package/utils/QueryHelper.js +183 -72
- package/utils/RawQueryFragment.d.ts +28 -34
- package/utils/RawQueryFragment.js +37 -72
- package/utils/RequestContext.js +2 -2
- package/utils/TransactionContext.js +2 -2
- package/utils/TransactionManager.js +11 -8
- package/utils/Utils.d.ts +16 -127
- package/utils/Utils.js +104 -402
- package/utils/clone.js +13 -23
- package/utils/env-vars.d.ts +7 -0
- package/utils/env-vars.js +98 -0
- package/utils/fs-utils.d.ts +20 -0
- package/utils/fs-utils.js +193 -0
- package/utils/index.d.ts +1 -3
- package/utils/index.js +1 -3
- package/utils/upsert-utils.d.ts +9 -4
- package/utils/upsert-utils.js +51 -5
- package/decorators/Check.d.ts +0 -3
- package/decorators/Check.js +0 -13
- package/decorators/CreateRequestContext.d.ts +0 -3
- package/decorators/CreateRequestContext.js +0 -32
- package/decorators/Embeddable.d.ts +0 -8
- package/decorators/Embeddable.js +0 -11
- package/decorators/Embedded.d.ts +0 -12
- package/decorators/Embedded.js +0 -18
- package/decorators/Entity.d.ts +0 -33
- package/decorators/Entity.js +0 -12
- package/decorators/Enum.d.ts +0 -9
- package/decorators/Enum.js +0 -16
- package/decorators/Filter.d.ts +0 -2
- package/decorators/Filter.js +0 -8
- package/decorators/Formula.d.ts +0 -4
- package/decorators/Formula.js +0 -15
- package/decorators/Indexed.d.ts +0 -19
- package/decorators/Indexed.js +0 -20
- package/decorators/ManyToMany.d.ts +0 -42
- package/decorators/ManyToMany.js +0 -14
- package/decorators/ManyToOne.d.ts +0 -34
- package/decorators/ManyToOne.js +0 -14
- package/decorators/OneToMany.d.ts +0 -28
- package/decorators/OneToMany.js +0 -17
- package/decorators/OneToOne.d.ts +0 -28
- package/decorators/OneToOne.js +0 -7
- package/decorators/PrimaryKey.d.ts +0 -8
- package/decorators/PrimaryKey.js +0 -20
- package/decorators/Property.d.ts +0 -250
- package/decorators/Property.js +0 -32
- package/decorators/Transactional.d.ts +0 -14
- package/decorators/Transactional.js +0 -28
- package/decorators/hooks.d.ts +0 -16
- package/decorators/hooks.js +0 -47
- package/decorators/index.d.ts +0 -17
- package/decorators/index.js +0 -17
- package/entity/ArrayCollection.d.ts +0 -118
- package/entity/ArrayCollection.js +0 -407
- package/entity/EntityValidator.d.ts +0 -19
- package/entity/EntityValidator.js +0 -150
- package/metadata/ReflectMetadataProvider.d.ts +0 -8
- package/metadata/ReflectMetadataProvider.js +0 -44
- package/utils/resolveContextProvider.d.ts +0 -10
- package/utils/resolveContextProvider.js +0 -28
|
@@ -1,40 +1,39 @@
|
|
|
1
1
|
import { EntityIdentifier } from '../entity/EntityIdentifier.js';
|
|
2
|
+
import { PolymorphicRef } from '../entity/PolymorphicRef.js';
|
|
2
3
|
import { helper } from '../entity/wrap.js';
|
|
3
4
|
import { ChangeSetType } from './ChangeSet.js';
|
|
4
5
|
import { isRaw } from '../utils/RawQueryFragment.js';
|
|
5
6
|
import { Utils } from '../utils/Utils.js';
|
|
6
|
-
import { OptimisticLockError } from '../errors.js';
|
|
7
|
+
import { OptimisticLockError, ValidationError } from '../errors.js';
|
|
7
8
|
import { ReferenceKind } from '../enums.js';
|
|
8
9
|
export class ChangeSetPersister {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
this
|
|
21
|
-
this
|
|
22
|
-
this
|
|
23
|
-
this
|
|
24
|
-
this
|
|
25
|
-
this
|
|
26
|
-
this
|
|
27
|
-
this
|
|
28
|
-
this.comparator = this.config.getComparator(this.metadata);
|
|
29
|
-
this.usesReturningStatement = this.platform.usesReturningStatement() || this.platform.usesOutputStatement();
|
|
10
|
+
#platform;
|
|
11
|
+
#comparator;
|
|
12
|
+
#usesReturningStatement;
|
|
13
|
+
#driver;
|
|
14
|
+
#metadata;
|
|
15
|
+
#hydrator;
|
|
16
|
+
#factory;
|
|
17
|
+
#config;
|
|
18
|
+
#em;
|
|
19
|
+
constructor(em) {
|
|
20
|
+
this.#em = em;
|
|
21
|
+
this.#driver = this.#em.getDriver();
|
|
22
|
+
this.#config = this.#em.config;
|
|
23
|
+
this.#metadata = this.#em.getMetadata();
|
|
24
|
+
this.#factory = this.#em.getEntityFactory();
|
|
25
|
+
this.#platform = this.#driver.getPlatform();
|
|
26
|
+
this.#hydrator = this.#config.getHydrator(this.#metadata);
|
|
27
|
+
this.#comparator = this.#config.getComparator(this.#metadata);
|
|
28
|
+
this.#usesReturningStatement = this.#platform.usesReturningStatement() || this.#platform.usesOutputStatement();
|
|
30
29
|
}
|
|
31
30
|
async executeInserts(changeSets, options, withSchema) {
|
|
32
31
|
if (!withSchema) {
|
|
33
32
|
return this.runForEachSchema(changeSets, 'executeInserts', options);
|
|
34
33
|
}
|
|
35
|
-
const meta =
|
|
34
|
+
const meta = changeSets[0].meta;
|
|
36
35
|
changeSets.forEach(changeSet => this.processProperties(changeSet));
|
|
37
|
-
if (changeSets.length > 1 && this
|
|
36
|
+
if (changeSets.length > 1 && this.#config.get('useBatchInserts', this.#platform.usesBatchInserts())) {
|
|
38
37
|
return this.persistNewEntities(meta, changeSets, options);
|
|
39
38
|
}
|
|
40
39
|
for (const changeSet of changeSets) {
|
|
@@ -45,9 +44,15 @@ export class ChangeSetPersister {
|
|
|
45
44
|
if (!withSchema) {
|
|
46
45
|
return this.runForEachSchema(changeSets, 'executeUpdates', options, batched);
|
|
47
46
|
}
|
|
48
|
-
const meta =
|
|
47
|
+
const meta = changeSets[0].meta;
|
|
49
48
|
changeSets.forEach(changeSet => this.processProperties(changeSet));
|
|
50
|
-
|
|
49
|
+
// For STI with conflicting fieldNames (renamedFrom properties), we can't batch mixed child types
|
|
50
|
+
const hasSTIConflicts = meta.root.props.some(p => p.renamedFrom);
|
|
51
|
+
const hasMixedTypes = hasSTIConflicts && changeSets.some(cs => cs.meta.class !== meta.class);
|
|
52
|
+
if (batched &&
|
|
53
|
+
changeSets.length > 1 &&
|
|
54
|
+
!hasMixedTypes &&
|
|
55
|
+
this.#config.get('useBatchUpdates', this.#platform.usesBatchUpdates())) {
|
|
51
56
|
return this.persistManagedEntities(meta, changeSets, options);
|
|
52
57
|
}
|
|
53
58
|
for (const changeSet of changeSets) {
|
|
@@ -58,14 +63,14 @@ export class ChangeSetPersister {
|
|
|
58
63
|
if (!withSchema) {
|
|
59
64
|
return this.runForEachSchema(changeSets, 'executeDeletes', options);
|
|
60
65
|
}
|
|
61
|
-
const size = this
|
|
66
|
+
const size = this.#config.get('batchSize');
|
|
62
67
|
const meta = changeSets[0].meta;
|
|
63
68
|
const pk = Utils.getPrimaryKeyHash(meta.primaryKeys);
|
|
64
69
|
for (let i = 0; i < changeSets.length; i += size) {
|
|
65
70
|
const chunk = changeSets.slice(i, i + size);
|
|
66
71
|
const pks = chunk.map(cs => cs.getPrimaryKey());
|
|
67
72
|
options = this.prepareOptions(meta, options);
|
|
68
|
-
await this
|
|
73
|
+
await this.#driver.nativeDelete(meta.root.class, { [pk]: { $in: pks } }, options);
|
|
69
74
|
}
|
|
70
75
|
}
|
|
71
76
|
async runForEachSchema(changeSets, method, options, ...args) {
|
|
@@ -81,13 +86,32 @@ export class ChangeSetPersister {
|
|
|
81
86
|
await this[method](group, ...args, options, true);
|
|
82
87
|
}
|
|
83
88
|
}
|
|
89
|
+
validateRequired(entity) {
|
|
90
|
+
const wrapped = helper(entity);
|
|
91
|
+
for (const prop of wrapped.__meta.props) {
|
|
92
|
+
if (!prop.nullable &&
|
|
93
|
+
!prop.autoincrement &&
|
|
94
|
+
!prop.default &&
|
|
95
|
+
!prop.defaultRaw &&
|
|
96
|
+
!prop.onCreate &&
|
|
97
|
+
!prop.generated &&
|
|
98
|
+
!prop.embedded &&
|
|
99
|
+
![ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(prop.kind) &&
|
|
100
|
+
prop.name !== wrapped.__meta.root.discriminatorColumn &&
|
|
101
|
+
prop.type !== 'ObjectId' &&
|
|
102
|
+
prop.persist !== false &&
|
|
103
|
+
entity[prop.name] == null) {
|
|
104
|
+
throw ValidationError.propertyRequired(entity, prop);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
84
108
|
processProperties(changeSet) {
|
|
85
|
-
const meta =
|
|
109
|
+
const meta = changeSet.meta;
|
|
86
110
|
for (const prop of meta.relations) {
|
|
87
111
|
this.processProperty(changeSet, prop);
|
|
88
112
|
}
|
|
89
|
-
if (changeSet.type === ChangeSetType.CREATE && this
|
|
90
|
-
this.
|
|
113
|
+
if (changeSet.type === ChangeSetType.CREATE && this.#config.get('validateRequired')) {
|
|
114
|
+
this.validateRequired(changeSet.entity);
|
|
91
115
|
}
|
|
92
116
|
}
|
|
93
117
|
async persistNewEntity(meta, changeSet, options) {
|
|
@@ -95,31 +119,33 @@ export class ChangeSetPersister {
|
|
|
95
119
|
options = this.prepareOptions(meta, options, {
|
|
96
120
|
convertCustomTypes: false,
|
|
97
121
|
});
|
|
98
|
-
|
|
122
|
+
this.resolveTPTIdentifiers(changeSet);
|
|
123
|
+
// Use changeSet's own meta for STI entities to get correct field mappings
|
|
124
|
+
const res = await this.#driver.nativeInsertMany(changeSet.meta.class, [changeSet.payload], options);
|
|
99
125
|
if (!wrapped.hasPrimaryKey()) {
|
|
100
|
-
this.mapPrimaryKey(meta, res.insertId, changeSet);
|
|
126
|
+
this.mapPrimaryKey(meta, res.insertId ?? res.row?.[meta.primaryKeys[0]], changeSet);
|
|
101
127
|
}
|
|
102
128
|
this.mapReturnedValues(changeSet.entity, changeSet.payload, res.row, meta);
|
|
103
129
|
this.markAsPopulated(changeSet, meta);
|
|
104
130
|
wrapped.__initialized = true;
|
|
105
131
|
wrapped.__managed = true;
|
|
106
|
-
if (!this
|
|
132
|
+
if (!this.#usesReturningStatement) {
|
|
107
133
|
await this.reloadVersionValues(meta, [changeSet], options);
|
|
108
134
|
}
|
|
109
135
|
changeSet.persisted = true;
|
|
110
136
|
}
|
|
111
137
|
async persistNewEntities(meta, changeSets, options) {
|
|
112
|
-
const size = this
|
|
138
|
+
const size = this.#config.get('batchSize');
|
|
113
139
|
for (let i = 0; i < changeSets.length; i += size) {
|
|
114
140
|
const chunk = changeSets.slice(i, i + size);
|
|
115
141
|
await this.persistNewEntitiesBatch(meta, chunk, options);
|
|
116
|
-
if (!this
|
|
142
|
+
if (!this.#usesReturningStatement) {
|
|
117
143
|
await this.reloadVersionValues(meta, chunk, options);
|
|
118
144
|
}
|
|
119
145
|
}
|
|
120
146
|
}
|
|
121
147
|
prepareOptions(meta, options, additionalOptions) {
|
|
122
|
-
const loggerContext = Utils.merge({ id: this
|
|
148
|
+
const loggerContext = Utils.merge({ id: this.#em._id }, this.#em.getLoggerContext({ disableContextResolution: true }));
|
|
123
149
|
return {
|
|
124
150
|
...options,
|
|
125
151
|
...additionalOptions,
|
|
@@ -132,7 +158,10 @@ export class ChangeSetPersister {
|
|
|
132
158
|
convertCustomTypes: false,
|
|
133
159
|
processCollections: false,
|
|
134
160
|
});
|
|
135
|
-
const
|
|
161
|
+
for (const changeSet of changeSets) {
|
|
162
|
+
this.resolveTPTIdentifiers(changeSet);
|
|
163
|
+
}
|
|
164
|
+
const res = await this.#driver.nativeInsertMany(meta.class, changeSets.map(cs => cs.payload), options);
|
|
136
165
|
for (let i = 0; i < changeSets.length; i++) {
|
|
137
166
|
const changeSet = changeSets[i];
|
|
138
167
|
const wrapped = helper(changeSet.entity);
|
|
@@ -150,7 +179,7 @@ export class ChangeSetPersister {
|
|
|
150
179
|
}
|
|
151
180
|
}
|
|
152
181
|
async persistManagedEntity(changeSet, options) {
|
|
153
|
-
const meta =
|
|
182
|
+
const meta = changeSet.meta;
|
|
154
183
|
const res = await this.updateEntity(meta, changeSet, options);
|
|
155
184
|
this.checkOptimisticLock(meta, changeSet, res);
|
|
156
185
|
this.mapReturnedValues(changeSet.entity, changeSet.payload, res.row, meta);
|
|
@@ -158,7 +187,7 @@ export class ChangeSetPersister {
|
|
|
158
187
|
changeSet.persisted = true;
|
|
159
188
|
}
|
|
160
189
|
async persistManagedEntities(meta, changeSets, options) {
|
|
161
|
-
const size = this
|
|
190
|
+
const size = this.#config.get('batchSize');
|
|
162
191
|
for (let i = 0; i < changeSets.length; i += size) {
|
|
163
192
|
const chunk = changeSets.slice(i, i + size);
|
|
164
193
|
await this.persistManagedEntitiesBatch(meta, chunk, options);
|
|
@@ -191,9 +220,9 @@ export class ChangeSetPersister {
|
|
|
191
220
|
cond.push(where);
|
|
192
221
|
payload.push(changeSet.payload);
|
|
193
222
|
}
|
|
194
|
-
const res = await this
|
|
223
|
+
const res = await this.#driver.nativeUpdateMany(meta.class, cond, payload, options);
|
|
195
224
|
const map = new Map();
|
|
196
|
-
res.rows?.forEach(item => map.set(Utils.getCompositeKeyHash(item, meta, true, this
|
|
225
|
+
res.rows?.forEach(item => map.set(Utils.getCompositeKeyHash(item, meta, true, this.#platform, true), item));
|
|
197
226
|
for (const changeSet of changeSets) {
|
|
198
227
|
if (res.rows) {
|
|
199
228
|
const row = map.get(helper(changeSet.entity).getSerializedPrimaryKey());
|
|
@@ -204,7 +233,7 @@ export class ChangeSetPersister {
|
|
|
204
233
|
}
|
|
205
234
|
mapPrimaryKey(meta, value, changeSet) {
|
|
206
235
|
const prop = meta.properties[meta.primaryKeys[0]];
|
|
207
|
-
const insertId = prop.customType ? prop.customType.convertToJSValue(value, this
|
|
236
|
+
const insertId = prop.customType ? prop.customType.convertToJSValue(value, this.#platform) : value;
|
|
208
237
|
const wrapped = helper(changeSet.entity);
|
|
209
238
|
if (!wrapped.hasPrimaryKey()) {
|
|
210
239
|
wrapped.setPrimaryKey(insertId);
|
|
@@ -212,7 +241,9 @@ export class ChangeSetPersister {
|
|
|
212
241
|
// some drivers might be returning bigint PKs as numbers when the number is small enough,
|
|
213
242
|
// but we need to have it as string so comparison works in change set tracking, so instead
|
|
214
243
|
// of using the raw value from db, we convert it back to the db value explicitly
|
|
215
|
-
value = prop.customType
|
|
244
|
+
value = prop.customType
|
|
245
|
+
? prop.customType.convertToDatabaseValue(insertId, this.#platform, { mode: 'serialization' })
|
|
246
|
+
: value;
|
|
216
247
|
changeSet.payload[wrapped.__meta.primaryKeys[0]] = value;
|
|
217
248
|
if (wrapped.__identifier && !Array.isArray(wrapped.__identifier)) {
|
|
218
249
|
wrapped.__identifier.setValue(value);
|
|
@@ -222,8 +253,8 @@ export class ChangeSetPersister {
|
|
|
222
253
|
* Sets populate flag to new entities so they are serialized like if they were loaded from the db
|
|
223
254
|
*/
|
|
224
255
|
markAsPopulated(changeSet, meta) {
|
|
225
|
-
helper(changeSet.entity).__schema = this
|
|
226
|
-
if (!this
|
|
256
|
+
helper(changeSet.entity).__schema = this.#driver.getSchemaName(meta, changeSet);
|
|
257
|
+
if (!this.#config.get('populateAfterFlush')) {
|
|
227
258
|
return;
|
|
228
259
|
}
|
|
229
260
|
helper(changeSet.entity).populated();
|
|
@@ -242,17 +273,19 @@ export class ChangeSetPersister {
|
|
|
242
273
|
options = this.prepareOptions(meta, options, {
|
|
243
274
|
convertCustomTypes: false,
|
|
244
275
|
});
|
|
245
|
-
if (meta.concurrencyCheckKeys.size === 0 &&
|
|
246
|
-
|
|
276
|
+
if (meta.concurrencyCheckKeys.size === 0 &&
|
|
277
|
+
(!meta.versionProperty || changeSet.entity[meta.versionProperty] == null)) {
|
|
278
|
+
return this.#driver.nativeUpdate(changeSet.meta.class, cond, changeSet.payload, options);
|
|
247
279
|
}
|
|
248
280
|
if (meta.versionProperty) {
|
|
249
|
-
cond[meta.versionProperty] = this
|
|
281
|
+
cond[meta.versionProperty] = this.#platform.convertVersionValue(changeSet.entity[meta.versionProperty], meta.properties[meta.versionProperty]);
|
|
250
282
|
}
|
|
251
283
|
this.checkConcurrencyKeys(meta, changeSet, cond);
|
|
252
|
-
return this
|
|
284
|
+
return this.#driver.nativeUpdate(changeSet.meta.class, cond, changeSet.payload, options);
|
|
253
285
|
}
|
|
254
286
|
async checkOptimisticLocks(meta, changeSets, options) {
|
|
255
|
-
if (meta.concurrencyCheckKeys.size === 0 &&
|
|
287
|
+
if (meta.concurrencyCheckKeys.size === 0 &&
|
|
288
|
+
(!meta.versionProperty || changeSets.every(cs => cs.entity[meta.versionProperty] == null))) {
|
|
256
289
|
return;
|
|
257
290
|
}
|
|
258
291
|
// skip entity references as they don't have version values loaded
|
|
@@ -261,7 +294,7 @@ export class ChangeSetPersister {
|
|
|
261
294
|
const cond = Utils.getPrimaryKeyCond(cs.originalEntity, meta.primaryKeys.concat(...meta.concurrencyCheckKeys));
|
|
262
295
|
if (meta.versionProperty) {
|
|
263
296
|
// @ts-ignore
|
|
264
|
-
cond[meta.versionProperty] = this
|
|
297
|
+
cond[meta.versionProperty] = this.#platform.convertVersionValue(cs.entity[meta.versionProperty], meta.properties[meta.versionProperty]);
|
|
265
298
|
}
|
|
266
299
|
return cond;
|
|
267
300
|
});
|
|
@@ -269,7 +302,7 @@ export class ChangeSetPersister {
|
|
|
269
302
|
options = this.prepareOptions(meta, options, {
|
|
270
303
|
fields: primaryKeys,
|
|
271
304
|
});
|
|
272
|
-
const res = await this
|
|
305
|
+
const res = await this.#driver.find(meta.root.class, { $or }, options);
|
|
273
306
|
if (res.length !== changeSets.length) {
|
|
274
307
|
const compare = (a, b, keys) => keys.every(k => a[k] === b[k]);
|
|
275
308
|
const entity = changeSets.find(cs => {
|
|
@@ -288,13 +321,24 @@ export class ChangeSetPersister {
|
|
|
288
321
|
* so we use a single query in case of both versioning and default values is used.
|
|
289
322
|
*/
|
|
290
323
|
async reloadVersionValues(meta, changeSets, options) {
|
|
291
|
-
const reloadProps = meta.versionProperty && !this
|
|
324
|
+
const reloadProps = meta.versionProperty && !this.#usesReturningStatement ? [meta.properties[meta.versionProperty]] : [];
|
|
292
325
|
if (changeSets[0].type === ChangeSetType.CREATE) {
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
.
|
|
326
|
+
for (const prop of meta.props) {
|
|
327
|
+
if (prop.persist === false) {
|
|
328
|
+
continue;
|
|
329
|
+
}
|
|
330
|
+
if (isRaw(changeSets[0].entity[prop.name])) {
|
|
331
|
+
reloadProps.push(prop);
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
// do not reload things that already had a runtime value
|
|
335
|
+
if (changeSets[0].entity[prop.name] != null || prop.defaultRaw === 'null') {
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
if (prop.autoincrement || prop.generated || prop.defaultRaw) {
|
|
339
|
+
reloadProps.push(prop);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
298
342
|
}
|
|
299
343
|
if (changeSets[0].type === ChangeSetType.UPDATE) {
|
|
300
344
|
const returning = new Set();
|
|
@@ -306,10 +350,8 @@ export class ChangeSetPersister {
|
|
|
306
350
|
});
|
|
307
351
|
});
|
|
308
352
|
// reload generated columns
|
|
309
|
-
if (!this
|
|
310
|
-
meta.props
|
|
311
|
-
.filter(prop => prop.generated && !prop.primary)
|
|
312
|
-
.forEach(prop => reloadProps.push(prop));
|
|
353
|
+
if (!this.#usesReturningStatement) {
|
|
354
|
+
meta.props.filter(prop => prop.generated && !prop.primary).forEach(prop => reloadProps.push(prop));
|
|
313
355
|
reloadProps.push(...returning);
|
|
314
356
|
}
|
|
315
357
|
}
|
|
@@ -321,35 +363,56 @@ export class ChangeSetPersister {
|
|
|
321
363
|
const pks = changeSets.map(cs => {
|
|
322
364
|
const val = helper(cs.entity).getPrimaryKey(true);
|
|
323
365
|
if (Utils.isPlainObject(val)) {
|
|
324
|
-
return Utils.getCompositeKeyValue(val, meta, false, this
|
|
366
|
+
return Utils.getCompositeKeyValue(val, meta, false, this.#platform);
|
|
325
367
|
}
|
|
326
368
|
return val;
|
|
327
369
|
});
|
|
328
370
|
options = this.prepareOptions(meta, options, {
|
|
329
371
|
fields: Utils.unique(reloadProps.map(prop => prop.name)),
|
|
330
372
|
});
|
|
331
|
-
const data = await this
|
|
373
|
+
const data = await this.#driver.find(meta.class, { [pk]: { $in: pks } }, options);
|
|
332
374
|
const map = new Map();
|
|
333
|
-
data.forEach(item => map.set(Utils.getCompositeKeyHash(item, meta, false, this
|
|
375
|
+
data.forEach(item => map.set(Utils.getCompositeKeyHash(item, meta, false, this.#platform, true), item));
|
|
334
376
|
for (const changeSet of changeSets) {
|
|
335
377
|
const data = map.get(helper(changeSet.entity).getSerializedPrimaryKey());
|
|
336
|
-
this
|
|
378
|
+
this.#hydrator.hydrate(changeSet.entity, meta, data, this.#factory, 'full', false, true);
|
|
337
379
|
Object.assign(changeSet.payload, data); // merge to the changeset payload, so it gets saved to the entity snapshot
|
|
338
380
|
}
|
|
339
381
|
}
|
|
382
|
+
/**
|
|
383
|
+
* For TPT child tables, resolve EntityIdentifier values in PK fields.
|
|
384
|
+
* The parent table insert assigns the actual PK value, which the child table references.
|
|
385
|
+
*/
|
|
386
|
+
resolveTPTIdentifiers(changeSet) {
|
|
387
|
+
if (changeSet.meta.inheritanceType !== 'tpt' || !changeSet.meta.tptParent) {
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
for (const pk of changeSet.meta.primaryKeys) {
|
|
391
|
+
const value = changeSet.payload[pk];
|
|
392
|
+
if (value instanceof EntityIdentifier) {
|
|
393
|
+
changeSet.payload[pk] = value.getValue();
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
340
397
|
processProperty(changeSet, prop) {
|
|
341
|
-
const meta =
|
|
398
|
+
const meta = changeSet.meta;
|
|
342
399
|
const value = changeSet.payload[prop.name]; // for inline embeddables
|
|
343
400
|
if (value instanceof EntityIdentifier) {
|
|
344
401
|
changeSet.payload[prop.name] = value.getValue();
|
|
345
402
|
return;
|
|
346
403
|
}
|
|
404
|
+
if (value instanceof PolymorphicRef) {
|
|
405
|
+
if (value.id instanceof EntityIdentifier) {
|
|
406
|
+
value.id = value.id.getValue();
|
|
407
|
+
}
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
347
410
|
if (Array.isArray(value) && value.every(item => item instanceof EntityIdentifier)) {
|
|
348
411
|
changeSet.payload[prop.name] = value.map(item => item.getValue());
|
|
349
412
|
return;
|
|
350
413
|
}
|
|
351
414
|
if (prop.kind === ReferenceKind.MANY_TO_MANY && Array.isArray(value)) {
|
|
352
|
-
changeSet.payload[prop.name] = value.map(val => val instanceof EntityIdentifier ? val.getValue() : val);
|
|
415
|
+
changeSet.payload[prop.name] = value.map(val => (val instanceof EntityIdentifier ? val.getValue() : val));
|
|
353
416
|
return;
|
|
354
417
|
}
|
|
355
418
|
if (prop.name in changeSet.payload) {
|
|
@@ -368,17 +431,17 @@ export class ChangeSetPersister {
|
|
|
368
431
|
* We do need to map to the change set payload too, as it will be used in the originalEntityData for new entities.
|
|
369
432
|
*/
|
|
370
433
|
mapReturnedValues(entity, payload, row, meta, upsert = false) {
|
|
371
|
-
if ((!this
|
|
434
|
+
if ((!this.#usesReturningStatement && !upsert) || !row || !Utils.hasObjectKeys(row)) {
|
|
372
435
|
return;
|
|
373
436
|
}
|
|
374
|
-
const mapped = this
|
|
437
|
+
const mapped = this.#comparator.mapResult(meta, row);
|
|
375
438
|
if (entity) {
|
|
376
|
-
this
|
|
439
|
+
this.#hydrator.hydrate(entity, meta, mapped, this.#factory, 'full', false, true);
|
|
377
440
|
}
|
|
378
441
|
if (upsert) {
|
|
379
442
|
for (const prop of meta.props) {
|
|
380
443
|
if (prop.customType && prop.name in mapped) {
|
|
381
|
-
mapped[prop.name] = prop.customType.convertToJSValue(mapped[prop.name], this
|
|
444
|
+
mapped[prop.name] = prop.customType.convertToJSValue(mapped[prop.name], this.#platform);
|
|
382
445
|
}
|
|
383
446
|
}
|
|
384
447
|
}
|
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { EntityProperty } from '../typings.js';
|
|
2
2
|
export declare const enum NodeState {
|
|
3
3
|
NOT_VISITED = 0,
|
|
4
4
|
IN_PROGRESS = 1,
|
|
5
5
|
VISITED = 2
|
|
6
6
|
}
|
|
7
|
+
type Hash = number;
|
|
7
8
|
export interface Node {
|
|
8
|
-
hash:
|
|
9
|
+
hash: Hash;
|
|
9
10
|
state: NodeState;
|
|
10
|
-
dependencies:
|
|
11
|
+
dependencies: Map<Hash, Edge>;
|
|
11
12
|
}
|
|
12
13
|
export interface Edge {
|
|
13
|
-
from:
|
|
14
|
-
to:
|
|
14
|
+
from: Hash;
|
|
15
|
+
to: Hash;
|
|
15
16
|
weight: number;
|
|
16
17
|
}
|
|
17
18
|
/**
|
|
@@ -25,30 +26,27 @@ export interface Edge {
|
|
|
25
26
|
* @internal
|
|
26
27
|
*/
|
|
27
28
|
export declare class CommitOrderCalculator {
|
|
28
|
-
|
|
29
|
-
private nodes;
|
|
30
|
-
/** Volatile variable holding calculated nodes during sorting process. */
|
|
31
|
-
private sortedNodeList;
|
|
29
|
+
#private;
|
|
32
30
|
/**
|
|
33
31
|
* Checks for node existence in graph.
|
|
34
32
|
*/
|
|
35
|
-
hasNode(hash:
|
|
33
|
+
hasNode(hash: Hash): boolean;
|
|
36
34
|
/**
|
|
37
35
|
* Adds a new node to the graph, assigning its hash.
|
|
38
36
|
*/
|
|
39
|
-
addNode(hash:
|
|
37
|
+
addNode(hash: Hash): void;
|
|
40
38
|
/**
|
|
41
39
|
* Adds a new dependency (edge) to the graph using their hashes.
|
|
42
40
|
*/
|
|
43
|
-
addDependency(from:
|
|
44
|
-
discoverProperty(prop: EntityProperty, entityName:
|
|
41
|
+
addDependency(from: Hash, to: Hash, weight: number): void;
|
|
42
|
+
discoverProperty(prop: EntityProperty, entityName: Hash): void;
|
|
45
43
|
/**
|
|
46
44
|
* Return a valid order list of all current nodes.
|
|
47
45
|
* The desired topological sorting is the reverse post order of these searches.
|
|
48
46
|
*
|
|
49
47
|
* @internal Highly performance-sensitive method.
|
|
50
48
|
*/
|
|
51
|
-
sort():
|
|
49
|
+
sort(): Hash[];
|
|
52
50
|
/**
|
|
53
51
|
* Visit a given node definition for reordering.
|
|
54
52
|
*
|
|
@@ -60,3 +58,4 @@ export declare class CommitOrderCalculator {
|
|
|
60
58
|
*/
|
|
61
59
|
private visitOpenNode;
|
|
62
60
|
}
|
|
61
|
+
export {};
|
|
@@ -17,26 +17,26 @@ export var NodeState;
|
|
|
17
17
|
*/
|
|
18
18
|
export class CommitOrderCalculator {
|
|
19
19
|
/** Matrix of nodes, keys are provided hashes and values are the node definition objects. */
|
|
20
|
-
nodes =
|
|
20
|
+
#nodes = new Map();
|
|
21
21
|
/** Volatile variable holding calculated nodes during sorting process. */
|
|
22
|
-
sortedNodeList = [];
|
|
22
|
+
#sortedNodeList = [];
|
|
23
23
|
/**
|
|
24
24
|
* Checks for node existence in graph.
|
|
25
25
|
*/
|
|
26
26
|
hasNode(hash) {
|
|
27
|
-
return
|
|
27
|
+
return this.#nodes.has(hash);
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
30
30
|
* Adds a new node to the graph, assigning its hash.
|
|
31
31
|
*/
|
|
32
32
|
addNode(hash) {
|
|
33
|
-
this.
|
|
33
|
+
this.#nodes.set(hash, { hash, state: 0 /* NodeState.NOT_VISITED */, dependencies: new Map() });
|
|
34
34
|
}
|
|
35
35
|
/**
|
|
36
36
|
* Adds a new dependency (edge) to the graph using their hashes.
|
|
37
37
|
*/
|
|
38
38
|
addDependency(from, to, weight) {
|
|
39
|
-
this.
|
|
39
|
+
this.#nodes.get(from).dependencies.set(to, { from, to, weight });
|
|
40
40
|
}
|
|
41
41
|
discoverProperty(prop, entityName) {
|
|
42
42
|
const toOneOwner = (prop.kind === ReferenceKind.ONE_TO_ONE && prop.owner) || prop.kind === ReferenceKind.MANY_TO_ONE;
|
|
@@ -44,8 +44,8 @@ export class CommitOrderCalculator {
|
|
|
44
44
|
if (!toOneOwner && !toManyOwner) {
|
|
45
45
|
return;
|
|
46
46
|
}
|
|
47
|
-
const propertyType = prop.targetMeta?.root.
|
|
48
|
-
if (
|
|
47
|
+
const propertyType = prop.targetMeta?.root._id;
|
|
48
|
+
if (propertyType == null || !this.hasNode(propertyType)) {
|
|
49
49
|
return;
|
|
50
50
|
}
|
|
51
51
|
this.addDependency(propertyType, entityName, prop.nullable || prop.persist === false ? 0 : 1);
|
|
@@ -57,15 +57,15 @@ export class CommitOrderCalculator {
|
|
|
57
57
|
* @internal Highly performance-sensitive method.
|
|
58
58
|
*/
|
|
59
59
|
sort() {
|
|
60
|
-
for (const vertex of
|
|
60
|
+
for (const vertex of this.#nodes.values()) {
|
|
61
61
|
if (vertex.state !== 0 /* NodeState.NOT_VISITED */) {
|
|
62
62
|
continue;
|
|
63
63
|
}
|
|
64
64
|
this.visit(vertex);
|
|
65
65
|
}
|
|
66
|
-
const sortedList = this
|
|
67
|
-
this
|
|
68
|
-
this
|
|
66
|
+
const sortedList = this.#sortedNodeList.reverse();
|
|
67
|
+
this.#nodes = new Map();
|
|
68
|
+
this.#sortedNodeList = [];
|
|
69
69
|
return sortedList;
|
|
70
70
|
}
|
|
71
71
|
/**
|
|
@@ -75,35 +75,37 @@ export class CommitOrderCalculator {
|
|
|
75
75
|
*/
|
|
76
76
|
visit(node) {
|
|
77
77
|
node.state = 1 /* NodeState.IN_PROGRESS */;
|
|
78
|
-
for (const edge of
|
|
79
|
-
const target = this.
|
|
78
|
+
for (const edge of node.dependencies.values()) {
|
|
79
|
+
const target = this.#nodes.get(edge.to);
|
|
80
80
|
switch (target.state) {
|
|
81
|
-
case 2 /* NodeState.VISITED */:
|
|
81
|
+
case 2 /* NodeState.VISITED */:
|
|
82
|
+
break; // Do nothing, since node was already visited
|
|
82
83
|
case 1 /* NodeState.IN_PROGRESS */:
|
|
83
84
|
this.visitOpenNode(node, target, edge);
|
|
84
85
|
break;
|
|
85
|
-
case 0 /* NodeState.NOT_VISITED */:
|
|
86
|
+
case 0 /* NodeState.NOT_VISITED */:
|
|
87
|
+
this.visit(target);
|
|
86
88
|
}
|
|
87
89
|
}
|
|
88
90
|
if (node.state !== 2 /* NodeState.VISITED */) {
|
|
89
91
|
node.state = 2 /* NodeState.VISITED */;
|
|
90
|
-
this
|
|
92
|
+
this.#sortedNodeList.push(node.hash);
|
|
91
93
|
}
|
|
92
94
|
}
|
|
93
95
|
/**
|
|
94
96
|
* Visits all target's dependencies if in cycle with given node
|
|
95
97
|
*/
|
|
96
98
|
visitOpenNode(node, target, edge) {
|
|
97
|
-
if (!target.dependencies
|
|
99
|
+
if (!target.dependencies.has(node.hash) || target.dependencies.get(node.hash).weight >= edge.weight) {
|
|
98
100
|
return;
|
|
99
101
|
}
|
|
100
|
-
for (const edge of
|
|
101
|
-
const targetNode = this.
|
|
102
|
+
for (const edge of target.dependencies.values()) {
|
|
103
|
+
const targetNode = this.#nodes.get(edge.to);
|
|
102
104
|
if (targetNode.state === 0 /* NodeState.NOT_VISITED */) {
|
|
103
105
|
this.visit(targetNode);
|
|
104
106
|
}
|
|
105
107
|
}
|
|
106
108
|
target.state = 2 /* NodeState.VISITED */;
|
|
107
|
-
this
|
|
109
|
+
this.#sortedNodeList.push(target.hash);
|
|
108
110
|
}
|
|
109
111
|
}
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import type { AnyEntity, EntityMetadata } from '../typings.js';
|
|
2
2
|
export declare class IdentityMap {
|
|
3
|
-
private
|
|
4
|
-
constructor(defaultSchema?: string
|
|
5
|
-
private readonly registry;
|
|
3
|
+
#private;
|
|
4
|
+
constructor(defaultSchema?: string);
|
|
6
5
|
store<T>(item: T): void;
|
|
6
|
+
/**
|
|
7
|
+
* Stores an entity under an alternate key (non-PK property).
|
|
8
|
+
* This allows looking up entities by unique properties that are not the primary key.
|
|
9
|
+
*/
|
|
10
|
+
storeByKey<T>(item: T, key: string, value: string, schema?: string): void;
|
|
7
11
|
delete<T>(item: T): void;
|
|
8
12
|
getByHash<T>(meta: EntityMetadata<T>, hash: string): T | undefined;
|
|
9
13
|
getStore<T>(meta: EntityMetadata<T>): Map<string, T>;
|
|
@@ -16,4 +20,9 @@ export declare class IdentityMap {
|
|
|
16
20
|
*/
|
|
17
21
|
get<T>(hash: string): T | undefined;
|
|
18
22
|
private getPkHash;
|
|
23
|
+
/**
|
|
24
|
+
* Creates a hash for an alternate key lookup.
|
|
25
|
+
* Format: `[key]value` or `schema:[key]value`
|
|
26
|
+
*/
|
|
27
|
+
getKeyHash(key: string, value: string, schema?: string): string;
|
|
19
28
|
}
|