@mikro-orm/core 7.1.15-dev.14 → 7.1.15-dev.16
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 +4 -0
- package/typings.js +12 -0
- package/unit-of-work/ChangeSetPersister.js +9 -7
- package/unit-of-work/UnitOfWork.js +3 -3
- package/utils/Utils.js +1 -1
- package/utils/upsert-utils.js +10 -3
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.16",
|
|
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
|
@@ -1052,6 +1052,10 @@ export declare class EntityMetadata<Entity = any, Class extends EntityCtor<Entit
|
|
|
1052
1052
|
removeProperty(name: string, sync?: boolean): void;
|
|
1053
1053
|
/** For TPT entities, the version column exists only on the table of the entity that declares it. */
|
|
1054
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;
|
|
1055
1059
|
getPrimaryProps(flatten?: boolean): EntityProperty<Entity>[];
|
|
1056
1060
|
getPrimaryProp(): EntityProperty<Entity>;
|
|
1057
1061
|
/**
|
package/typings.js
CHANGED
|
@@ -86,6 +86,18 @@ export class EntityMetadata {
|
|
|
86
86
|
}
|
|
87
87
|
return this.inheritanceType !== 'tpt' || !this.ownProps || this.ownProps.some(p => p.name === this.versionProperty);
|
|
88
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
|
+
}
|
|
89
101
|
getPrimaryProps(flatten = false) {
|
|
90
102
|
const pks = this.primaryKeys.map(pk => this.properties[pk]);
|
|
91
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,7 +304,7 @@ export class ChangeSetPersister {
|
|
|
303
304
|
options = this.prepareOptions(meta, options, {
|
|
304
305
|
convertCustomTypes: false,
|
|
305
306
|
});
|
|
306
|
-
if (meta.
|
|
307
|
+
if (meta.getOwnConcurrencyCheckKeys().length === 0 &&
|
|
307
308
|
(!meta.ownsVersionProperty() || changeSet.entity[meta.versionProperty] == null)) {
|
|
308
309
|
return this.#driver.nativeUpdate(changeSet.meta.class, cond, changeSet.payload, options);
|
|
309
310
|
}
|
|
@@ -314,21 +315,22 @@ export class ChangeSetPersister {
|
|
|
314
315
|
return this.#driver.nativeUpdate(changeSet.meta.class, cond, changeSet.payload, options);
|
|
315
316
|
}
|
|
316
317
|
async checkOptimisticLocks(meta, changeSets, options) {
|
|
317
|
-
|
|
318
|
+
const concurrencyCheckKeys = meta.getOwnConcurrencyCheckKeys();
|
|
319
|
+
if (concurrencyCheckKeys.length === 0 &&
|
|
318
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,
|
|
327
|
+
const cond = Utils.getPrimaryKeyCond(cs.originalEntity, primaryKeys);
|
|
325
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) => {
|
|
@@ -349,7 +351,7 @@ export class ChangeSetPersister {
|
|
|
349
351
|
}
|
|
350
352
|
}
|
|
351
353
|
checkOptimisticLock(meta, changeSet, res) {
|
|
352
|
-
if ((meta.
|
|
354
|
+
if ((meta.ownsVersionProperty() || meta.getOwnConcurrencyCheckKeys().length > 0) && res && !res.affectedRows) {
|
|
353
355
|
throw OptimisticLockError.lockFailed(changeSet.entity);
|
|
354
356
|
}
|
|
355
357
|
}
|
|
@@ -706,8 +706,8 @@ export class UnitOfWork {
|
|
|
706
706
|
payload[pk] = identifiers[i] ?? originalChangeSet.payload[pk];
|
|
707
707
|
}
|
|
708
708
|
}
|
|
709
|
-
// the table declaring the version property still needs its bump and lock check
|
|
710
|
-
if (!isCreate && Object.keys(payload).length === 0 && !current.
|
|
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()) {
|
|
711
711
|
current = current.tptParent;
|
|
712
712
|
continue;
|
|
713
713
|
}
|
|
@@ -1211,7 +1211,7 @@ export class UnitOfWork {
|
|
|
1211
1211
|
// Skip stub TPT changesets with empty payload (e.g. leaf with no own-property changes on UPDATE)
|
|
1212
1212
|
if ((cs.type === ChangeSetType.UPDATE || cs.type === ChangeSetType.UPDATE_EARLY) &&
|
|
1213
1213
|
!Utils.hasObjectKeys(cs.payload) &&
|
|
1214
|
-
!cs.meta.
|
|
1214
|
+
!cs.meta.hasOptimisticLock()) {
|
|
1215
1215
|
return;
|
|
1216
1216
|
}
|
|
1217
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.16';
|
|
157
157
|
/**
|
|
158
158
|
* Checks if the argument is instance of `Object`. Returns false for arrays.
|
|
159
159
|
*/
|
package/utils/upsert-utils.js
CHANGED
|
@@ -138,7 +138,14 @@ function getPropertyValue(obj, key) {
|
|
|
138
138
|
}
|
|
139
139
|
/** @internal */
|
|
140
140
|
export function getWhereCondition(meta, onConflictFields, data, where) {
|
|
141
|
-
|
|
141
|
+
// TPT children do not inherit the unique flags and indexes of their parent tables
|
|
142
|
+
const uniqueProps = new Set();
|
|
143
|
+
const uniques = [];
|
|
144
|
+
for (let current = meta; current; current = current.tptParent) {
|
|
145
|
+
current.props.filter(p => p.unique).forEach(p => uniqueProps.add(p.name));
|
|
146
|
+
uniques.push(...current.uniques);
|
|
147
|
+
}
|
|
148
|
+
const unique = onConflictFields ?? [...uniqueProps];
|
|
142
149
|
const propIndex = !isRaw(unique) &&
|
|
143
150
|
unique.findIndex(p => data[p] ?? data[p.substring(0, p.indexOf('.'))] != null);
|
|
144
151
|
if (onConflictFields || where == null) {
|
|
@@ -152,8 +159,8 @@ export function getWhereCondition(meta, onConflictFields, data, where) {
|
|
|
152
159
|
}
|
|
153
160
|
where = { [key]: getPropertyValue(data, unique[propIndex]) };
|
|
154
161
|
}
|
|
155
|
-
else
|
|
156
|
-
for (const u of
|
|
162
|
+
else {
|
|
163
|
+
for (const u of uniques) {
|
|
157
164
|
if (Utils.asArray(u.properties).every(p => data[p] != null)) {
|
|
158
165
|
where = Utils.asArray(u.properties).reduce((o, key) => {
|
|
159
166
|
o[key] = data[key];
|