@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
|
@@ -6,20 +6,20 @@ import { Raw } from './RawQueryFragment.js';
|
|
|
6
6
|
import { EntityIdentifier } from '../entity/EntityIdentifier.js';
|
|
7
7
|
import { PolymorphicRef } from '../entity/PolymorphicRef.js';
|
|
8
8
|
export class EntityComparator {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
9
|
+
#comparators = new Map();
|
|
10
|
+
#mappers = new Map();
|
|
11
|
+
#snapshotGenerators = new Map();
|
|
12
|
+
#pkGetters = new Map();
|
|
13
|
+
#pkGettersConverted = new Map();
|
|
14
|
+
#pkSerializers = new Map();
|
|
15
|
+
#tmpIndex = 0;
|
|
16
|
+
#metadata;
|
|
17
|
+
#platform;
|
|
18
|
+
#config;
|
|
19
19
|
constructor(metadata, platform, config) {
|
|
20
|
-
this
|
|
21
|
-
this
|
|
22
|
-
this
|
|
20
|
+
this.#metadata = metadata;
|
|
21
|
+
this.#platform = platform;
|
|
22
|
+
this.#config = config;
|
|
23
23
|
}
|
|
24
24
|
/**
|
|
25
25
|
* Computes difference between two entities.
|
|
@@ -51,7 +51,7 @@ export class EntityComparator {
|
|
|
51
51
|
* @internal Highly performance-sensitive method.
|
|
52
52
|
*/
|
|
53
53
|
getPkGetter(meta) {
|
|
54
|
-
const exists = this
|
|
54
|
+
const exists = this.#pkGetters.get(meta);
|
|
55
55
|
/* v8 ignore next */
|
|
56
56
|
if (exists) {
|
|
57
57
|
return exists;
|
|
@@ -93,15 +93,15 @@ export class EntityComparator {
|
|
|
93
93
|
}
|
|
94
94
|
const code = `// compiled pk getter for entity ${meta.className}\n` + `return function(entity) {\n${lines.join('\n')}\n}`;
|
|
95
95
|
const fnKey = `pkGetter-${meta.uniqueName}`;
|
|
96
|
-
const pkSerializer = Utils.createFunction(context, code, this
|
|
97
|
-
this
|
|
96
|
+
const pkSerializer = Utils.createFunction(context, code, this.#config?.get('compiledFunctions'), fnKey);
|
|
97
|
+
this.#pkGetters.set(meta, pkSerializer);
|
|
98
98
|
return pkSerializer;
|
|
99
99
|
}
|
|
100
100
|
/**
|
|
101
101
|
* @internal Highly performance-sensitive method.
|
|
102
102
|
*/
|
|
103
103
|
getPkGetterConverted(meta) {
|
|
104
|
-
const exists = this
|
|
104
|
+
const exists = this.#pkGettersConverted.get(meta);
|
|
105
105
|
/* v8 ignore next */
|
|
106
106
|
if (exists) {
|
|
107
107
|
return exists;
|
|
@@ -144,22 +144,22 @@ export class EntityComparator {
|
|
|
144
144
|
const code = `// compiled pk getter (with converted custom types) for entity ${meta.className}\n` +
|
|
145
145
|
`return function(entity) {\n${lines.join('\n')}\n}`;
|
|
146
146
|
const fnKey = `pkGetterConverted-${meta.uniqueName}`;
|
|
147
|
-
const pkSerializer = Utils.createFunction(context, code, this
|
|
148
|
-
this
|
|
147
|
+
const pkSerializer = Utils.createFunction(context, code, this.#config?.get('compiledFunctions'), fnKey);
|
|
148
|
+
this.#pkGettersConverted.set(meta, pkSerializer);
|
|
149
149
|
return pkSerializer;
|
|
150
150
|
}
|
|
151
151
|
/**
|
|
152
152
|
* @internal Highly performance-sensitive method.
|
|
153
153
|
*/
|
|
154
154
|
getPkSerializer(meta) {
|
|
155
|
-
const exists = this
|
|
155
|
+
const exists = this.#pkSerializers.get(meta);
|
|
156
156
|
/* v8 ignore next */
|
|
157
157
|
if (exists) {
|
|
158
158
|
return exists;
|
|
159
159
|
}
|
|
160
160
|
const lines = [];
|
|
161
161
|
const context = new Map();
|
|
162
|
-
context.set('getCompositeKeyValue', (val) => Utils.flatten(Utils.getCompositeKeyValue(val, meta, 'convertToDatabaseValue', this
|
|
162
|
+
context.set('getCompositeKeyValue', (val) => Utils.flatten(Utils.getCompositeKeyValue(val, meta, 'convertToDatabaseValue', this.#platform)));
|
|
163
163
|
context.set('getPrimaryKeyHash', (val) => Utils.getPrimaryKeyHash(Utils.asArray(val)));
|
|
164
164
|
if (meta.primaryKeys.length > 1) {
|
|
165
165
|
lines.push(` const pks = entity.__helper.__pk ? getCompositeKeyValue(entity.__helper.__pk) : [`);
|
|
@@ -186,7 +186,7 @@ export class EntityComparator {
|
|
|
186
186
|
}
|
|
187
187
|
else if (prop.customType) {
|
|
188
188
|
const convertorKey = this.registerCustomType(meta.properties[pk], context);
|
|
189
|
-
const idx = this
|
|
189
|
+
const idx = this.#tmpIndex++;
|
|
190
190
|
lines.push(` const val_${idx} = convertToDatabaseValue_${convertorKey}(entity${this.wrap(pk)});`);
|
|
191
191
|
lines.push(` return getPrimaryKeyHash(val_${idx});`);
|
|
192
192
|
}
|
|
@@ -196,23 +196,23 @@ export class EntityComparator {
|
|
|
196
196
|
}
|
|
197
197
|
const code = `// compiled pk serializer for entity ${meta.className}\n` + `return function(entity) {\n${lines.join('\n')}\n}`;
|
|
198
198
|
const fnKey = `pkSerializer-${meta.uniqueName}`;
|
|
199
|
-
const pkSerializer = Utils.createFunction(context, code, this
|
|
200
|
-
this
|
|
199
|
+
const pkSerializer = Utils.createFunction(context, code, this.#config?.get('compiledFunctions'), fnKey);
|
|
200
|
+
this.#pkSerializers.set(meta, pkSerializer);
|
|
201
201
|
return pkSerializer;
|
|
202
202
|
}
|
|
203
203
|
/**
|
|
204
204
|
* @internal Highly performance-sensitive method.
|
|
205
205
|
*/
|
|
206
206
|
getSnapshotGenerator(entityName) {
|
|
207
|
-
const meta = this
|
|
208
|
-
const exists = this
|
|
207
|
+
const meta = this.#metadata.find(entityName);
|
|
208
|
+
const exists = this.#snapshotGenerators.get(meta);
|
|
209
209
|
if (exists) {
|
|
210
210
|
return exists;
|
|
211
211
|
}
|
|
212
212
|
const lines = [];
|
|
213
213
|
const context = new Map();
|
|
214
214
|
context.set('clone', clone);
|
|
215
|
-
context.set('cloneEmbeddable', (o) => this
|
|
215
|
+
context.set('cloneEmbeddable', (o) => this.#platform.cloneEmbeddable(o)); // do not clone prototypes
|
|
216
216
|
if (meta.root.inheritanceType === 'sti' && meta.discriminatorValue) {
|
|
217
217
|
lines.push(` ret${this.wrap(meta.root.discriminatorColumn)} = '${meta.discriminatorValue}'`);
|
|
218
218
|
}
|
|
@@ -226,8 +226,8 @@ export class EntityComparator {
|
|
|
226
226
|
.forEach(prop => lines.push(this.getPropertySnapshot(meta, prop, context, this.wrap(prop.name), this.wrap(prop.name), [prop.name])));
|
|
227
227
|
const code = `return function(entity) {\n const ret = {};\n${lines.join('\n')}\n return ret;\n}`;
|
|
228
228
|
const fnKey = `snapshotGenerator-${meta.uniqueName}`;
|
|
229
|
-
const snapshotGenerator = Utils.createFunction(context, code, this
|
|
230
|
-
this
|
|
229
|
+
const snapshotGenerator = Utils.createFunction(context, code, this.#config?.get('compiledFunctions'), fnKey);
|
|
230
|
+
this.#snapshotGenerators.set(meta, snapshotGenerator);
|
|
231
231
|
return snapshotGenerator;
|
|
232
232
|
}
|
|
233
233
|
/**
|
|
@@ -271,21 +271,21 @@ export class EntityComparator {
|
|
|
271
271
|
if (part.length === 1) {
|
|
272
272
|
return this.formatCompositeKeyPart(part[0]);
|
|
273
273
|
}
|
|
274
|
-
const formatted = part.map(this.formatCompositeKeyPart).join(', ');
|
|
274
|
+
const formatted = part.map(p => this.formatCompositeKeyPart(p)).join(', ');
|
|
275
275
|
return `[${formatted}]`;
|
|
276
276
|
}
|
|
277
277
|
/**
|
|
278
278
|
* @internal Highly performance-sensitive method.
|
|
279
279
|
*/
|
|
280
280
|
getResultMapper(meta) {
|
|
281
|
-
const exists = this
|
|
281
|
+
const exists = this.#mappers.get(meta);
|
|
282
282
|
if (exists) {
|
|
283
283
|
return exists;
|
|
284
284
|
}
|
|
285
285
|
const lines = [];
|
|
286
286
|
const context = new Map();
|
|
287
287
|
context.set('PolymorphicRef', PolymorphicRef);
|
|
288
|
-
const tz = this
|
|
288
|
+
const tz = this.#platform.getTimezone();
|
|
289
289
|
const parseDate = (key, value, padding = '') => {
|
|
290
290
|
lines.push(`${padding} if (${value} == null || ${value} instanceof Date) {`);
|
|
291
291
|
lines.push(`${padding} ${key} = ${value};`);
|
|
@@ -345,15 +345,15 @@ export class EntityComparator {
|
|
|
345
345
|
lines.push(`${padding} ${this.propName(prop.fieldNames[0], 'mapped')} = true;`);
|
|
346
346
|
lines.push(`${padding} }`);
|
|
347
347
|
}
|
|
348
|
-
else if (prop.runtimeType === 'Date' && !this
|
|
348
|
+
else if (prop.runtimeType === 'Date' && !this.#platform.isNumericProperty(prop)) {
|
|
349
349
|
lines.push(`${padding} if (typeof ${this.propName(prop.fieldNames[0])} !== 'undefined') {`);
|
|
350
|
-
context.set('parseDate', (value) => this
|
|
350
|
+
context.set('parseDate', (value) => this.#platform.parseDate(value));
|
|
351
351
|
parseDate('ret' + this.wrap(prop.name), this.propName(prop.fieldNames[0]), padding);
|
|
352
352
|
lines.push(`${padding} ${this.propName(prop.fieldNames[0], 'mapped')} = true;`);
|
|
353
353
|
lines.push(`${padding} }`);
|
|
354
354
|
}
|
|
355
355
|
else if (prop.kind === ReferenceKind.EMBEDDED && (prop.object || meta.embeddable)) {
|
|
356
|
-
const idx = this
|
|
356
|
+
const idx = this.#tmpIndex++;
|
|
357
357
|
context.set(`mapEmbeddedResult_${idx}`, (data) => {
|
|
358
358
|
const item = parseJsonSafe(data);
|
|
359
359
|
if (Array.isArray(item)) {
|
|
@@ -392,8 +392,8 @@ export class EntityComparator {
|
|
|
392
392
|
const code = `// compiled mapper for entity ${meta.className}\n` +
|
|
393
393
|
`return function(result) {\n const ret = {};\n${lines.join('\n')}\n return ret;\n}`;
|
|
394
394
|
const fnKey = `resultMapper-${meta.uniqueName}`;
|
|
395
|
-
const resultMapper = Utils.createFunction(context, code, this
|
|
396
|
-
this
|
|
395
|
+
const resultMapper = Utils.createFunction(context, code, this.#config?.get('compiledFunctions'), fnKey);
|
|
396
|
+
this.#mappers.set(meta, resultMapper);
|
|
397
397
|
return resultMapper;
|
|
398
398
|
}
|
|
399
399
|
getPropertyCondition(path) {
|
|
@@ -404,7 +404,7 @@ export class EntityComparator {
|
|
|
404
404
|
let tail = '';
|
|
405
405
|
return parts
|
|
406
406
|
.map(k => {
|
|
407
|
-
if (
|
|
407
|
+
if (/^\[idx_\d+]$/.exec(k)) {
|
|
408
408
|
tail += k;
|
|
409
409
|
return '';
|
|
410
410
|
}
|
|
@@ -419,7 +419,7 @@ export class EntityComparator {
|
|
|
419
419
|
const entityKey = path.map(k => this.wrap(k)).join('');
|
|
420
420
|
const ret = [];
|
|
421
421
|
const padding = ' '.repeat(level * 2);
|
|
422
|
-
const idx = this
|
|
422
|
+
const idx = this.#tmpIndex++;
|
|
423
423
|
ret.push(`${padding}if (Array.isArray(entity${entityKey})) {`);
|
|
424
424
|
ret.push(`${padding} ret${dataKey} = [];`);
|
|
425
425
|
ret.push(`${padding} entity${entityKey}.forEach((_, idx_${idx}) => {`);
|
|
@@ -445,7 +445,7 @@ export class EntityComparator {
|
|
|
445
445
|
getEmbeddedPropertySnapshot(meta, prop, context, level, path, dataKey, object = prop.object) {
|
|
446
446
|
const padding = ' '.repeat(level * 2);
|
|
447
447
|
const nullCond = `entity${path.map(k => this.wrap(k)).join('')} === null`;
|
|
448
|
-
let ret =
|
|
448
|
+
let ret = level === 1 ? '' : '\n';
|
|
449
449
|
if (object) {
|
|
450
450
|
ret += `${padding}if (${nullCond}) ret${dataKey} = null;\n`;
|
|
451
451
|
}
|
|
@@ -517,7 +517,7 @@ export class EntityComparator {
|
|
|
517
517
|
if (Raw.isKnownFragment(val)) {
|
|
518
518
|
return val;
|
|
519
519
|
}
|
|
520
|
-
return prop.customType.convertToDatabaseValue(val, this
|
|
520
|
+
return prop.customType.convertToDatabaseValue(val, this.#platform, { mode: 'serialization' });
|
|
521
521
|
});
|
|
522
522
|
return convertorKey;
|
|
523
523
|
}
|
|
@@ -602,7 +602,7 @@ export class EntityComparator {
|
|
|
602
602
|
return (ret + ` ret${dataKey} = clone(convertToDatabaseValue_${convertorKey}(entity${entityKey}${unwrap}));\n }\n`);
|
|
603
603
|
}
|
|
604
604
|
if (prop.runtimeType === 'Date') {
|
|
605
|
-
context.set('processDateProperty', this
|
|
605
|
+
context.set('processDateProperty', this.#platform.processDateProperty.bind(this.#platform));
|
|
606
606
|
return ret + ` ret${dataKey} = clone(processDateProperty(entity${entityKey}${unwrap}));\n }\n`;
|
|
607
607
|
}
|
|
608
608
|
return ret + ` ret${dataKey} = clone(entity${entityKey}${unwrap});\n }\n`;
|
|
@@ -611,8 +611,8 @@ export class EntityComparator {
|
|
|
611
611
|
* @internal Highly performance-sensitive method.
|
|
612
612
|
*/
|
|
613
613
|
getEntityComparator(entityName) {
|
|
614
|
-
const meta = this
|
|
615
|
-
const exists = this
|
|
614
|
+
const meta = this.#metadata.find(entityName);
|
|
615
|
+
const exists = this.#comparators.get(meta);
|
|
616
616
|
if (exists) {
|
|
617
617
|
return exists;
|
|
618
618
|
}
|
|
@@ -637,8 +637,8 @@ export class EntityComparator {
|
|
|
637
637
|
const code = `// compiled comparator for entity ${meta.className}\n` +
|
|
638
638
|
`return function(last, current, options) {\n const diff = {};\n${lines.join('\n')}\n return diff;\n}`;
|
|
639
639
|
const fnKey = `comparator-${meta.uniqueName}`;
|
|
640
|
-
const comparator = Utils.createFunction(context, code, this
|
|
641
|
-
this
|
|
640
|
+
const comparator = Utils.createFunction(context, code, this.#config?.get('compiledFunctions'), fnKey);
|
|
641
|
+
this.#comparators.set(meta, comparator);
|
|
642
642
|
return comparator;
|
|
643
643
|
}
|
|
644
644
|
getGenericComparator(prop, cond) {
|
|
@@ -669,7 +669,7 @@ export class EntityComparator {
|
|
|
669
669
|
}
|
|
670
670
|
if (prop.customType) {
|
|
671
671
|
if (prop.customType.compareValues) {
|
|
672
|
-
const idx = this
|
|
672
|
+
const idx = this.#tmpIndex++;
|
|
673
673
|
context.set(`compareValues_${idx}`, (a, b) => {
|
|
674
674
|
if (Raw.isKnownFragment(a) || Raw.isKnownFragment(b)) {
|
|
675
675
|
return Raw.getKnownFragment(a) === Raw.getKnownFragment(b);
|
|
@@ -708,10 +708,10 @@ export class EntityComparator {
|
|
|
708
708
|
return this.getGenericComparator(this.wrap(prop.name), `!equals(last${this.wrap(prop.name)}, current${this.wrap(prop.name)})`);
|
|
709
709
|
}
|
|
710
710
|
wrap(key) {
|
|
711
|
-
if (
|
|
711
|
+
if (/^\[.*]$/.exec(key)) {
|
|
712
712
|
return key;
|
|
713
713
|
}
|
|
714
|
-
return
|
|
714
|
+
return /^\w+$/.exec(key) ? `.${key}` : `['${key}']`;
|
|
715
715
|
}
|
|
716
716
|
safeKey(key) {
|
|
717
717
|
return key.replace(/\W/g, '_');
|
package/utils/QueryHelper.d.ts
CHANGED
|
@@ -25,8 +25,23 @@ export declare class QueryHelper {
|
|
|
25
25
|
static processCustomType<T extends object>(prop: EntityProperty<T>, cond: FilterQuery<T>, platform: Platform, key?: string, fromQuery?: boolean): FilterQuery<T>;
|
|
26
26
|
private static isSupportedOperator;
|
|
27
27
|
private static processJsonCondition;
|
|
28
|
-
private static getValueType;
|
|
29
28
|
static findProperty<T>(fieldName: string, options: ProcessWhereOptions<T>): EntityProperty<T> | undefined;
|
|
29
|
+
/**
|
|
30
|
+
* Converts entity references for composite FK properties into flat arrays
|
|
31
|
+
* of correctly-ordered join column values, before processParams flattens them
|
|
32
|
+
* incorrectly due to shared FK columns.
|
|
33
|
+
*/
|
|
34
|
+
private static convertCompositeEntityRefs;
|
|
35
|
+
/**
|
|
36
|
+
* Extracts values for a FK's join columns from an entity by traversing the FK chain.
|
|
37
|
+
* Handles shared FK columns (e.g., tenant_id referenced by multiple FKs) correctly.
|
|
38
|
+
*/
|
|
39
|
+
private static extractJoinColumnValues;
|
|
40
|
+
/**
|
|
41
|
+
* Extracts the value for a specific column from an entity by finding which PK property
|
|
42
|
+
* owns that column and recursively traversing FK references.
|
|
43
|
+
*/
|
|
44
|
+
private static extractColumnValue;
|
|
30
45
|
/**
|
|
31
46
|
* Merges multiple orderBy sources with key-level deduplication (first-seen key wins).
|
|
32
47
|
* RawQueryFragment symbol keys are never deduped (each is unique).
|
package/utils/QueryHelper.js
CHANGED
|
@@ -133,6 +133,9 @@ export class QueryHelper {
|
|
|
133
133
|
QueryHelper.liftGroupOperators(where, meta, metadata);
|
|
134
134
|
QueryHelper.inlinePrimaryKeyObjects(where, meta, metadata);
|
|
135
135
|
}
|
|
136
|
+
if (meta && root) {
|
|
137
|
+
QueryHelper.convertCompositeEntityRefs(where, meta);
|
|
138
|
+
}
|
|
136
139
|
if (platform.getConfig().get('ignoreUndefinedInQuery') && where && typeof where === 'object') {
|
|
137
140
|
Utils.dropUndefinedProperties(where);
|
|
138
141
|
}
|
|
@@ -183,7 +186,7 @@ export class QueryHelper {
|
|
|
183
186
|
value = QueryHelper.processCustomType(prop, value, platform, undefined, true);
|
|
184
187
|
}
|
|
185
188
|
// oxfmt-ignore
|
|
186
|
-
const isJsonProperty = prop?.customType instanceof JsonType &&
|
|
189
|
+
const isJsonProperty = prop?.customType instanceof JsonType && !isRaw(value) && (Utils.isPlainObject(value) ? !['$eq', '$elemMatch'].includes(Object.keys(value)[0]) : !Array.isArray(value));
|
|
187
190
|
if (isJsonProperty && prop?.kind !== ReferenceKind.EMBEDDED) {
|
|
188
191
|
return this.processJsonCondition(o, value, [prop.fieldNames[0]], platform, aliased);
|
|
189
192
|
}
|
|
@@ -280,29 +283,7 @@ export class QueryHelper {
|
|
|
280
283
|
return !!QueryHelper.SUPPORTED_OPERATORS.find(op => key === op);
|
|
281
284
|
}
|
|
282
285
|
static processJsonCondition(o, value, path, platform, alias) {
|
|
283
|
-
|
|
284
|
-
Utils.keys(value).forEach(k => {
|
|
285
|
-
this.processJsonCondition(o, value[k], [...path, k], platform, alias);
|
|
286
|
-
});
|
|
287
|
-
return o;
|
|
288
|
-
}
|
|
289
|
-
if (path.length === 1) {
|
|
290
|
-
o[path[0]] = value;
|
|
291
|
-
return o;
|
|
292
|
-
}
|
|
293
|
-
const type = this.getValueType(value);
|
|
294
|
-
const k = platform.getSearchJsonPropertyKey(path, type, alias, value);
|
|
295
|
-
o[k] = value;
|
|
296
|
-
return o;
|
|
297
|
-
}
|
|
298
|
-
static getValueType(value) {
|
|
299
|
-
if (Array.isArray(value)) {
|
|
300
|
-
return typeof value[0];
|
|
301
|
-
}
|
|
302
|
-
if (Utils.isPlainObject(value) && Object.keys(value).every(k => Utils.isOperator(k))) {
|
|
303
|
-
return this.getValueType(Object.values(value)[0]);
|
|
304
|
-
}
|
|
305
|
-
return typeof value;
|
|
286
|
+
return platform.processJsonCondition(o, value, path, alias);
|
|
306
287
|
}
|
|
307
288
|
static findProperty(fieldName, options) {
|
|
308
289
|
const parts = fieldName.split('.');
|
|
@@ -312,6 +293,71 @@ export class QueryHelper {
|
|
|
312
293
|
const meta = entityName ? options.metadata.find(entityName) : undefined;
|
|
313
294
|
return meta?.properties[propName];
|
|
314
295
|
}
|
|
296
|
+
/**
|
|
297
|
+
* Converts entity references for composite FK properties into flat arrays
|
|
298
|
+
* of correctly-ordered join column values, before processParams flattens them
|
|
299
|
+
* incorrectly due to shared FK columns.
|
|
300
|
+
*/
|
|
301
|
+
static convertCompositeEntityRefs(where, meta) {
|
|
302
|
+
if (!Utils.isPlainObject(where)) {
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
for (const k of Object.keys(where)) {
|
|
306
|
+
if (k in GroupOperator) {
|
|
307
|
+
if (Array.isArray(where[k])) {
|
|
308
|
+
where[k].forEach((sub) => this.convertCompositeEntityRefs(sub, meta));
|
|
309
|
+
}
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
if (k === '$not') {
|
|
313
|
+
this.convertCompositeEntityRefs(where[k], meta);
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
const prop = meta.properties[k];
|
|
317
|
+
if (!prop?.joinColumns || prop.joinColumns.length <= 1) {
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
const w = where[k];
|
|
321
|
+
if (Utils.isEntity(w)) {
|
|
322
|
+
where[k] = this.extractJoinColumnValues(w, prop);
|
|
323
|
+
}
|
|
324
|
+
else if (Utils.isPlainObject(w)) {
|
|
325
|
+
for (const op of Object.keys(w)) {
|
|
326
|
+
if (Utils.isOperator(op, false) && Array.isArray(w[op])) {
|
|
327
|
+
w[op] = w[op].map((item) => Utils.isEntity(item) ? this.extractJoinColumnValues(item, prop) : item);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Extracts values for a FK's join columns from an entity by traversing the FK chain.
|
|
335
|
+
* Handles shared FK columns (e.g., tenant_id referenced by multiple FKs) correctly.
|
|
336
|
+
*/
|
|
337
|
+
static extractJoinColumnValues(entity, prop) {
|
|
338
|
+
return prop.referencedColumnNames.map(refCol => {
|
|
339
|
+
return this.extractColumnValue(entity, prop.targetMeta, refCol);
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Extracts the value for a specific column from an entity by finding which PK property
|
|
344
|
+
* owns that column and recursively traversing FK references.
|
|
345
|
+
*/
|
|
346
|
+
static extractColumnValue(entity, meta, columnName) {
|
|
347
|
+
for (const pk of meta.primaryKeys) {
|
|
348
|
+
const pkProp = meta.properties[pk];
|
|
349
|
+
const colIdx = pkProp.fieldNames.indexOf(columnName);
|
|
350
|
+
if (colIdx !== -1) {
|
|
351
|
+
const value = entity[pk];
|
|
352
|
+
if (pkProp.targetMeta && Utils.isEntity(value, true)) {
|
|
353
|
+
const refCol = pkProp.referencedColumnNames[colIdx];
|
|
354
|
+
return this.extractColumnValue(value, pkProp.targetMeta, refCol);
|
|
355
|
+
}
|
|
356
|
+
return value;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return null;
|
|
360
|
+
}
|
|
315
361
|
/**
|
|
316
362
|
* Merges multiple orderBy sources with key-level deduplication (first-seen key wins).
|
|
317
363
|
* RawQueryFragment symbol keys are never deduped (each is unique).
|
|
@@ -19,7 +19,7 @@ export declare class RawQueryFragment<Alias extends string = string> {
|
|
|
19
19
|
static isKnownFragmentSymbol(key: unknown): key is RawQueryFragmentSymbol;
|
|
20
20
|
static hasObjectFragments(object: unknown): boolean;
|
|
21
21
|
static isKnownFragment(key: unknown): key is RawQueryFragment | symbol;
|
|
22
|
-
static getKnownFragment(key: unknown): RawQueryFragment
|
|
22
|
+
static getKnownFragment(key: unknown): RawQueryFragment | undefined;
|
|
23
23
|
}
|
|
24
24
|
export { RawQueryFragment as Raw };
|
|
25
25
|
export declare function isRaw(value: unknown): value is RawQueryFragment;
|
|
@@ -102,8 +102,8 @@ export declare function raw<R = RawQueryFragment & symbol, T extends object = an
|
|
|
102
102
|
*/
|
|
103
103
|
export declare function sql<R = RawQueryFragment & symbol>(sql: readonly string[], ...values: unknown[]): R;
|
|
104
104
|
export declare namespace sql {
|
|
105
|
-
var ref: <T extends object = any>(...keys: string[]) => RawQueryFragment
|
|
106
|
-
var now: (length?: number) => RawQueryFragment
|
|
105
|
+
var ref: <T extends object = any>(...keys: string[]) => RawQueryFragment & symbol;
|
|
106
|
+
var now: (length?: number) => RawQueryFragment & symbol;
|
|
107
107
|
var lower: <R = RawQueryFragment<string> & symbol, T extends object = any>(key: string | ((alias: string) => string)) => R;
|
|
108
108
|
var upper: <R = RawQueryFragment<string> & symbol, T extends object = any>(key: string | ((alias: string) => string)) => R;
|
|
109
109
|
}
|
|
@@ -123,4 +123,4 @@ export declare function createSqlFunction<R = RawQueryFragment & symbol, T exten
|
|
|
123
123
|
*/
|
|
124
124
|
export declare function quote(expParts: readonly string[], ...values: (string | {
|
|
125
125
|
toString(): string;
|
|
126
|
-
})[]): RawQueryFragment
|
|
126
|
+
})[]): RawQueryFragment & symbol;
|
|
@@ -160,8 +160,7 @@ export class TransactionManager {
|
|
|
160
160
|
for (const entity of fork.getUnitOfWork(false).getIdentityMap()) {
|
|
161
161
|
const wrapped = helper(entity);
|
|
162
162
|
const meta = wrapped.__meta;
|
|
163
|
-
|
|
164
|
-
const parentEntity = parentUoW.getById(meta.class, wrapped.getPrimaryKey(), parent['_schema'], true);
|
|
163
|
+
const parentEntity = parentUoW.getById(meta.class, wrapped.getPrimaryKey(), parent.schema, true);
|
|
165
164
|
if (parentEntity && parentEntity !== entity) {
|
|
166
165
|
const parentWrapped = helper(parentEntity);
|
|
167
166
|
parentWrapped.__data = wrapped.__data;
|
package/utils/Utils.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ export declare class Utils {
|
|
|
22
22
|
/**
|
|
23
23
|
* Removes `undefined` properties (recursively) so they are not saved as nulls
|
|
24
24
|
*/
|
|
25
|
-
static dropUndefinedProperties(o: any, value?:
|
|
25
|
+
static dropUndefinedProperties(o: any, value?: null, visited?: Set<unknown>): void;
|
|
26
26
|
/**
|
|
27
27
|
* Returns the number of properties on `obj`. This is 20x faster than Object.keys(obj).length.
|
|
28
28
|
* @see https://github.com/deepkit/deepkit-framework/blob/master/packages/core/src/core.ts
|
package/utils/Utils.js
CHANGED
|
@@ -123,7 +123,7 @@ export function parseJsonSafe(value) {
|
|
|
123
123
|
}
|
|
124
124
|
export class Utils {
|
|
125
125
|
static PK_SEPARATOR = '~~~';
|
|
126
|
-
static #ORM_VERSION = '7.0.
|
|
126
|
+
static #ORM_VERSION = '7.0.1-dev.0';
|
|
127
127
|
/**
|
|
128
128
|
* Checks if the argument is instance of `Object`. Returns false for arrays.
|
|
129
129
|
*/
|
|
@@ -543,7 +543,7 @@ export class Utils {
|
|
|
543
543
|
!!process.env?.TS_JEST || // check if ts-jest is used
|
|
544
544
|
!!process.env?.VITEST || // check if vitest is used
|
|
545
545
|
!!process.versions?.bun || // check if bun is used
|
|
546
|
-
process.argv?.slice(1).some(arg =>
|
|
546
|
+
process.argv?.slice(1).some(arg => /\.([mc]?ts|tsx)$/.exec(arg)) || // executing `.ts` file
|
|
547
547
|
process.execArgv?.some(arg => {
|
|
548
548
|
return (arg.includes('ts-node') || // check for ts-node loader
|
|
549
549
|
arg.includes('@swc-node/register') || // check for swc-node/register loader
|
|
@@ -559,7 +559,7 @@ export class Utils {
|
|
|
559
559
|
return simple;
|
|
560
560
|
}
|
|
561
561
|
const objectType = Object.prototype.toString.call(value);
|
|
562
|
-
const type =
|
|
562
|
+
const type = /^\[object (.+)]$/.exec(objectType)[1];
|
|
563
563
|
if (type === 'Uint8Array') {
|
|
564
564
|
return 'Buffer';
|
|
565
565
|
}
|
|
@@ -613,7 +613,7 @@ export class Utils {
|
|
|
613
613
|
}
|
|
614
614
|
static findDuplicates(items) {
|
|
615
615
|
return items.reduce((acc, v, i, arr) => {
|
|
616
|
-
return arr.indexOf(v) !== i && acc.
|
|
616
|
+
return arr.indexOf(v) !== i && !acc.includes(v) ? acc.concat(v) : acc;
|
|
617
617
|
}, []);
|
|
618
618
|
}
|
|
619
619
|
static removeDuplicates(items) {
|
|
@@ -677,6 +677,7 @@ export class Utils {
|
|
|
677
677
|
return compiledFunctions[key](...context.values());
|
|
678
678
|
}
|
|
679
679
|
try {
|
|
680
|
+
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
|
680
681
|
return new Function(...context.keys(), `'use strict';\n` + code)(...context.values());
|
|
681
682
|
/* v8 ignore next */
|
|
682
683
|
}
|
package/utils/clone.js
CHANGED
|
@@ -20,6 +20,7 @@ function getPropertyDescriptor(obj, prop) {
|
|
|
20
20
|
}
|
|
21
21
|
return null;
|
|
22
22
|
}
|
|
23
|
+
const TypedArray = Object.getPrototypeOf(Uint8Array);
|
|
23
24
|
export function clone(parent, respectCustomCloneMethod = true) {
|
|
24
25
|
const allParents = [];
|
|
25
26
|
const allChildren = [];
|
|
@@ -74,6 +75,10 @@ export function clone(parent, respectCustomCloneMethod = true) {
|
|
|
74
75
|
parent.copy(child);
|
|
75
76
|
return child;
|
|
76
77
|
}
|
|
78
|
+
else if (parent instanceof TypedArray) {
|
|
79
|
+
child = parent.slice();
|
|
80
|
+
return child;
|
|
81
|
+
}
|
|
77
82
|
else if (parent instanceof Error) {
|
|
78
83
|
child = new parent.constructor(parent.message);
|
|
79
84
|
}
|
package/utils/fs-utils.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Dictionary } from '../typings.js';
|
|
2
|
-
export
|
|
2
|
+
export interface FsUtils {
|
|
3
3
|
init(): Promise<void>;
|
|
4
4
|
pathExists(path: string): boolean;
|
|
5
5
|
ensureDir(path: string): void;
|
|
@@ -10,25 +10,11 @@ export declare const fs: {
|
|
|
10
10
|
getORMPackages(): Set<string>;
|
|
11
11
|
getORMPackageVersion(name: string): string | undefined;
|
|
12
12
|
checkPackageVersion(): void;
|
|
13
|
-
/**
|
|
14
|
-
* Resolves and normalizes a series of path parts relative to each preceding part.
|
|
15
|
-
* If any part is a `file:` URL, it is converted to a local path. If any part is an
|
|
16
|
-
* absolute path, it replaces preceding paths (similar to `path.resolve` in NodeJS).
|
|
17
|
-
* Trailing directory separators are removed, and all directory separators are converted
|
|
18
|
-
* to POSIX-style separators (`/`).
|
|
19
|
-
*/
|
|
20
13
|
normalizePath(...parts: string[]): string;
|
|
21
|
-
/**
|
|
22
|
-
* Determines the relative path between two paths. If either path is a `file:` URL,
|
|
23
|
-
* it is converted to a local path.
|
|
24
|
-
*/
|
|
25
14
|
relativePath(path: string, relativeTo: string): string;
|
|
26
|
-
/**
|
|
27
|
-
* Computes the absolute path to for the given path relative to the provided base directory.
|
|
28
|
-
* If either `path` or `baseDir` are `file:` URLs, they are converted to local paths.
|
|
29
|
-
*/
|
|
30
15
|
absolutePath(path: string, baseDir?: string): string;
|
|
31
16
|
writeFile(path: string, data: string, options?: Record<string, any>): Promise<void>;
|
|
32
17
|
dynamicImport<T = any>(id: string): Promise<T>;
|
|
33
|
-
}
|
|
18
|
+
}
|
|
19
|
+
export declare const fs: FsUtils;
|
|
34
20
|
export * from '../cache/FileCacheAdapter.js';
|
package/utils/fs-utils.js
CHANGED
|
@@ -150,7 +150,7 @@ export const fs = {
|
|
|
150
150
|
}
|
|
151
151
|
let path = parts.join('/').replace(/\\/g, '/').replace(/\/$/, '');
|
|
152
152
|
path = normalize(path).replace(/\\/g, '/');
|
|
153
|
-
return
|
|
153
|
+
return /^[/.]|[a-zA-Z]:/.exec(path) || path.startsWith('!') ? path : './' + path;
|
|
154
154
|
},
|
|
155
155
|
/**
|
|
156
156
|
* Determines the relative path between two paths. If either path is a `file:` URL,
|
package/utils/upsert-utils.js
CHANGED
|
@@ -101,7 +101,7 @@ export function getOnConflictReturningFields(meta, data, uniqueFields, options)
|
|
|
101
101
|
return keys.filter(key => !(key in data));
|
|
102
102
|
}
|
|
103
103
|
function getPropertyValue(obj, key) {
|
|
104
|
-
if (key.
|
|
104
|
+
if (!key.includes('.')) {
|
|
105
105
|
return obj[key];
|
|
106
106
|
}
|
|
107
107
|
const parts = key.split('.');
|