@mikro-orm/core 7.0.0-rc.3 → 7.0.1-dev.0
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 +2 -15
- package/EntityManager.js +155 -152
- package/MikroORM.d.ts +4 -6
- package/MikroORM.js +20 -20
- package/README.md +5 -4
- package/cache/FileCacheAdapter.d.ts +1 -5
- package/cache/FileCacheAdapter.js +22 -22
- package/cache/GeneratedCacheAdapter.d.ts +1 -1
- package/cache/GeneratedCacheAdapter.js +6 -6
- package/cache/MemoryCacheAdapter.d.ts +1 -2
- package/cache/MemoryCacheAdapter.js +8 -8
- package/cache/index.d.ts +1 -1
- package/cache/index.js +0 -1
- package/connections/Connection.d.ts +1 -0
- package/connections/Connection.js +27 -11
- package/drivers/DatabaseDriver.d.ts +0 -2
- package/drivers/DatabaseDriver.js +2 -4
- package/entity/Collection.d.ts +1 -9
- package/entity/Collection.js +95 -105
- package/entity/EntityFactory.d.ts +1 -8
- package/entity/EntityFactory.js +48 -48
- package/entity/EntityLoader.d.ts +1 -3
- package/entity/EntityLoader.js +36 -39
- package/entity/Reference.d.ts +1 -2
- package/entity/Reference.js +11 -11
- package/entity/WrappedEntity.d.ts +4 -2
- package/entity/defineEntity.d.ts +18 -73
- package/enums.d.ts +2 -1
- package/enums.js +1 -0
- package/errors.d.ts +11 -11
- package/errors.js +3 -13
- package/events/EventManager.d.ts +1 -4
- package/events/EventManager.js +25 -22
- package/events/index.d.ts +1 -1
- package/events/index.js +0 -1
- package/exceptions.js +8 -6
- package/hydration/ObjectHydrator.d.ts +1 -2
- package/hydration/ObjectHydrator.js +16 -16
- package/logging/DefaultLogger.js +3 -2
- package/logging/Logger.d.ts +2 -1
- package/logging/colors.js +1 -1
- package/logging/index.d.ts +1 -1
- package/logging/index.js +0 -1
- package/metadata/EntitySchema.d.ts +1 -1
- package/metadata/MetadataDiscovery.d.ts +1 -9
- package/metadata/MetadataDiscovery.js +162 -149
- package/metadata/MetadataStorage.d.ts +1 -5
- package/metadata/MetadataStorage.js +36 -36
- package/metadata/discover-entities.js +1 -1
- package/metadata/index.d.ts +1 -1
- package/metadata/index.js +0 -1
- package/naming-strategy/AbstractNamingStrategy.js +1 -1
- package/naming-strategy/EntityCaseNamingStrategy.js +1 -1
- package/naming-strategy/index.d.ts +1 -1
- package/naming-strategy/index.js +0 -1
- package/package.json +1 -1
- package/platforms/Platform.d.ts +23 -1
- package/platforms/Platform.js +57 -4
- package/serialization/EntitySerializer.js +1 -1
- package/serialization/EntityTransformer.js +4 -1
- package/serialization/SerializationContext.d.ts +4 -8
- package/serialization/SerializationContext.js +20 -15
- package/types/UuidType.d.ts +2 -0
- package/types/UuidType.js +14 -2
- package/types/index.d.ts +2 -1
- package/typings.d.ts +12 -1
- package/unit-of-work/ChangeSetComputer.d.ts +1 -6
- package/unit-of-work/ChangeSetComputer.js +21 -21
- package/unit-of-work/ChangeSetPersister.d.ts +1 -9
- package/unit-of-work/ChangeSetPersister.js +52 -52
- package/unit-of-work/CommitOrderCalculator.d.ts +1 -4
- package/unit-of-work/CommitOrderCalculator.js +13 -13
- package/unit-of-work/IdentityMap.d.ts +2 -5
- package/unit-of-work/IdentityMap.js +18 -18
- package/unit-of-work/UnitOfWork.d.ts +5 -19
- package/unit-of-work/UnitOfWork.js +182 -174
- package/utils/AbstractMigrator.d.ts +1 -1
- package/utils/AbstractMigrator.js +7 -7
- package/utils/Configuration.d.ts +90 -189
- package/utils/Configuration.js +94 -78
- package/utils/Cursor.d.ts +3 -3
- package/utils/Cursor.js +4 -4
- package/utils/EntityComparator.d.ts +8 -15
- package/utils/EntityComparator.js +49 -49
- package/utils/QueryHelper.d.ts +16 -1
- package/utils/QueryHelper.js +70 -24
- package/utils/RawQueryFragment.d.ts +4 -4
- package/utils/TransactionManager.js +1 -2
- package/utils/Utils.d.ts +1 -1
- package/utils/Utils.js +5 -4
- package/utils/clone.js +5 -0
- package/utils/fs-utils.d.ts +3 -17
- package/utils/fs-utils.js +1 -1
- package/utils/upsert-utils.js +1 -1
|
@@ -7,22 +7,22 @@ import { Reference } from '../entity/Reference.js';
|
|
|
7
7
|
import { PolymorphicRef } from '../entity/PolymorphicRef.js';
|
|
8
8
|
import { ReferenceKind } from '../enums.js';
|
|
9
9
|
export class ChangeSetComputer {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
#comparator;
|
|
11
|
+
#metadata;
|
|
12
|
+
#platform;
|
|
13
|
+
#config;
|
|
14
|
+
#em;
|
|
15
|
+
#collectionUpdates;
|
|
16
16
|
constructor(em, collectionUpdates) {
|
|
17
|
-
this
|
|
18
|
-
this
|
|
19
|
-
this
|
|
20
|
-
this
|
|
21
|
-
this
|
|
22
|
-
this
|
|
17
|
+
this.#em = em;
|
|
18
|
+
this.#collectionUpdates = collectionUpdates;
|
|
19
|
+
this.#config = this.#em.config;
|
|
20
|
+
this.#metadata = this.#em.getMetadata();
|
|
21
|
+
this.#platform = this.#em.getPlatform();
|
|
22
|
+
this.#comparator = this.#config.getComparator(this.#metadata);
|
|
23
23
|
}
|
|
24
24
|
computeChangeSet(entity) {
|
|
25
|
-
const meta = this
|
|
25
|
+
const meta = this.#metadata.get(entity.constructor);
|
|
26
26
|
if (meta.readonly) {
|
|
27
27
|
return null;
|
|
28
28
|
}
|
|
@@ -38,7 +38,7 @@ export class ChangeSetComputer {
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
if (type === ChangeSetType.UPDATE && !wrapped.__initialized) {
|
|
41
|
-
const data = this
|
|
41
|
+
const data = this.#comparator.prepareEntity(entity);
|
|
42
42
|
if (Utils.equals(data, wrapped.__originalEntityData)) {
|
|
43
43
|
return null;
|
|
44
44
|
}
|
|
@@ -79,11 +79,11 @@ export class ChangeSetComputer {
|
|
|
79
79
|
type === ChangeSetType.CREATE &&
|
|
80
80
|
(entity[prop.name] == null ||
|
|
81
81
|
(Utils.isScalarReference(entity[prop.name]) && entity[prop.name].unwrap() == null))) {
|
|
82
|
-
entity[prop.name] = prop.onCreate(entity, this
|
|
82
|
+
entity[prop.name] = prop.onCreate(entity, this.#em);
|
|
83
83
|
}
|
|
84
84
|
if (prop.onUpdate && type === ChangeSetType.UPDATE) {
|
|
85
85
|
const pairs = map.get(entity) ?? [];
|
|
86
|
-
pairs.push([prop.name, prop.onUpdate(entity, this
|
|
86
|
+
pairs.push([prop.name, prop.onUpdate(entity, this.#em)]);
|
|
87
87
|
map.set(entity, pairs);
|
|
88
88
|
}
|
|
89
89
|
if (prop.kind === ReferenceKind.EMBEDDED && entity[prop.name]) {
|
|
@@ -93,7 +93,7 @@ export class ChangeSetComputer {
|
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
95
|
computePayload(entity, ignoreUndefined = false) {
|
|
96
|
-
const data = this
|
|
96
|
+
const data = this.#comparator.prepareEntity(entity);
|
|
97
97
|
const wrapped = helper(entity);
|
|
98
98
|
const entityName = wrapped.__meta.class;
|
|
99
99
|
const originalEntityData = wrapped.__originalEntityData;
|
|
@@ -104,7 +104,7 @@ export class ChangeSetComputer {
|
|
|
104
104
|
return data;
|
|
105
105
|
}
|
|
106
106
|
if (originalEntityData) {
|
|
107
|
-
const comparator = this
|
|
107
|
+
const comparator = this.#comparator.getEntityComparator(entityName);
|
|
108
108
|
const diff = comparator(originalEntityData, data);
|
|
109
109
|
if (ignoreUndefined) {
|
|
110
110
|
Utils.keys(diff)
|
|
@@ -144,7 +144,7 @@ export class ChangeSetComputer {
|
|
|
144
144
|
if (prop.targetKey && prop.targetMeta) {
|
|
145
145
|
const targetProp = prop.targetMeta.properties[prop.targetKey];
|
|
146
146
|
if (targetProp?.customType) {
|
|
147
|
-
value = targetProp.customType.convertToDatabaseValue(value, this
|
|
147
|
+
value = targetProp.customType.convertToDatabaseValue(value, this.#platform, { mode: 'serialization' });
|
|
148
148
|
}
|
|
149
149
|
}
|
|
150
150
|
if (prop.polymorphic) {
|
|
@@ -163,9 +163,9 @@ export class ChangeSetComputer {
|
|
|
163
163
|
return;
|
|
164
164
|
}
|
|
165
165
|
if (target.isDirty()) {
|
|
166
|
-
this
|
|
166
|
+
this.#collectionUpdates.add(target);
|
|
167
167
|
}
|
|
168
|
-
if (prop.owner && !this
|
|
168
|
+
if (prop.owner && !this.#platform.usesPivotTable()) {
|
|
169
169
|
changeSet.payload[prop.name] = target.getItems(false).map((item) => {
|
|
170
170
|
return item.__helper.__identifier ?? item.__helper.getPrimaryKey();
|
|
171
171
|
});
|
|
@@ -3,15 +3,7 @@ import { type ChangeSet } from './ChangeSet.js';
|
|
|
3
3
|
import type { DriverMethodOptions } from '../drivers/IDatabaseDriver.js';
|
|
4
4
|
import type { EntityManager } from '../EntityManager.js';
|
|
5
5
|
export declare class ChangeSetPersister {
|
|
6
|
-
private
|
|
7
|
-
private readonly platform;
|
|
8
|
-
private readonly comparator;
|
|
9
|
-
private readonly usesReturningStatement;
|
|
10
|
-
private readonly driver;
|
|
11
|
-
private readonly metadata;
|
|
12
|
-
private readonly hydrator;
|
|
13
|
-
private readonly factory;
|
|
14
|
-
private readonly config;
|
|
6
|
+
#private;
|
|
15
7
|
constructor(em: EntityManager);
|
|
16
8
|
executeInserts<T extends object>(changeSets: ChangeSet<T>[], options?: DriverMethodOptions, withSchema?: boolean): Promise<void>;
|
|
17
9
|
executeUpdates<T extends object>(changeSets: ChangeSet<T>[], batched: boolean, options?: DriverMethodOptions, withSchema?: boolean): Promise<void>;
|
|
@@ -7,25 +7,25 @@ import { Utils } from '../utils/Utils.js';
|
|
|
7
7
|
import { OptimisticLockError, ValidationError } from '../errors.js';
|
|
8
8
|
import { ReferenceKind } from '../enums.js';
|
|
9
9
|
export class ChangeSetPersister {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
10
|
+
#platform;
|
|
11
|
+
#comparator;
|
|
12
|
+
#usesReturningStatement;
|
|
13
|
+
#driver;
|
|
14
|
+
#metadata;
|
|
15
|
+
#hydrator;
|
|
16
|
+
#factory;
|
|
17
|
+
#config;
|
|
18
|
+
#em;
|
|
19
19
|
constructor(em) {
|
|
20
|
-
this
|
|
21
|
-
this
|
|
22
|
-
this
|
|
23
|
-
this
|
|
24
|
-
this
|
|
25
|
-
this
|
|
26
|
-
this
|
|
27
|
-
this
|
|
28
|
-
this
|
|
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();
|
|
29
29
|
}
|
|
30
30
|
async executeInserts(changeSets, options, withSchema) {
|
|
31
31
|
if (!withSchema) {
|
|
@@ -33,7 +33,7 @@ export class ChangeSetPersister {
|
|
|
33
33
|
}
|
|
34
34
|
const meta = changeSets[0].meta;
|
|
35
35
|
changeSets.forEach(changeSet => this.processProperties(changeSet));
|
|
36
|
-
if (changeSets.length > 1 && this
|
|
36
|
+
if (changeSets.length > 1 && this.#config.get('useBatchInserts', this.#platform.usesBatchInserts())) {
|
|
37
37
|
return this.persistNewEntities(meta, changeSets, options);
|
|
38
38
|
}
|
|
39
39
|
for (const changeSet of changeSets) {
|
|
@@ -52,7 +52,7 @@ export class ChangeSetPersister {
|
|
|
52
52
|
if (batched &&
|
|
53
53
|
changeSets.length > 1 &&
|
|
54
54
|
!hasMixedTypes &&
|
|
55
|
-
this
|
|
55
|
+
this.#config.get('useBatchUpdates', this.#platform.usesBatchUpdates())) {
|
|
56
56
|
return this.persistManagedEntities(meta, changeSets, options);
|
|
57
57
|
}
|
|
58
58
|
for (const changeSet of changeSets) {
|
|
@@ -63,14 +63,14 @@ export class ChangeSetPersister {
|
|
|
63
63
|
if (!withSchema) {
|
|
64
64
|
return this.runForEachSchema(changeSets, 'executeDeletes', options);
|
|
65
65
|
}
|
|
66
|
-
const size = this
|
|
66
|
+
const size = this.#config.get('batchSize');
|
|
67
67
|
const meta = changeSets[0].meta;
|
|
68
68
|
const pk = Utils.getPrimaryKeyHash(meta.primaryKeys);
|
|
69
69
|
for (let i = 0; i < changeSets.length; i += size) {
|
|
70
70
|
const chunk = changeSets.slice(i, i + size);
|
|
71
71
|
const pks = chunk.map(cs => cs.getPrimaryKey());
|
|
72
72
|
options = this.prepareOptions(meta, options);
|
|
73
|
-
await this
|
|
73
|
+
await this.#driver.nativeDelete(meta.root.class, { [pk]: { $in: pks } }, options);
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
async runForEachSchema(changeSets, method, options, ...args) {
|
|
@@ -110,7 +110,7 @@ export class ChangeSetPersister {
|
|
|
110
110
|
for (const prop of meta.relations) {
|
|
111
111
|
this.processProperty(changeSet, prop);
|
|
112
112
|
}
|
|
113
|
-
if (changeSet.type === ChangeSetType.CREATE && this
|
|
113
|
+
if (changeSet.type === ChangeSetType.CREATE && this.#config.get('validateRequired')) {
|
|
114
114
|
this.validateRequired(changeSet.entity);
|
|
115
115
|
}
|
|
116
116
|
}
|
|
@@ -121,31 +121,31 @@ export class ChangeSetPersister {
|
|
|
121
121
|
});
|
|
122
122
|
this.resolveTPTIdentifiers(changeSet);
|
|
123
123
|
// Use changeSet's own meta for STI entities to get correct field mappings
|
|
124
|
-
const res = await this
|
|
124
|
+
const res = await this.#driver.nativeInsertMany(changeSet.meta.class, [changeSet.payload], options);
|
|
125
125
|
if (!wrapped.hasPrimaryKey()) {
|
|
126
|
-
this.mapPrimaryKey(meta, res.insertId, changeSet);
|
|
126
|
+
this.mapPrimaryKey(meta, res.insertId ?? res.row?.[meta.primaryKeys[0]], changeSet);
|
|
127
127
|
}
|
|
128
128
|
this.mapReturnedValues(changeSet.entity, changeSet.payload, res.row, meta);
|
|
129
129
|
this.markAsPopulated(changeSet, meta);
|
|
130
130
|
wrapped.__initialized = true;
|
|
131
131
|
wrapped.__managed = true;
|
|
132
|
-
if (!this
|
|
132
|
+
if (!this.#usesReturningStatement) {
|
|
133
133
|
await this.reloadVersionValues(meta, [changeSet], options);
|
|
134
134
|
}
|
|
135
135
|
changeSet.persisted = true;
|
|
136
136
|
}
|
|
137
137
|
async persistNewEntities(meta, changeSets, options) {
|
|
138
|
-
const size = this
|
|
138
|
+
const size = this.#config.get('batchSize');
|
|
139
139
|
for (let i = 0; i < changeSets.length; i += size) {
|
|
140
140
|
const chunk = changeSets.slice(i, i + size);
|
|
141
141
|
await this.persistNewEntitiesBatch(meta, chunk, options);
|
|
142
|
-
if (!this
|
|
142
|
+
if (!this.#usesReturningStatement) {
|
|
143
143
|
await this.reloadVersionValues(meta, chunk, options);
|
|
144
144
|
}
|
|
145
145
|
}
|
|
146
146
|
}
|
|
147
147
|
prepareOptions(meta, options, additionalOptions) {
|
|
148
|
-
const loggerContext = Utils.merge({ id: this
|
|
148
|
+
const loggerContext = Utils.merge({ id: this.#em._id }, this.#em.getLoggerContext({ disableContextResolution: true }));
|
|
149
149
|
return {
|
|
150
150
|
...options,
|
|
151
151
|
...additionalOptions,
|
|
@@ -161,7 +161,7 @@ export class ChangeSetPersister {
|
|
|
161
161
|
for (const changeSet of changeSets) {
|
|
162
162
|
this.resolveTPTIdentifiers(changeSet);
|
|
163
163
|
}
|
|
164
|
-
const res = await this
|
|
164
|
+
const res = await this.#driver.nativeInsertMany(meta.class, changeSets.map(cs => cs.payload), options);
|
|
165
165
|
for (let i = 0; i < changeSets.length; i++) {
|
|
166
166
|
const changeSet = changeSets[i];
|
|
167
167
|
const wrapped = helper(changeSet.entity);
|
|
@@ -187,7 +187,7 @@ export class ChangeSetPersister {
|
|
|
187
187
|
changeSet.persisted = true;
|
|
188
188
|
}
|
|
189
189
|
async persistManagedEntities(meta, changeSets, options) {
|
|
190
|
-
const size = this
|
|
190
|
+
const size = this.#config.get('batchSize');
|
|
191
191
|
for (let i = 0; i < changeSets.length; i += size) {
|
|
192
192
|
const chunk = changeSets.slice(i, i + size);
|
|
193
193
|
await this.persistManagedEntitiesBatch(meta, chunk, options);
|
|
@@ -220,9 +220,9 @@ export class ChangeSetPersister {
|
|
|
220
220
|
cond.push(where);
|
|
221
221
|
payload.push(changeSet.payload);
|
|
222
222
|
}
|
|
223
|
-
const res = await this
|
|
223
|
+
const res = await this.#driver.nativeUpdateMany(meta.class, cond, payload, options);
|
|
224
224
|
const map = new Map();
|
|
225
|
-
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));
|
|
226
226
|
for (const changeSet of changeSets) {
|
|
227
227
|
if (res.rows) {
|
|
228
228
|
const row = map.get(helper(changeSet.entity).getSerializedPrimaryKey());
|
|
@@ -233,7 +233,7 @@ export class ChangeSetPersister {
|
|
|
233
233
|
}
|
|
234
234
|
mapPrimaryKey(meta, value, changeSet) {
|
|
235
235
|
const prop = meta.properties[meta.primaryKeys[0]];
|
|
236
|
-
const insertId = prop.customType ? prop.customType.convertToJSValue(value, this
|
|
236
|
+
const insertId = prop.customType ? prop.customType.convertToJSValue(value, this.#platform) : value;
|
|
237
237
|
const wrapped = helper(changeSet.entity);
|
|
238
238
|
if (!wrapped.hasPrimaryKey()) {
|
|
239
239
|
wrapped.setPrimaryKey(insertId);
|
|
@@ -242,7 +242,7 @@ export class ChangeSetPersister {
|
|
|
242
242
|
// but we need to have it as string so comparison works in change set tracking, so instead
|
|
243
243
|
// of using the raw value from db, we convert it back to the db value explicitly
|
|
244
244
|
value = prop.customType
|
|
245
|
-
? prop.customType.convertToDatabaseValue(insertId, this
|
|
245
|
+
? prop.customType.convertToDatabaseValue(insertId, this.#platform, { mode: 'serialization' })
|
|
246
246
|
: value;
|
|
247
247
|
changeSet.payload[wrapped.__meta.primaryKeys[0]] = value;
|
|
248
248
|
if (wrapped.__identifier && !Array.isArray(wrapped.__identifier)) {
|
|
@@ -253,8 +253,8 @@ export class ChangeSetPersister {
|
|
|
253
253
|
* Sets populate flag to new entities so they are serialized like if they were loaded from the db
|
|
254
254
|
*/
|
|
255
255
|
markAsPopulated(changeSet, meta) {
|
|
256
|
-
helper(changeSet.entity).__schema = this
|
|
257
|
-
if (!this
|
|
256
|
+
helper(changeSet.entity).__schema = this.#driver.getSchemaName(meta, changeSet);
|
|
257
|
+
if (!this.#config.get('populateAfterFlush')) {
|
|
258
258
|
return;
|
|
259
259
|
}
|
|
260
260
|
helper(changeSet.entity).populated();
|
|
@@ -275,13 +275,13 @@ export class ChangeSetPersister {
|
|
|
275
275
|
});
|
|
276
276
|
if (meta.concurrencyCheckKeys.size === 0 &&
|
|
277
277
|
(!meta.versionProperty || changeSet.entity[meta.versionProperty] == null)) {
|
|
278
|
-
return this
|
|
278
|
+
return this.#driver.nativeUpdate(changeSet.meta.class, cond, changeSet.payload, options);
|
|
279
279
|
}
|
|
280
280
|
if (meta.versionProperty) {
|
|
281
|
-
cond[meta.versionProperty] = this
|
|
281
|
+
cond[meta.versionProperty] = this.#platform.convertVersionValue(changeSet.entity[meta.versionProperty], meta.properties[meta.versionProperty]);
|
|
282
282
|
}
|
|
283
283
|
this.checkConcurrencyKeys(meta, changeSet, cond);
|
|
284
|
-
return this
|
|
284
|
+
return this.#driver.nativeUpdate(changeSet.meta.class, cond, changeSet.payload, options);
|
|
285
285
|
}
|
|
286
286
|
async checkOptimisticLocks(meta, changeSets, options) {
|
|
287
287
|
if (meta.concurrencyCheckKeys.size === 0 &&
|
|
@@ -294,7 +294,7 @@ export class ChangeSetPersister {
|
|
|
294
294
|
const cond = Utils.getPrimaryKeyCond(cs.originalEntity, meta.primaryKeys.concat(...meta.concurrencyCheckKeys));
|
|
295
295
|
if (meta.versionProperty) {
|
|
296
296
|
// @ts-ignore
|
|
297
|
-
cond[meta.versionProperty] = this
|
|
297
|
+
cond[meta.versionProperty] = this.#platform.convertVersionValue(cs.entity[meta.versionProperty], meta.properties[meta.versionProperty]);
|
|
298
298
|
}
|
|
299
299
|
return cond;
|
|
300
300
|
});
|
|
@@ -302,7 +302,7 @@ export class ChangeSetPersister {
|
|
|
302
302
|
options = this.prepareOptions(meta, options, {
|
|
303
303
|
fields: primaryKeys,
|
|
304
304
|
});
|
|
305
|
-
const res = await this
|
|
305
|
+
const res = await this.#driver.find(meta.root.class, { $or }, options);
|
|
306
306
|
if (res.length !== changeSets.length) {
|
|
307
307
|
const compare = (a, b, keys) => keys.every(k => a[k] === b[k]);
|
|
308
308
|
const entity = changeSets.find(cs => {
|
|
@@ -321,7 +321,7 @@ export class ChangeSetPersister {
|
|
|
321
321
|
* so we use a single query in case of both versioning and default values is used.
|
|
322
322
|
*/
|
|
323
323
|
async reloadVersionValues(meta, changeSets, options) {
|
|
324
|
-
const reloadProps = meta.versionProperty && !this
|
|
324
|
+
const reloadProps = meta.versionProperty && !this.#usesReturningStatement ? [meta.properties[meta.versionProperty]] : [];
|
|
325
325
|
if (changeSets[0].type === ChangeSetType.CREATE) {
|
|
326
326
|
for (const prop of meta.props) {
|
|
327
327
|
if (prop.persist === false) {
|
|
@@ -350,7 +350,7 @@ export class ChangeSetPersister {
|
|
|
350
350
|
});
|
|
351
351
|
});
|
|
352
352
|
// reload generated columns
|
|
353
|
-
if (!this
|
|
353
|
+
if (!this.#usesReturningStatement) {
|
|
354
354
|
meta.props.filter(prop => prop.generated && !prop.primary).forEach(prop => reloadProps.push(prop));
|
|
355
355
|
reloadProps.push(...returning);
|
|
356
356
|
}
|
|
@@ -363,19 +363,19 @@ export class ChangeSetPersister {
|
|
|
363
363
|
const pks = changeSets.map(cs => {
|
|
364
364
|
const val = helper(cs.entity).getPrimaryKey(true);
|
|
365
365
|
if (Utils.isPlainObject(val)) {
|
|
366
|
-
return Utils.getCompositeKeyValue(val, meta, false, this
|
|
366
|
+
return Utils.getCompositeKeyValue(val, meta, false, this.#platform);
|
|
367
367
|
}
|
|
368
368
|
return val;
|
|
369
369
|
});
|
|
370
370
|
options = this.prepareOptions(meta, options, {
|
|
371
371
|
fields: Utils.unique(reloadProps.map(prop => prop.name)),
|
|
372
372
|
});
|
|
373
|
-
const data = await this
|
|
373
|
+
const data = await this.#driver.find(meta.class, { [pk]: { $in: pks } }, options);
|
|
374
374
|
const map = new Map();
|
|
375
|
-
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));
|
|
376
376
|
for (const changeSet of changeSets) {
|
|
377
377
|
const data = map.get(helper(changeSet.entity).getSerializedPrimaryKey());
|
|
378
|
-
this
|
|
378
|
+
this.#hydrator.hydrate(changeSet.entity, meta, data, this.#factory, 'full', false, true);
|
|
379
379
|
Object.assign(changeSet.payload, data); // merge to the changeset payload, so it gets saved to the entity snapshot
|
|
380
380
|
}
|
|
381
381
|
}
|
|
@@ -431,17 +431,17 @@ export class ChangeSetPersister {
|
|
|
431
431
|
* We do need to map to the change set payload too, as it will be used in the originalEntityData for new entities.
|
|
432
432
|
*/
|
|
433
433
|
mapReturnedValues(entity, payload, row, meta, upsert = false) {
|
|
434
|
-
if ((!this
|
|
434
|
+
if ((!this.#usesReturningStatement && !upsert) || !row || !Utils.hasObjectKeys(row)) {
|
|
435
435
|
return;
|
|
436
436
|
}
|
|
437
|
-
const mapped = this
|
|
437
|
+
const mapped = this.#comparator.mapResult(meta, row);
|
|
438
438
|
if (entity) {
|
|
439
|
-
this
|
|
439
|
+
this.#hydrator.hydrate(entity, meta, mapped, this.#factory, 'full', false, true);
|
|
440
440
|
}
|
|
441
441
|
if (upsert) {
|
|
442
442
|
for (const prop of meta.props) {
|
|
443
443
|
if (prop.customType && prop.name in mapped) {
|
|
444
|
-
mapped[prop.name] = prop.customType.convertToJSValue(mapped[prop.name], this
|
|
444
|
+
mapped[prop.name] = prop.customType.convertToJSValue(mapped[prop.name], this.#platform);
|
|
445
445
|
}
|
|
446
446
|
}
|
|
447
447
|
}
|
|
@@ -26,10 +26,7 @@ export interface Edge {
|
|
|
26
26
|
* @internal
|
|
27
27
|
*/
|
|
28
28
|
export declare class CommitOrderCalculator {
|
|
29
|
-
|
|
30
|
-
private nodes;
|
|
31
|
-
/** Volatile variable holding calculated nodes during sorting process. */
|
|
32
|
-
private sortedNodeList;
|
|
29
|
+
#private;
|
|
33
30
|
/**
|
|
34
31
|
* Checks for node existence in graph.
|
|
35
32
|
*/
|
|
@@ -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 = new Map();
|
|
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 this
|
|
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;
|
|
@@ -57,15 +57,15 @@ export class CommitOrderCalculator {
|
|
|
57
57
|
* @internal Highly performance-sensitive method.
|
|
58
58
|
*/
|
|
59
59
|
sort() {
|
|
60
|
-
for (const vertex of this
|
|
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
|
/**
|
|
@@ -76,7 +76,7 @@ export class CommitOrderCalculator {
|
|
|
76
76
|
visit(node) {
|
|
77
77
|
node.state = 1 /* NodeState.IN_PROGRESS */;
|
|
78
78
|
for (const edge of node.dependencies.values()) {
|
|
79
|
-
const target = this
|
|
79
|
+
const target = this.#nodes.get(edge.to);
|
|
80
80
|
switch (target.state) {
|
|
81
81
|
case 2 /* NodeState.VISITED */:
|
|
82
82
|
break; // Do nothing, since node was already visited
|
|
@@ -89,7 +89,7 @@ export class CommitOrderCalculator {
|
|
|
89
89
|
}
|
|
90
90
|
if (node.state !== 2 /* NodeState.VISITED */) {
|
|
91
91
|
node.state = 2 /* NodeState.VISITED */;
|
|
92
|
-
this
|
|
92
|
+
this.#sortedNodeList.push(node.hash);
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
95
|
/**
|
|
@@ -100,12 +100,12 @@ export class CommitOrderCalculator {
|
|
|
100
100
|
return;
|
|
101
101
|
}
|
|
102
102
|
for (const edge of target.dependencies.values()) {
|
|
103
|
-
const targetNode = this
|
|
103
|
+
const targetNode = this.#nodes.get(edge.to);
|
|
104
104
|
if (targetNode.state === 0 /* NodeState.NOT_VISITED */) {
|
|
105
105
|
this.visit(targetNode);
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
108
|
target.state = 2 /* NodeState.VISITED */;
|
|
109
|
-
this
|
|
109
|
+
this.#sortedNodeList.push(target.hash);
|
|
110
110
|
}
|
|
111
111
|
}
|
|
@@ -1,10 +1,7 @@
|
|
|
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;
|
|
6
|
-
/** Tracks alternate key hashes for each entity so we can clean them up on delete */
|
|
7
|
-
private readonly alternateKeys;
|
|
3
|
+
#private;
|
|
4
|
+
constructor(defaultSchema?: string);
|
|
8
5
|
store<T>(item: T): void;
|
|
9
6
|
/**
|
|
10
7
|
* Stores an entity under an alternate key (non-PK property).
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
export class IdentityMap {
|
|
2
|
-
defaultSchema;
|
|
2
|
+
#defaultSchema;
|
|
3
|
+
#registry = new Map();
|
|
4
|
+
/** Tracks alternate key hashes for each entity so we can clean them up on delete */
|
|
5
|
+
#alternateKeys = new WeakMap();
|
|
3
6
|
constructor(defaultSchema) {
|
|
4
|
-
this
|
|
7
|
+
this.#defaultSchema = defaultSchema;
|
|
5
8
|
}
|
|
6
|
-
registry = new Map();
|
|
7
|
-
/** Tracks alternate key hashes for each entity so we can clean them up on delete */
|
|
8
|
-
alternateKeys = new WeakMap();
|
|
9
9
|
store(item) {
|
|
10
10
|
this.getStore(item.__meta.root).set(this.getPkHash(item), item);
|
|
11
11
|
}
|
|
@@ -17,10 +17,10 @@ export class IdentityMap {
|
|
|
17
17
|
const hash = this.getKeyHash(key, value, schema);
|
|
18
18
|
this.getStore(item.__meta.root).set(hash, item);
|
|
19
19
|
// Track this alternate key so we can clean it up when the entity is deleted
|
|
20
|
-
let keys = this
|
|
20
|
+
let keys = this.#alternateKeys.get(item);
|
|
21
21
|
if (!keys) {
|
|
22
22
|
keys = new Set();
|
|
23
|
-
this
|
|
23
|
+
this.#alternateKeys.set(item, keys);
|
|
24
24
|
}
|
|
25
25
|
keys.add(hash);
|
|
26
26
|
}
|
|
@@ -29,12 +29,12 @@ export class IdentityMap {
|
|
|
29
29
|
const store = this.getStore(meta);
|
|
30
30
|
store.delete(this.getPkHash(item));
|
|
31
31
|
// Also delete any alternate key entries for this entity
|
|
32
|
-
const altKeys = this
|
|
32
|
+
const altKeys = this.#alternateKeys.get(item);
|
|
33
33
|
if (altKeys) {
|
|
34
34
|
for (const hash of altKeys) {
|
|
35
35
|
store.delete(hash);
|
|
36
36
|
}
|
|
37
|
-
this
|
|
37
|
+
this.#alternateKeys.delete(item);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
getByHash(meta, hash) {
|
|
@@ -42,26 +42,26 @@ export class IdentityMap {
|
|
|
42
42
|
return store.has(hash) ? store.get(hash) : undefined;
|
|
43
43
|
}
|
|
44
44
|
getStore(meta) {
|
|
45
|
-
const store = this
|
|
45
|
+
const store = this.#registry.get(meta.class);
|
|
46
46
|
if (store) {
|
|
47
47
|
return store;
|
|
48
48
|
}
|
|
49
49
|
const newStore = new Map();
|
|
50
|
-
this
|
|
50
|
+
this.#registry.set(meta.class, newStore);
|
|
51
51
|
return newStore;
|
|
52
52
|
}
|
|
53
53
|
clear() {
|
|
54
|
-
this
|
|
54
|
+
this.#registry.clear();
|
|
55
55
|
}
|
|
56
56
|
values() {
|
|
57
57
|
const ret = [];
|
|
58
|
-
for (const store of this
|
|
58
|
+
for (const store of this.#registry.values()) {
|
|
59
59
|
ret.push(...store.values());
|
|
60
60
|
}
|
|
61
61
|
return ret;
|
|
62
62
|
}
|
|
63
63
|
*[Symbol.iterator]() {
|
|
64
|
-
for (const store of this
|
|
64
|
+
for (const store of this.#registry.values()) {
|
|
65
65
|
for (const item of store.values()) {
|
|
66
66
|
yield item;
|
|
67
67
|
}
|
|
@@ -69,7 +69,7 @@ export class IdentityMap {
|
|
|
69
69
|
}
|
|
70
70
|
keys() {
|
|
71
71
|
const ret = [];
|
|
72
|
-
for (const [cls, store] of this
|
|
72
|
+
for (const [cls, store] of this.#registry) {
|
|
73
73
|
ret.push(...[...store.keys()].map(hash => `${cls.name}-${hash}`));
|
|
74
74
|
}
|
|
75
75
|
return ret;
|
|
@@ -79,18 +79,18 @@ export class IdentityMap {
|
|
|
79
79
|
*/
|
|
80
80
|
get(hash) {
|
|
81
81
|
const [name, id] = hash.split('-', 2);
|
|
82
|
-
const cls = [...this
|
|
82
|
+
const cls = [...this.#registry.keys()].find(k => k.name === name);
|
|
83
83
|
if (!cls) {
|
|
84
84
|
return undefined;
|
|
85
85
|
}
|
|
86
|
-
const store = this
|
|
86
|
+
const store = this.#registry.get(cls);
|
|
87
87
|
return store.has(id) ? store.get(id) : undefined;
|
|
88
88
|
}
|
|
89
89
|
getPkHash(item) {
|
|
90
90
|
const wrapped = item.__helper;
|
|
91
91
|
const meta = wrapped.__meta;
|
|
92
92
|
const hash = wrapped.getSerializedPrimaryKey();
|
|
93
|
-
const schema = wrapped.__schema ?? meta.root.schema ?? this
|
|
93
|
+
const schema = wrapped.__schema ?? meta.root.schema ?? this.#defaultSchema;
|
|
94
94
|
if (schema) {
|
|
95
95
|
return schema + ':' + hash;
|
|
96
96
|
}
|
|
@@ -7,25 +7,7 @@ import type { EntityManager } from '../EntityManager.js';
|
|
|
7
7
|
import { IdentityMap } from './IdentityMap.js';
|
|
8
8
|
import type { LockOptions } from '../drivers/IDatabaseDriver.js';
|
|
9
9
|
export declare class UnitOfWork {
|
|
10
|
-
private
|
|
11
|
-
/** map of references to managed entities */
|
|
12
|
-
private readonly identityMap;
|
|
13
|
-
private readonly persistStack;
|
|
14
|
-
private readonly removeStack;
|
|
15
|
-
private readonly orphanRemoveStack;
|
|
16
|
-
private readonly changeSets;
|
|
17
|
-
private readonly collectionUpdates;
|
|
18
|
-
private readonly extraUpdates;
|
|
19
|
-
private readonly metadata;
|
|
20
|
-
private readonly platform;
|
|
21
|
-
private readonly eventManager;
|
|
22
|
-
private readonly comparator;
|
|
23
|
-
private readonly changeSetComputer;
|
|
24
|
-
private readonly changeSetPersister;
|
|
25
|
-
private readonly queuedActions;
|
|
26
|
-
private readonly loadedEntities;
|
|
27
|
-
private readonly flushQueue;
|
|
28
|
-
private working;
|
|
10
|
+
#private;
|
|
29
11
|
constructor(em: EntityManager);
|
|
30
12
|
merge<T extends object>(entity: T, visited?: Set<AnyEntity>): void;
|
|
31
13
|
/**
|
|
@@ -42,6 +24,10 @@ export declare class UnitOfWork {
|
|
|
42
24
|
* @internal
|
|
43
25
|
*/
|
|
44
26
|
dispatchOnLoadEvent(): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* @internal
|
|
29
|
+
*/
|
|
30
|
+
unmarkAsLoaded(entity: AnyEntity): void;
|
|
45
31
|
/**
|
|
46
32
|
* 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`.
|
|
47
33
|
*/
|