@mikro-orm/core 7.1.15-dev.13 → 7.1.15-dev.15
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/package.json +1 -1
- package/typings.d.ts +6 -0
- package/typings.js +19 -0
- package/unit-of-work/ChangeSetPersister.js +17 -13
- package/unit-of-work/UnitOfWork.js +6 -3
- package/utils/Utils.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikro-orm/core",
|
|
3
|
-
"version": "7.1.15-dev.
|
|
3
|
+
"version": "7.1.15-dev.15",
|
|
4
4
|
"description": "TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, PostgreSQL and SQLite databases as well as usage with vanilla JavaScript.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"data-mapper",
|
package/typings.d.ts
CHANGED
|
@@ -1050,6 +1050,12 @@ export declare class EntityMetadata<Entity = any, Class extends EntityCtor<Entit
|
|
|
1050
1050
|
constructor(meta?: Partial<EntityMetadata>);
|
|
1051
1051
|
addProperty(prop: Partial<EntityProperty<Entity>>): void;
|
|
1052
1052
|
removeProperty(name: string, sync?: boolean): void;
|
|
1053
|
+
/** For TPT entities, the version column exists only on the table of the entity that declares it. */
|
|
1054
|
+
ownsVersionProperty(): boolean;
|
|
1055
|
+
/** For TPT entities, concurrency check columns exist only on the table of the entity that declares them. */
|
|
1056
|
+
getOwnConcurrencyCheckKeys(): EntityKey<Entity>[];
|
|
1057
|
+
/** Whether updates of this table are guarded by a version property or concurrency check columns it owns. */
|
|
1058
|
+
hasOptimisticLock(): boolean;
|
|
1053
1059
|
getPrimaryProps(flatten?: boolean): EntityProperty<Entity>[];
|
|
1054
1060
|
getPrimaryProp(): EntityProperty<Entity>;
|
|
1055
1061
|
/**
|
package/typings.js
CHANGED
|
@@ -79,6 +79,25 @@ export class EntityMetadata {
|
|
|
79
79
|
this.sync();
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
|
+
/** For TPT entities, the version column exists only on the table of the entity that declares it. */
|
|
83
|
+
ownsVersionProperty() {
|
|
84
|
+
if (!this.versionProperty) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
return this.inheritanceType !== 'tpt' || !this.ownProps || this.ownProps.some(p => p.name === this.versionProperty);
|
|
88
|
+
}
|
|
89
|
+
/** For TPT entities, concurrency check columns exist only on the table of the entity that declares them. */
|
|
90
|
+
getOwnConcurrencyCheckKeys() {
|
|
91
|
+
const keys = [...this.concurrencyCheckKeys];
|
|
92
|
+
if (this.inheritanceType !== 'tpt' || !this.ownProps) {
|
|
93
|
+
return keys;
|
|
94
|
+
}
|
|
95
|
+
return keys.filter(key => this.ownProps.some(p => p.name === key));
|
|
96
|
+
}
|
|
97
|
+
/** Whether updates of this table are guarded by a version property or concurrency check columns it owns. */
|
|
98
|
+
hasOptimisticLock() {
|
|
99
|
+
return this.ownsVersionProperty() || this.getOwnConcurrencyCheckKeys().length > 0;
|
|
100
|
+
}
|
|
82
101
|
getPrimaryProps(flatten = false) {
|
|
83
102
|
const pks = this.primaryKeys.map(pk => this.properties[pk]);
|
|
84
103
|
if (flatten) {
|
|
@@ -204,13 +204,14 @@ export class ChangeSetPersister {
|
|
|
204
204
|
}
|
|
205
205
|
checkConcurrencyKeys(meta, changeSet, cond) {
|
|
206
206
|
const tmp = [];
|
|
207
|
-
|
|
207
|
+
const keys = meta.getOwnConcurrencyCheckKeys();
|
|
208
|
+
for (const key of keys) {
|
|
208
209
|
cond[key] = changeSet.originalEntity[key];
|
|
209
210
|
if (changeSet.payload[key]) {
|
|
210
211
|
tmp.push(key);
|
|
211
212
|
}
|
|
212
213
|
}
|
|
213
|
-
if (tmp.length === 0 &&
|
|
214
|
+
if (tmp.length === 0 && keys.length > 0) {
|
|
214
215
|
throw OptimisticLockError.lockFailed(changeSet.entity);
|
|
215
216
|
}
|
|
216
217
|
}
|
|
@@ -303,32 +304,33 @@ export class ChangeSetPersister {
|
|
|
303
304
|
options = this.prepareOptions(meta, options, {
|
|
304
305
|
convertCustomTypes: false,
|
|
305
306
|
});
|
|
306
|
-
if (meta.
|
|
307
|
-
(!meta.
|
|
307
|
+
if (meta.getOwnConcurrencyCheckKeys().length === 0 &&
|
|
308
|
+
(!meta.ownsVersionProperty() || changeSet.entity[meta.versionProperty] == null)) {
|
|
308
309
|
return this.#driver.nativeUpdate(changeSet.meta.class, cond, changeSet.payload, options);
|
|
309
310
|
}
|
|
310
|
-
if (meta.
|
|
311
|
+
if (meta.ownsVersionProperty()) {
|
|
311
312
|
cond[meta.versionProperty] = this.#platform.convertVersionValue(changeSet.entity[meta.versionProperty], meta.properties[meta.versionProperty]);
|
|
312
313
|
}
|
|
313
314
|
this.checkConcurrencyKeys(meta, changeSet, cond);
|
|
314
315
|
return this.#driver.nativeUpdate(changeSet.meta.class, cond, changeSet.payload, options);
|
|
315
316
|
}
|
|
316
317
|
async checkOptimisticLocks(meta, changeSets, options) {
|
|
317
|
-
|
|
318
|
-
|
|
318
|
+
const concurrencyCheckKeys = meta.getOwnConcurrencyCheckKeys();
|
|
319
|
+
if (concurrencyCheckKeys.length === 0 &&
|
|
320
|
+
(!meta.ownsVersionProperty() || changeSets.every(cs => cs.entity[meta.versionProperty] == null))) {
|
|
319
321
|
return;
|
|
320
322
|
}
|
|
321
323
|
// skip entity references as they don't have version values loaded
|
|
322
324
|
changeSets = changeSets.filter(cs => helper(cs.entity).__initialized);
|
|
325
|
+
const primaryKeys = meta.primaryKeys.concat(...concurrencyCheckKeys);
|
|
323
326
|
const $or = changeSets.map(cs => {
|
|
324
|
-
const cond = Utils.getPrimaryKeyCond(cs.originalEntity,
|
|
325
|
-
if (meta.
|
|
327
|
+
const cond = Utils.getPrimaryKeyCond(cs.originalEntity, primaryKeys);
|
|
328
|
+
if (meta.ownsVersionProperty()) {
|
|
326
329
|
// @ts-ignore
|
|
327
330
|
cond[meta.versionProperty] = this.#platform.convertVersionValue(cs.entity[meta.versionProperty], meta.properties[meta.versionProperty]);
|
|
328
331
|
}
|
|
329
332
|
return cond;
|
|
330
333
|
});
|
|
331
|
-
const primaryKeys = meta.primaryKeys.concat(...meta.concurrencyCheckKeys);
|
|
332
334
|
options = this.prepareOptions(meta, options, {
|
|
333
335
|
fields: primaryKeys,
|
|
334
336
|
orderBy: meta.primaryKeys.reduce((o, pk) => {
|
|
@@ -336,7 +338,9 @@ export class ChangeSetPersister {
|
|
|
336
338
|
return o;
|
|
337
339
|
}, {}),
|
|
338
340
|
});
|
|
339
|
-
|
|
341
|
+
// TPT tables query their own metadata, as the version column might not live on the root table
|
|
342
|
+
const target = meta.inheritanceType === 'tpt' ? meta : meta.root;
|
|
343
|
+
const res = await this.#driver.find(target.class, { $or }, options);
|
|
340
344
|
if (res.length !== changeSets.length) {
|
|
341
345
|
// a FK pointing to a composite PK is an array, so the values need to be compared deeply
|
|
342
346
|
const compare = (a, b, keys) => keys.every(k => equals(a[k], b[k]));
|
|
@@ -347,7 +351,7 @@ export class ChangeSetPersister {
|
|
|
347
351
|
}
|
|
348
352
|
}
|
|
349
353
|
checkOptimisticLock(meta, changeSet, res) {
|
|
350
|
-
if ((meta.
|
|
354
|
+
if ((meta.ownsVersionProperty() || meta.getOwnConcurrencyCheckKeys().length > 0) && res && !res.affectedRows) {
|
|
351
355
|
throw OptimisticLockError.lockFailed(changeSet.entity);
|
|
352
356
|
}
|
|
353
357
|
}
|
|
@@ -356,7 +360,7 @@ export class ChangeSetPersister {
|
|
|
356
360
|
* so we use a single query in case of both versioning and default values is used.
|
|
357
361
|
*/
|
|
358
362
|
async reloadVersionValues(meta, changeSets, options) {
|
|
359
|
-
const reloadProps = meta.
|
|
363
|
+
const reloadProps = meta.ownsVersionProperty() && !this.#usesReturningStatement ? [meta.properties[meta.versionProperty]] : [];
|
|
360
364
|
if (changeSets[0].type === ChangeSetType.CREATE) {
|
|
361
365
|
for (const prop of meta.props) {
|
|
362
366
|
if (prop.persist === false) {
|
|
@@ -331,6 +331,7 @@ export class UnitOfWork {
|
|
|
331
331
|
let parentCs = changeSet.tptChangeSets.find(pc => pc.meta === current);
|
|
332
332
|
if (!parentCs) {
|
|
333
333
|
parentCs = new ChangeSet(entity, changeSet.type, {}, current);
|
|
334
|
+
parentCs.originalEntity = changeSet.originalEntity;
|
|
334
335
|
changeSet.tptChangeSets.splice(idx, 0, parentCs);
|
|
335
336
|
}
|
|
336
337
|
idx++;
|
|
@@ -705,13 +706,14 @@ export class UnitOfWork {
|
|
|
705
706
|
payload[pk] = identifiers[i] ?? originalChangeSet.payload[pk];
|
|
706
707
|
}
|
|
707
708
|
}
|
|
708
|
-
|
|
709
|
+
// the table declaring the version property or a concurrency check still needs its bump and lock check
|
|
710
|
+
if (!isCreate && Object.keys(payload).length === 0 && !current.hasOptimisticLock()) {
|
|
709
711
|
current = current.tptParent;
|
|
710
712
|
continue;
|
|
711
713
|
}
|
|
712
714
|
const cs = new ChangeSet(entity, originalChangeSet.type, payload, current);
|
|
715
|
+
cs.originalEntity = originalChangeSet.originalEntity;
|
|
713
716
|
if (current === meta) {
|
|
714
|
-
cs.originalEntity = originalChangeSet.originalEntity;
|
|
715
717
|
leafCs = cs;
|
|
716
718
|
}
|
|
717
719
|
else {
|
|
@@ -1208,7 +1210,8 @@ export class UnitOfWork {
|
|
|
1208
1210
|
const addToGroup = (cs) => {
|
|
1209
1211
|
// Skip stub TPT changesets with empty payload (e.g. leaf with no own-property changes on UPDATE)
|
|
1210
1212
|
if ((cs.type === ChangeSetType.UPDATE || cs.type === ChangeSetType.UPDATE_EARLY) &&
|
|
1211
|
-
!Utils.hasObjectKeys(cs.payload)
|
|
1213
|
+
!Utils.hasObjectKeys(cs.payload) &&
|
|
1214
|
+
!cs.meta.hasOptimisticLock()) {
|
|
1212
1215
|
return;
|
|
1213
1216
|
}
|
|
1214
1217
|
const group = groups[cs.type];
|
package/utils/Utils.js
CHANGED
|
@@ -153,7 +153,7 @@ export function parseJsonSafe(value) {
|
|
|
153
153
|
/** Collection of general-purpose utility methods used throughout the ORM. */
|
|
154
154
|
export class Utils {
|
|
155
155
|
static PK_SEPARATOR = '~~~';
|
|
156
|
-
static #ORM_VERSION = '7.1.15-dev.
|
|
156
|
+
static #ORM_VERSION = '7.1.15-dev.15';
|
|
157
157
|
/**
|
|
158
158
|
* Checks if the argument is instance of `Object`. Returns false for arrays.
|
|
159
159
|
*/
|