@mikro-orm/core 7.0.0-dev.2 → 7.0.0-dev.200
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/EntityManager.d.ts +111 -61
- package/EntityManager.js +346 -300
- package/MikroORM.d.ts +44 -35
- package/MikroORM.js +103 -143
- package/README.md +3 -2
- package/cache/FileCacheAdapter.d.ts +1 -1
- package/cache/FileCacheAdapter.js +8 -7
- package/cache/GeneratedCacheAdapter.d.ts +0 -1
- package/cache/GeneratedCacheAdapter.js +0 -2
- package/cache/index.d.ts +0 -1
- package/cache/index.js +0 -1
- package/connections/Connection.d.ts +16 -7
- package/connections/Connection.js +23 -14
- package/drivers/DatabaseDriver.d.ts +25 -16
- package/drivers/DatabaseDriver.js +80 -35
- package/drivers/IDatabaseDriver.d.ts +47 -17
- package/entity/BaseEntity.d.ts +2 -2
- package/entity/BaseEntity.js +0 -3
- package/entity/Collection.d.ts +95 -31
- package/entity/Collection.js +444 -102
- package/entity/EntityAssigner.d.ts +1 -1
- package/entity/EntityAssigner.js +26 -18
- package/entity/EntityFactory.d.ts +13 -1
- package/entity/EntityFactory.js +88 -54
- package/entity/EntityHelper.d.ts +2 -2
- package/entity/EntityHelper.js +38 -15
- package/entity/EntityLoader.d.ts +8 -7
- package/entity/EntityLoader.js +134 -80
- package/entity/EntityRepository.d.ts +24 -4
- package/entity/EntityRepository.js +8 -2
- package/entity/Reference.d.ts +9 -12
- package/entity/Reference.js +34 -9
- package/entity/WrappedEntity.d.ts +2 -7
- package/entity/WrappedEntity.js +3 -8
- package/entity/defineEntity.d.ts +585 -0
- package/entity/defineEntity.js +533 -0
- package/entity/index.d.ts +3 -2
- package/entity/index.js +3 -2
- package/entity/utils.d.ts +7 -0
- package/entity/utils.js +16 -4
- package/entity/validators.d.ts +11 -0
- package/entity/validators.js +65 -0
- package/enums.d.ts +22 -6
- package/enums.js +15 -1
- package/errors.d.ts +23 -9
- package/errors.js +59 -21
- package/events/EventManager.d.ts +2 -1
- package/events/EventManager.js +19 -11
- package/events/EventSubscriber.d.ts +3 -1
- package/hydration/Hydrator.js +1 -2
- package/hydration/ObjectHydrator.d.ts +4 -4
- package/hydration/ObjectHydrator.js +53 -33
- package/index.d.ts +2 -2
- package/index.js +1 -2
- package/logging/DefaultLogger.d.ts +1 -1
- package/logging/DefaultLogger.js +1 -0
- package/logging/SimpleLogger.d.ts +1 -1
- package/logging/colors.d.ts +1 -1
- package/logging/colors.js +7 -6
- package/logging/index.d.ts +1 -0
- package/logging/index.js +1 -0
- package/logging/inspect.d.ts +2 -0
- package/logging/inspect.js +11 -0
- package/metadata/EntitySchema.d.ts +26 -26
- package/metadata/EntitySchema.js +82 -51
- package/metadata/MetadataDiscovery.d.ts +7 -10
- package/metadata/MetadataDiscovery.js +408 -335
- package/metadata/MetadataProvider.d.ts +11 -2
- package/metadata/MetadataProvider.js +46 -2
- package/metadata/MetadataStorage.d.ts +13 -11
- package/metadata/MetadataStorage.js +70 -37
- package/metadata/MetadataValidator.d.ts +17 -9
- package/metadata/MetadataValidator.js +100 -42
- package/metadata/discover-entities.d.ts +5 -0
- package/metadata/discover-entities.js +40 -0
- package/metadata/index.d.ts +1 -1
- package/metadata/index.js +1 -1
- package/metadata/types.d.ts +502 -0
- package/metadata/types.js +1 -0
- package/naming-strategy/AbstractNamingStrategy.d.ts +12 -4
- package/naming-strategy/AbstractNamingStrategy.js +14 -2
- package/naming-strategy/EntityCaseNamingStrategy.d.ts +3 -3
- package/naming-strategy/EntityCaseNamingStrategy.js +6 -5
- package/naming-strategy/MongoNamingStrategy.d.ts +3 -3
- package/naming-strategy/MongoNamingStrategy.js +6 -6
- package/naming-strategy/NamingStrategy.d.ts +24 -4
- package/naming-strategy/UnderscoreNamingStrategy.d.ts +3 -3
- package/naming-strategy/UnderscoreNamingStrategy.js +6 -6
- package/not-supported.d.ts +2 -0
- package/not-supported.js +4 -0
- package/package.json +19 -11
- package/platforms/ExceptionConverter.js +1 -1
- package/platforms/Platform.d.ts +7 -13
- package/platforms/Platform.js +20 -43
- package/serialization/EntitySerializer.d.ts +5 -0
- package/serialization/EntitySerializer.js +47 -27
- package/serialization/EntityTransformer.js +28 -18
- package/serialization/SerializationContext.d.ts +6 -6
- package/serialization/SerializationContext.js +16 -13
- package/types/ArrayType.d.ts +1 -1
- package/types/ArrayType.js +2 -3
- package/types/BigIntType.d.ts +9 -6
- package/types/BigIntType.js +4 -1
- package/types/BlobType.d.ts +0 -1
- package/types/BlobType.js +0 -3
- package/types/BooleanType.d.ts +2 -1
- package/types/BooleanType.js +3 -0
- package/types/DecimalType.d.ts +6 -4
- package/types/DecimalType.js +3 -3
- package/types/DoubleType.js +2 -2
- package/types/EnumArrayType.js +1 -2
- package/types/JsonType.d.ts +1 -1
- package/types/JsonType.js +7 -2
- package/types/TinyIntType.js +1 -1
- package/types/Type.d.ts +2 -4
- package/types/Type.js +3 -3
- package/types/Uint8ArrayType.d.ts +0 -1
- package/types/Uint8ArrayType.js +1 -4
- package/types/index.d.ts +1 -1
- package/typings.d.ts +300 -140
- package/typings.js +62 -44
- package/unit-of-work/ChangeSet.d.ts +2 -6
- package/unit-of-work/ChangeSet.js +4 -5
- package/unit-of-work/ChangeSetComputer.d.ts +1 -3
- package/unit-of-work/ChangeSetComputer.js +26 -13
- package/unit-of-work/ChangeSetPersister.d.ts +5 -4
- package/unit-of-work/ChangeSetPersister.js +77 -35
- package/unit-of-work/CommitOrderCalculator.d.ts +12 -10
- package/unit-of-work/CommitOrderCalculator.js +13 -13
- package/unit-of-work/IdentityMap.d.ts +12 -0
- package/unit-of-work/IdentityMap.js +39 -1
- package/unit-of-work/UnitOfWork.d.ts +23 -3
- package/unit-of-work/UnitOfWork.js +199 -106
- package/utils/AbstractSchemaGenerator.d.ts +5 -5
- package/utils/AbstractSchemaGenerator.js +22 -17
- package/utils/AsyncContext.d.ts +6 -0
- package/utils/AsyncContext.js +42 -0
- package/utils/Configuration.d.ts +779 -207
- package/utils/Configuration.js +146 -190
- package/utils/ConfigurationLoader.d.ts +1 -54
- package/utils/ConfigurationLoader.js +1 -352
- package/utils/Cursor.d.ts +3 -6
- package/utils/Cursor.js +27 -11
- package/utils/DataloaderUtils.d.ts +15 -5
- package/utils/DataloaderUtils.js +65 -17
- package/utils/EntityComparator.d.ts +13 -9
- package/utils/EntityComparator.js +164 -89
- package/utils/QueryHelper.d.ts +14 -6
- package/utils/QueryHelper.js +88 -26
- package/utils/RawQueryFragment.d.ts +48 -25
- package/utils/RawQueryFragment.js +67 -66
- package/utils/RequestContext.js +2 -2
- package/utils/TransactionContext.js +2 -2
- package/utils/TransactionManager.d.ts +65 -0
- package/utils/TransactionManager.js +223 -0
- package/utils/Utils.d.ts +13 -120
- package/utils/Utils.js +104 -375
- package/utils/clone.js +8 -23
- package/utils/env-vars.d.ts +7 -0
- package/utils/env-vars.js +97 -0
- package/utils/fs-utils.d.ts +32 -0
- package/utils/fs-utils.js +178 -0
- package/utils/index.d.ts +2 -1
- package/utils/index.js +2 -1
- package/utils/upsert-utils.d.ts +9 -4
- package/utils/upsert-utils.js +55 -4
- package/decorators/Check.d.ts +0 -3
- package/decorators/Check.js +0 -13
- package/decorators/CreateRequestContext.d.ts +0 -3
- package/decorators/CreateRequestContext.js +0 -29
- package/decorators/Embeddable.d.ts +0 -8
- package/decorators/Embeddable.js +0 -11
- package/decorators/Embedded.d.ts +0 -18
- package/decorators/Embedded.js +0 -18
- package/decorators/Entity.d.ts +0 -18
- package/decorators/Entity.js +0 -13
- package/decorators/Enum.d.ts +0 -9
- package/decorators/Enum.js +0 -16
- package/decorators/Filter.d.ts +0 -2
- package/decorators/Filter.js +0 -8
- package/decorators/Formula.d.ts +0 -5
- package/decorators/Formula.js +0 -15
- package/decorators/Indexed.d.ts +0 -17
- package/decorators/Indexed.js +0 -20
- package/decorators/ManyToMany.d.ts +0 -40
- package/decorators/ManyToMany.js +0 -14
- package/decorators/ManyToOne.d.ts +0 -30
- package/decorators/ManyToOne.js +0 -14
- package/decorators/OneToMany.d.ts +0 -28
- package/decorators/OneToMany.js +0 -17
- package/decorators/OneToOne.d.ts +0 -24
- package/decorators/OneToOne.js +0 -7
- package/decorators/PrimaryKey.d.ts +0 -9
- package/decorators/PrimaryKey.js +0 -20
- package/decorators/Property.d.ts +0 -250
- package/decorators/Property.js +0 -32
- package/decorators/Transactional.d.ts +0 -13
- package/decorators/Transactional.js +0 -28
- package/decorators/hooks.d.ts +0 -16
- package/decorators/hooks.js +0 -47
- package/decorators/index.d.ts +0 -17
- package/decorators/index.js +0 -17
- package/entity/ArrayCollection.d.ts +0 -116
- package/entity/ArrayCollection.js +0 -395
- package/entity/EntityValidator.d.ts +0 -19
- package/entity/EntityValidator.js +0 -150
- package/metadata/ReflectMetadataProvider.d.ts +0 -8
- package/metadata/ReflectMetadataProvider.js +0 -44
- package/utils/resolveContextProvider.d.ts +0 -10
- package/utils/resolveContextProvider.js +0 -28
|
@@ -3,25 +3,25 @@ import { helper } from '../entity/wrap.js';
|
|
|
3
3
|
import { ChangeSetType } from './ChangeSet.js';
|
|
4
4
|
import { isRaw } from '../utils/RawQueryFragment.js';
|
|
5
5
|
import { Utils } from '../utils/Utils.js';
|
|
6
|
-
import { OptimisticLockError } from '../errors.js';
|
|
6
|
+
import { OptimisticLockError, ValidationError } from '../errors.js';
|
|
7
7
|
import { ReferenceKind } from '../enums.js';
|
|
8
8
|
export class ChangeSetPersister {
|
|
9
9
|
driver;
|
|
10
10
|
metadata;
|
|
11
11
|
hydrator;
|
|
12
12
|
factory;
|
|
13
|
-
validator;
|
|
14
13
|
config;
|
|
14
|
+
em;
|
|
15
15
|
platform;
|
|
16
16
|
comparator;
|
|
17
17
|
usesReturningStatement;
|
|
18
|
-
constructor(driver, metadata, hydrator, factory,
|
|
18
|
+
constructor(driver, metadata, hydrator, factory, config, em) {
|
|
19
19
|
this.driver = driver;
|
|
20
20
|
this.metadata = metadata;
|
|
21
21
|
this.hydrator = hydrator;
|
|
22
22
|
this.factory = factory;
|
|
23
|
-
this.validator = validator;
|
|
24
23
|
this.config = config;
|
|
24
|
+
this.em = em;
|
|
25
25
|
this.platform = this.driver.getPlatform();
|
|
26
26
|
this.comparator = this.config.getComparator(this.metadata);
|
|
27
27
|
this.usesReturningStatement = this.platform.usesReturningStatement() || this.platform.usesOutputStatement();
|
|
@@ -30,7 +30,7 @@ export class ChangeSetPersister {
|
|
|
30
30
|
if (!withSchema) {
|
|
31
31
|
return this.runForEachSchema(changeSets, 'executeInserts', options);
|
|
32
32
|
}
|
|
33
|
-
const meta =
|
|
33
|
+
const meta = changeSets[0].meta;
|
|
34
34
|
changeSets.forEach(changeSet => this.processProperties(changeSet));
|
|
35
35
|
if (changeSets.length > 1 && this.config.get('useBatchInserts', this.platform.usesBatchInserts())) {
|
|
36
36
|
return this.persistNewEntities(meta, changeSets, options);
|
|
@@ -43,9 +43,12 @@ export class ChangeSetPersister {
|
|
|
43
43
|
if (!withSchema) {
|
|
44
44
|
return this.runForEachSchema(changeSets, 'executeUpdates', options, batched);
|
|
45
45
|
}
|
|
46
|
-
const meta =
|
|
46
|
+
const meta = changeSets[0].meta;
|
|
47
47
|
changeSets.forEach(changeSet => this.processProperties(changeSet));
|
|
48
|
-
|
|
48
|
+
// For STI with conflicting fieldNames (renamedFrom properties), we can't batch mixed child types
|
|
49
|
+
const hasSTIConflicts = meta.root.props.some(p => p.renamedFrom);
|
|
50
|
+
const hasMixedTypes = hasSTIConflicts && changeSets.some(cs => cs.meta.class !== meta.class);
|
|
51
|
+
if (batched && changeSets.length > 1 && !hasMixedTypes && this.config.get('useBatchUpdates', this.platform.usesBatchUpdates())) {
|
|
49
52
|
return this.persistManagedEntities(meta, changeSets, options);
|
|
50
53
|
}
|
|
51
54
|
for (const changeSet of changeSets) {
|
|
@@ -62,8 +65,8 @@ export class ChangeSetPersister {
|
|
|
62
65
|
for (let i = 0; i < changeSets.length; i += size) {
|
|
63
66
|
const chunk = changeSets.slice(i, i + size);
|
|
64
67
|
const pks = chunk.map(cs => cs.getPrimaryKey());
|
|
65
|
-
options = this.
|
|
66
|
-
await this.driver.nativeDelete(meta.root.
|
|
68
|
+
options = this.prepareOptions(meta, options);
|
|
69
|
+
await this.driver.nativeDelete(meta.root.class, { [pk]: { $in: pks } }, options);
|
|
67
70
|
}
|
|
68
71
|
}
|
|
69
72
|
async runForEachSchema(changeSets, method, options, ...args) {
|
|
@@ -79,21 +82,41 @@ export class ChangeSetPersister {
|
|
|
79
82
|
await this[method](group, ...args, options, true);
|
|
80
83
|
}
|
|
81
84
|
}
|
|
85
|
+
validateRequired(entity) {
|
|
86
|
+
const wrapped = helper(entity);
|
|
87
|
+
for (const prop of wrapped.__meta.props) {
|
|
88
|
+
if (!prop.nullable &&
|
|
89
|
+
!prop.autoincrement &&
|
|
90
|
+
!prop.default &&
|
|
91
|
+
!prop.defaultRaw &&
|
|
92
|
+
!prop.onCreate &&
|
|
93
|
+
!prop.generated &&
|
|
94
|
+
!prop.embedded &&
|
|
95
|
+
![ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(prop.kind) &&
|
|
96
|
+
prop.name !== wrapped.__meta.root.discriminatorColumn &&
|
|
97
|
+
prop.type !== 'ObjectId' &&
|
|
98
|
+
prop.persist !== false &&
|
|
99
|
+
entity[prop.name] == null) {
|
|
100
|
+
throw ValidationError.propertyRequired(entity, prop);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
82
104
|
processProperties(changeSet) {
|
|
83
|
-
const meta =
|
|
105
|
+
const meta = changeSet.meta;
|
|
84
106
|
for (const prop of meta.relations) {
|
|
85
107
|
this.processProperty(changeSet, prop);
|
|
86
108
|
}
|
|
87
109
|
if (changeSet.type === ChangeSetType.CREATE && this.config.get('validateRequired')) {
|
|
88
|
-
this.
|
|
110
|
+
this.validateRequired(changeSet.entity);
|
|
89
111
|
}
|
|
90
112
|
}
|
|
91
113
|
async persistNewEntity(meta, changeSet, options) {
|
|
92
114
|
const wrapped = helper(changeSet.entity);
|
|
93
|
-
options = this.
|
|
115
|
+
options = this.prepareOptions(meta, options, {
|
|
94
116
|
convertCustomTypes: false,
|
|
95
117
|
});
|
|
96
|
-
|
|
118
|
+
// Use changeSet's own meta for STI entities to get correct field mappings
|
|
119
|
+
const res = await this.driver.nativeInsertMany(changeSet.meta.class, [changeSet.payload], options);
|
|
97
120
|
if (!wrapped.hasPrimaryKey()) {
|
|
98
121
|
this.mapPrimaryKey(meta, res.insertId, changeSet);
|
|
99
122
|
}
|
|
@@ -116,19 +139,21 @@ export class ChangeSetPersister {
|
|
|
116
139
|
}
|
|
117
140
|
}
|
|
118
141
|
}
|
|
119
|
-
|
|
142
|
+
prepareOptions(meta, options, additionalOptions) {
|
|
143
|
+
const loggerContext = Utils.merge({ id: this.em._id }, this.em.getLoggerContext({ disableContextResolution: true }));
|
|
120
144
|
return {
|
|
121
145
|
...options,
|
|
122
146
|
...additionalOptions,
|
|
123
147
|
schema: options?.schema ?? meta.schema,
|
|
148
|
+
loggerContext,
|
|
124
149
|
};
|
|
125
150
|
}
|
|
126
151
|
async persistNewEntitiesBatch(meta, changeSets, options) {
|
|
127
|
-
options = this.
|
|
152
|
+
options = this.prepareOptions(meta, options, {
|
|
128
153
|
convertCustomTypes: false,
|
|
129
154
|
processCollections: false,
|
|
130
155
|
});
|
|
131
|
-
const res = await this.driver.nativeInsertMany(meta.
|
|
156
|
+
const res = await this.driver.nativeInsertMany(meta.class, changeSets.map(cs => cs.payload), options);
|
|
132
157
|
for (let i = 0; i < changeSets.length; i++) {
|
|
133
158
|
const changeSet = changeSets[i];
|
|
134
159
|
const wrapped = helper(changeSet.entity);
|
|
@@ -146,7 +171,7 @@ export class ChangeSetPersister {
|
|
|
146
171
|
}
|
|
147
172
|
}
|
|
148
173
|
async persistManagedEntity(changeSet, options) {
|
|
149
|
-
const meta =
|
|
174
|
+
const meta = changeSet.meta;
|
|
150
175
|
const res = await this.updateEntity(meta, changeSet, options);
|
|
151
176
|
this.checkOptimisticLock(meta, changeSet, res);
|
|
152
177
|
this.mapReturnedValues(changeSet.entity, changeSet.payload, res.row, meta);
|
|
@@ -175,7 +200,7 @@ export class ChangeSetPersister {
|
|
|
175
200
|
}
|
|
176
201
|
async persistManagedEntitiesBatch(meta, changeSets, options) {
|
|
177
202
|
await this.checkOptimisticLocks(meta, changeSets, options);
|
|
178
|
-
options = this.
|
|
203
|
+
options = this.prepareOptions(meta, options, {
|
|
179
204
|
convertCustomTypes: false,
|
|
180
205
|
processCollections: false,
|
|
181
206
|
});
|
|
@@ -187,7 +212,7 @@ export class ChangeSetPersister {
|
|
|
187
212
|
cond.push(where);
|
|
188
213
|
payload.push(changeSet.payload);
|
|
189
214
|
}
|
|
190
|
-
const res = await this.driver.nativeUpdateMany(meta.
|
|
215
|
+
const res = await this.driver.nativeUpdateMany(meta.class, cond, payload, options);
|
|
191
216
|
const map = new Map();
|
|
192
217
|
res.rows?.forEach(item => map.set(Utils.getCompositeKeyHash(item, meta, true, this.platform, true), item));
|
|
193
218
|
for (const changeSet of changeSets) {
|
|
@@ -210,7 +235,9 @@ export class ChangeSetPersister {
|
|
|
210
235
|
// of using the raw value from db, we convert it back to the db value explicitly
|
|
211
236
|
value = prop.customType ? prop.customType.convertToDatabaseValue(insertId, this.platform, { mode: 'serialization' }) : value;
|
|
212
237
|
changeSet.payload[wrapped.__meta.primaryKeys[0]] = value;
|
|
213
|
-
wrapped.__identifier
|
|
238
|
+
if (wrapped.__identifier && !Array.isArray(wrapped.__identifier)) {
|
|
239
|
+
wrapped.__identifier.setValue(value);
|
|
240
|
+
}
|
|
214
241
|
}
|
|
215
242
|
/**
|
|
216
243
|
* Sets populate flag to new entities so they are serialized like if they were loaded from the db
|
|
@@ -233,17 +260,17 @@ export class ChangeSetPersister {
|
|
|
233
260
|
}
|
|
234
261
|
async updateEntity(meta, changeSet, options) {
|
|
235
262
|
const cond = changeSet.getPrimaryKey(true);
|
|
236
|
-
options = this.
|
|
263
|
+
options = this.prepareOptions(meta, options, {
|
|
237
264
|
convertCustomTypes: false,
|
|
238
265
|
});
|
|
239
266
|
if (meta.concurrencyCheckKeys.size === 0 && (!meta.versionProperty || changeSet.entity[meta.versionProperty] == null)) {
|
|
240
|
-
return this.driver.nativeUpdate(changeSet.
|
|
267
|
+
return this.driver.nativeUpdate(changeSet.meta.class, cond, changeSet.payload, options);
|
|
241
268
|
}
|
|
242
269
|
if (meta.versionProperty) {
|
|
243
270
|
cond[meta.versionProperty] = this.platform.quoteVersionValue(changeSet.entity[meta.versionProperty], meta.properties[meta.versionProperty]);
|
|
244
271
|
}
|
|
245
272
|
this.checkConcurrencyKeys(meta, changeSet, cond);
|
|
246
|
-
return this.driver.nativeUpdate(changeSet.
|
|
273
|
+
return this.driver.nativeUpdate(changeSet.meta.class, cond, changeSet.payload, options);
|
|
247
274
|
}
|
|
248
275
|
async checkOptimisticLocks(meta, changeSets, options) {
|
|
249
276
|
if (meta.concurrencyCheckKeys.size === 0 && (!meta.versionProperty || changeSets.every(cs => cs.entity[meta.versionProperty] == null))) {
|
|
@@ -260,10 +287,10 @@ export class ChangeSetPersister {
|
|
|
260
287
|
return cond;
|
|
261
288
|
});
|
|
262
289
|
const primaryKeys = meta.primaryKeys.concat(...meta.concurrencyCheckKeys);
|
|
263
|
-
options = this.
|
|
290
|
+
options = this.prepareOptions(meta, options, {
|
|
264
291
|
fields: primaryKeys,
|
|
265
292
|
});
|
|
266
|
-
const res = await this.driver.find(meta.root.
|
|
293
|
+
const res = await this.driver.find(meta.root.class, { $or }, options);
|
|
267
294
|
if (res.length !== changeSets.length) {
|
|
268
295
|
const compare = (a, b, keys) => keys.every(k => a[k] === b[k]);
|
|
269
296
|
const entity = changeSets.find(cs => {
|
|
@@ -284,11 +311,22 @@ export class ChangeSetPersister {
|
|
|
284
311
|
async reloadVersionValues(meta, changeSets, options) {
|
|
285
312
|
const reloadProps = meta.versionProperty && !this.usesReturningStatement ? [meta.properties[meta.versionProperty]] : [];
|
|
286
313
|
if (changeSets[0].type === ChangeSetType.CREATE) {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
.
|
|
314
|
+
for (const prop of meta.props) {
|
|
315
|
+
if (prop.persist === false) {
|
|
316
|
+
continue;
|
|
317
|
+
}
|
|
318
|
+
if (isRaw(changeSets[0].entity[prop.name])) {
|
|
319
|
+
reloadProps.push(prop);
|
|
320
|
+
continue;
|
|
321
|
+
}
|
|
322
|
+
// do not reload things that already had a runtime value
|
|
323
|
+
if (changeSets[0].entity[prop.name] != null || prop.defaultRaw === 'null') {
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
if (prop.autoincrement || prop.generated || prop.defaultRaw) {
|
|
327
|
+
reloadProps.push(prop);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
292
330
|
}
|
|
293
331
|
if (changeSets[0].type === ChangeSetType.UPDATE) {
|
|
294
332
|
const returning = new Set();
|
|
@@ -319,12 +357,12 @@ export class ChangeSetPersister {
|
|
|
319
357
|
}
|
|
320
358
|
return val;
|
|
321
359
|
});
|
|
322
|
-
options = this.
|
|
360
|
+
options = this.prepareOptions(meta, options, {
|
|
323
361
|
fields: Utils.unique(reloadProps.map(prop => prop.name)),
|
|
324
362
|
});
|
|
325
|
-
const data = await this.driver.find(meta.
|
|
363
|
+
const data = await this.driver.find(meta.class, { [pk]: { $in: pks } }, options);
|
|
326
364
|
const map = new Map();
|
|
327
|
-
data.forEach(item => map.set(Utils.getCompositeKeyHash(item, meta,
|
|
365
|
+
data.forEach(item => map.set(Utils.getCompositeKeyHash(item, meta, false, this.platform, true), item));
|
|
328
366
|
for (const changeSet of changeSets) {
|
|
329
367
|
const data = map.get(helper(changeSet.entity).getSerializedPrimaryKey());
|
|
330
368
|
this.hydrator.hydrate(changeSet.entity, meta, data, this.factory, 'full', false, true);
|
|
@@ -332,12 +370,16 @@ export class ChangeSetPersister {
|
|
|
332
370
|
}
|
|
333
371
|
}
|
|
334
372
|
processProperty(changeSet, prop) {
|
|
335
|
-
const meta =
|
|
373
|
+
const meta = changeSet.meta;
|
|
336
374
|
const value = changeSet.payload[prop.name]; // for inline embeddables
|
|
337
375
|
if (value instanceof EntityIdentifier) {
|
|
338
376
|
changeSet.payload[prop.name] = value.getValue();
|
|
339
377
|
return;
|
|
340
378
|
}
|
|
379
|
+
if (Array.isArray(value) && value.every(item => item instanceof EntityIdentifier)) {
|
|
380
|
+
changeSet.payload[prop.name] = value.map(item => item.getValue());
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
341
383
|
if (prop.kind === ReferenceKind.MANY_TO_MANY && Array.isArray(value)) {
|
|
342
384
|
changeSet.payload[prop.name] = value.map(val => val instanceof EntityIdentifier ? val.getValue() : val);
|
|
343
385
|
return;
|
|
@@ -361,7 +403,7 @@ export class ChangeSetPersister {
|
|
|
361
403
|
if ((!this.usesReturningStatement && !upsert) || !row || !Utils.hasObjectKeys(row)) {
|
|
362
404
|
return;
|
|
363
405
|
}
|
|
364
|
-
const mapped = this.comparator.mapResult(meta
|
|
406
|
+
const mapped = this.comparator.mapResult(meta, row);
|
|
365
407
|
if (entity) {
|
|
366
408
|
this.hydrator.hydrate(entity, meta, mapped, this.factory, 'full', false, true);
|
|
367
409
|
}
|
|
@@ -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
|
/**
|
|
@@ -32,23 +33,23 @@ export declare class CommitOrderCalculator {
|
|
|
32
33
|
/**
|
|
33
34
|
* Checks for node existence in graph.
|
|
34
35
|
*/
|
|
35
|
-
hasNode(hash:
|
|
36
|
+
hasNode(hash: Hash): boolean;
|
|
36
37
|
/**
|
|
37
38
|
* Adds a new node to the graph, assigning its hash.
|
|
38
39
|
*/
|
|
39
|
-
addNode(hash:
|
|
40
|
+
addNode(hash: Hash): void;
|
|
40
41
|
/**
|
|
41
42
|
* Adds a new dependency (edge) to the graph using their hashes.
|
|
42
43
|
*/
|
|
43
|
-
addDependency(from:
|
|
44
|
-
discoverProperty(prop: EntityProperty, entityName:
|
|
44
|
+
addDependency(from: Hash, to: Hash, weight: number): void;
|
|
45
|
+
discoverProperty(prop: EntityProperty, entityName: Hash): void;
|
|
45
46
|
/**
|
|
46
47
|
* Return a valid order list of all current nodes.
|
|
47
48
|
* The desired topological sorting is the reverse post order of these searches.
|
|
48
49
|
*
|
|
49
50
|
* @internal Highly performance-sensitive method.
|
|
50
51
|
*/
|
|
51
|
-
sort():
|
|
52
|
+
sort(): Hash[];
|
|
52
53
|
/**
|
|
53
54
|
* Visit a given node definition for reordering.
|
|
54
55
|
*
|
|
@@ -60,3 +61,4 @@ export declare class CommitOrderCalculator {
|
|
|
60
61
|
*/
|
|
61
62
|
private visitOpenNode;
|
|
62
63
|
}
|
|
64
|
+
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
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.nodes
|
|
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.nodes
|
|
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,14 +57,14 @@ 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
66
|
const sortedList = this.sortedNodeList.reverse();
|
|
67
|
-
this.nodes =
|
|
67
|
+
this.nodes = new Map();
|
|
68
68
|
this.sortedNodeList = [];
|
|
69
69
|
return sortedList;
|
|
70
70
|
}
|
|
@@ -75,8 +75,8 @@ 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.nodes
|
|
78
|
+
for (const edge of node.dependencies.values()) {
|
|
79
|
+
const target = this.nodes.get(edge.to);
|
|
80
80
|
switch (target.state) {
|
|
81
81
|
case 2 /* NodeState.VISITED */: break; // Do nothing, since node was already visited
|
|
82
82
|
case 1 /* NodeState.IN_PROGRESS */:
|
|
@@ -94,11 +94,11 @@ export class CommitOrderCalculator {
|
|
|
94
94
|
* Visits all target's dependencies if in cycle with given node
|
|
95
95
|
*/
|
|
96
96
|
visitOpenNode(node, target, edge) {
|
|
97
|
-
if (!target.dependencies
|
|
97
|
+
if (!target.dependencies.has(node.hash) || target.dependencies.get(node.hash).weight >= edge.weight) {
|
|
98
98
|
return;
|
|
99
99
|
}
|
|
100
|
-
for (const edge of
|
|
101
|
-
const targetNode = this.nodes
|
|
100
|
+
for (const edge of target.dependencies.values()) {
|
|
101
|
+
const targetNode = this.nodes.get(edge.to);
|
|
102
102
|
if (targetNode.state === 0 /* NodeState.NOT_VISITED */) {
|
|
103
103
|
this.visit(targetNode);
|
|
104
104
|
}
|
|
@@ -3,7 +3,14 @@ export declare class IdentityMap {
|
|
|
3
3
|
private readonly defaultSchema?;
|
|
4
4
|
constructor(defaultSchema?: string | undefined);
|
|
5
5
|
private readonly registry;
|
|
6
|
+
/** Tracks alternate key hashes for each entity so we can clean them up on delete */
|
|
7
|
+
private readonly alternateKeys;
|
|
6
8
|
store<T>(item: T): void;
|
|
9
|
+
/**
|
|
10
|
+
* Stores an entity under an alternate key (non-PK property).
|
|
11
|
+
* This allows looking up entities by unique properties that are not the primary key.
|
|
12
|
+
*/
|
|
13
|
+
storeByKey<T>(item: T, key: string, value: string, schema?: string): void;
|
|
7
14
|
delete<T>(item: T): void;
|
|
8
15
|
getByHash<T>(meta: EntityMetadata<T>, hash: string): T | undefined;
|
|
9
16
|
getStore<T>(meta: EntityMetadata<T>): Map<string, T>;
|
|
@@ -16,4 +23,9 @@ export declare class IdentityMap {
|
|
|
16
23
|
*/
|
|
17
24
|
get<T>(hash: string): T | undefined;
|
|
18
25
|
private getPkHash;
|
|
26
|
+
/**
|
|
27
|
+
* Creates a hash for an alternate key lookup.
|
|
28
|
+
* Format: `[key]value` or `schema:[key]value`
|
|
29
|
+
*/
|
|
30
|
+
getKeyHash(key: string, value: string, schema?: string): string;
|
|
19
31
|
}
|
|
@@ -4,11 +4,38 @@ export class IdentityMap {
|
|
|
4
4
|
this.defaultSchema = defaultSchema;
|
|
5
5
|
}
|
|
6
6
|
registry = new Map();
|
|
7
|
+
/** Tracks alternate key hashes for each entity so we can clean them up on delete */
|
|
8
|
+
alternateKeys = new WeakMap();
|
|
7
9
|
store(item) {
|
|
8
10
|
this.getStore(item.__meta.root).set(this.getPkHash(item), item);
|
|
9
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* Stores an entity under an alternate key (non-PK property).
|
|
14
|
+
* This allows looking up entities by unique properties that are not the primary key.
|
|
15
|
+
*/
|
|
16
|
+
storeByKey(item, key, value, schema) {
|
|
17
|
+
const hash = this.getKeyHash(key, value, schema);
|
|
18
|
+
this.getStore(item.__meta.root).set(hash, item);
|
|
19
|
+
// Track this alternate key so we can clean it up when the entity is deleted
|
|
20
|
+
let keys = this.alternateKeys.get(item);
|
|
21
|
+
if (!keys) {
|
|
22
|
+
keys = new Set();
|
|
23
|
+
this.alternateKeys.set(item, keys);
|
|
24
|
+
}
|
|
25
|
+
keys.add(hash);
|
|
26
|
+
}
|
|
10
27
|
delete(item) {
|
|
11
|
-
|
|
28
|
+
const meta = item.__meta.root;
|
|
29
|
+
const store = this.getStore(meta);
|
|
30
|
+
store.delete(this.getPkHash(item));
|
|
31
|
+
// Also delete any alternate key entries for this entity
|
|
32
|
+
const altKeys = this.alternateKeys.get(item);
|
|
33
|
+
if (altKeys) {
|
|
34
|
+
for (const hash of altKeys) {
|
|
35
|
+
store.delete(hash);
|
|
36
|
+
}
|
|
37
|
+
this.alternateKeys.delete(item);
|
|
38
|
+
}
|
|
12
39
|
}
|
|
13
40
|
getByHash(meta, hash) {
|
|
14
41
|
const store = this.getStore(meta);
|
|
@@ -69,4 +96,15 @@ export class IdentityMap {
|
|
|
69
96
|
}
|
|
70
97
|
return hash;
|
|
71
98
|
}
|
|
99
|
+
/**
|
|
100
|
+
* Creates a hash for an alternate key lookup.
|
|
101
|
+
* Format: `[key]value` or `schema:[key]value`
|
|
102
|
+
*/
|
|
103
|
+
getKeyHash(key, value, schema) {
|
|
104
|
+
const hash = `[${key}]${value}`;
|
|
105
|
+
if (schema) {
|
|
106
|
+
return schema + ':' + hash;
|
|
107
|
+
}
|
|
108
|
+
return hash;
|
|
109
|
+
}
|
|
72
110
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AnyEntity, EntityData, EntityMetadata, EntityProperty, FilterQuery, Primary } from '../typings.js';
|
|
1
|
+
import type { AnyEntity, EntityData, EntityMetadata, EntityName, EntityProperty, FilterQuery, Primary } from '../typings.js';
|
|
2
2
|
import { Collection } from '../entity/Collection.js';
|
|
3
3
|
import { Reference } from '../entity/Reference.js';
|
|
4
4
|
import { ChangeSet, ChangeSetType } from './ChangeSet.js';
|
|
@@ -28,6 +28,12 @@ export declare class UnitOfWork {
|
|
|
28
28
|
private working;
|
|
29
29
|
constructor(em: EntityManager);
|
|
30
30
|
merge<T extends object>(entity: T, visited?: Set<AnyEntity>): void;
|
|
31
|
+
/**
|
|
32
|
+
* Entity data can wary in its shape, e.g. we might get a deep relation graph with joined strategy, but for diffing,
|
|
33
|
+
* we need to normalize the shape, so relation values are only raw FKs. This method handles that.
|
|
34
|
+
* @internal
|
|
35
|
+
*/
|
|
36
|
+
normalizeEntityData<T extends object>(meta: EntityMetadata<T>, data: EntityData<T>): void;
|
|
31
37
|
/**
|
|
32
38
|
* @internal
|
|
33
39
|
*/
|
|
@@ -39,8 +45,21 @@ export declare class UnitOfWork {
|
|
|
39
45
|
/**
|
|
40
46
|
* 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`.
|
|
41
47
|
*/
|
|
42
|
-
getById<T extends object>(entityName:
|
|
43
|
-
|
|
48
|
+
getById<T extends object>(entityName: EntityName<T>, id: Primary<T> | Primary<T>[], schema?: string, convertCustomTypes?: boolean): T | undefined;
|
|
49
|
+
/**
|
|
50
|
+
* Returns entity from the identity map by an alternate key (non-PK property).
|
|
51
|
+
* @param convertCustomTypes - If true, the value is in database format and will be converted to JS format for lookup.
|
|
52
|
+
* If false (default), the value is assumed to be in JS format already.
|
|
53
|
+
*/
|
|
54
|
+
getByKey<T extends object>(entityName: EntityName<T>, key: string, value: unknown, schema?: string, convertCustomTypes?: boolean): T | undefined;
|
|
55
|
+
/**
|
|
56
|
+
* Stores an entity in the identity map under an alternate key (non-PK property).
|
|
57
|
+
* Also sets the property value on the entity.
|
|
58
|
+
* @param convertCustomTypes - If true, the value is in database format and will be converted to JS format.
|
|
59
|
+
* If false (default), the value is assumed to be in JS format already.
|
|
60
|
+
*/
|
|
61
|
+
storeByKey<T extends object>(entity: T, key: string, value: unknown, schema?: string, convertCustomTypes?: boolean): void;
|
|
62
|
+
tryGetById<T extends object>(entityName: EntityName<T>, where: FilterQuery<T>, schema?: string, strict?: boolean): T | null;
|
|
44
63
|
/**
|
|
45
64
|
* Returns map of all managed entities.
|
|
46
65
|
*/
|
|
@@ -103,6 +122,7 @@ export declare class UnitOfWork {
|
|
|
103
122
|
private commitDeleteChangeSets;
|
|
104
123
|
private commitExtraUpdates;
|
|
105
124
|
private commitCollectionUpdates;
|
|
125
|
+
private filterCollectionUpdates;
|
|
106
126
|
/**
|
|
107
127
|
* Orders change sets so FK constrains are maintained, ensures stable order (needed for node < 11)
|
|
108
128
|
*/
|