@mikro-orm/core 7.0.0-rc.2 → 7.0.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 +4 -16
- package/EntityManager.js +248 -181
- package/MikroORM.d.ts +4 -6
- package/MikroORM.js +24 -24
- package/README.md +5 -4
- package/cache/FileCacheAdapter.d.ts +1 -5
- package/cache/FileCacheAdapter.js +22 -24
- 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 +43 -14
- package/drivers/DatabaseDriver.d.ts +0 -2
- package/drivers/DatabaseDriver.js +28 -12
- package/drivers/IDatabaseDriver.d.ts +43 -0
- package/entity/Collection.d.ts +1 -9
- package/entity/Collection.js +124 -108
- package/entity/EntityAssigner.js +23 -11
- package/entity/EntityFactory.d.ts +1 -8
- package/entity/EntityFactory.js +79 -59
- package/entity/EntityHelper.js +25 -16
- package/entity/EntityLoader.d.ts +1 -3
- package/entity/EntityLoader.js +90 -60
- package/entity/Reference.d.ts +2 -3
- package/entity/Reference.js +48 -19
- package/entity/WrappedEntity.d.ts +4 -2
- package/entity/WrappedEntity.js +5 -1
- package/entity/defineEntity.d.ts +42 -85
- package/entity/utils.js +28 -26
- package/entity/validators.js +2 -1
- package/enums.d.ts +2 -1
- package/enums.js +13 -17
- package/errors.d.ts +11 -11
- package/errors.js +8 -8
- package/events/EventManager.d.ts +1 -4
- package/events/EventManager.js +26 -23
- package/events/index.d.ts +1 -1
- package/events/index.js +0 -1
- package/exceptions.js +9 -2
- package/hydration/ObjectHydrator.d.ts +1 -2
- package/hydration/ObjectHydrator.js +41 -27
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/logging/DefaultLogger.js +6 -7
- package/logging/Logger.d.ts +2 -1
- package/logging/colors.js +2 -5
- package/logging/index.d.ts +1 -1
- package/logging/index.js +0 -1
- package/metadata/EntitySchema.d.ts +3 -3
- package/metadata/EntitySchema.js +12 -2
- package/metadata/MetadataDiscovery.d.ts +1 -9
- package/metadata/MetadataDiscovery.js +251 -179
- package/metadata/MetadataProvider.js +26 -1
- package/metadata/MetadataStorage.d.ts +1 -5
- package/metadata/MetadataStorage.js +37 -39
- package/metadata/MetadataValidator.js +20 -5
- package/metadata/discover-entities.js +1 -1
- package/metadata/index.d.ts +1 -1
- package/metadata/index.js +0 -1
- package/metadata/types.d.ts +2 -2
- package/naming-strategy/AbstractNamingStrategy.js +6 -3
- package/naming-strategy/EntityCaseNamingStrategy.js +1 -1
- package/naming-strategy/index.d.ts +1 -1
- package/naming-strategy/index.js +0 -1
- package/not-supported.js +5 -1
- package/package.json +38 -38
- package/platforms/Platform.d.ts +24 -1
- package/platforms/Platform.js +106 -27
- package/serialization/EntitySerializer.js +8 -4
- package/serialization/EntityTransformer.js +4 -1
- package/serialization/SerializationContext.d.ts +4 -8
- package/serialization/SerializationContext.js +21 -16
- package/types/UuidType.d.ts +2 -0
- package/types/UuidType.js +14 -2
- package/types/index.d.ts +2 -1
- package/typings.d.ts +35 -24
- package/typings.js +9 -9
- package/unit-of-work/ChangeSet.js +4 -4
- package/unit-of-work/ChangeSetComputer.d.ts +1 -6
- package/unit-of-work/ChangeSetComputer.js +29 -27
- package/unit-of-work/ChangeSetPersister.d.ts +1 -9
- package/unit-of-work/ChangeSetPersister.js +63 -58
- package/unit-of-work/CommitOrderCalculator.d.ts +1 -4
- package/unit-of-work/CommitOrderCalculator.js +17 -15
- package/unit-of-work/IdentityMap.d.ts +2 -5
- package/unit-of-work/IdentityMap.js +18 -18
- package/unit-of-work/UnitOfWork.d.ts +12 -20
- package/unit-of-work/UnitOfWork.js +228 -191
- package/utils/AbstractMigrator.d.ts +2 -2
- package/utils/AbstractMigrator.js +10 -12
- package/utils/AbstractSchemaGenerator.js +2 -1
- package/utils/AsyncContext.js +1 -1
- package/utils/Configuration.d.ts +90 -189
- package/utils/Configuration.js +97 -77
- package/utils/Cursor.d.ts +3 -3
- package/utils/Cursor.js +8 -6
- package/utils/DataloaderUtils.js +15 -12
- package/utils/EntityComparator.d.ts +8 -15
- package/utils/EntityComparator.js +100 -92
- package/utils/QueryHelper.d.ts +16 -1
- package/utils/QueryHelper.js +108 -50
- package/utils/RawQueryFragment.d.ts +4 -4
- package/utils/RawQueryFragment.js +3 -2
- package/utils/TransactionManager.js +3 -3
- package/utils/Utils.d.ts +2 -2
- package/utils/Utils.js +39 -32
- package/utils/clone.js +5 -0
- package/utils/env-vars.js +6 -5
- package/utils/fs-utils.d.ts +3 -17
- package/utils/fs-utils.js +2 -5
- package/utils/upsert-utils.js +7 -4
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
import { clone } from './clone.js';
|
|
2
2
|
import { ReferenceKind } from '../enums.js';
|
|
3
|
-
import { compareArrays, compareBooleans, compareBuffers, compareObjects, equals, parseJsonSafe, Utils } from './Utils.js';
|
|
3
|
+
import { compareArrays, compareBooleans, compareBuffers, compareObjects, equals, parseJsonSafe, Utils, } from './Utils.js';
|
|
4
4
|
import { JsonType } from '../types/JsonType.js';
|
|
5
5
|
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;
|
|
@@ -91,18 +91,17 @@ export class EntityComparator {
|
|
|
91
91
|
}
|
|
92
92
|
lines.push(` return entity${this.wrap(pk)};`);
|
|
93
93
|
}
|
|
94
|
-
const code = `// compiled pk getter for entity ${meta.className}\n`
|
|
95
|
-
+ `return function(entity) {\n${lines.join('\n')}\n}`;
|
|
94
|
+
const code = `// compiled pk getter for entity ${meta.className}\n` + `return function(entity) {\n${lines.join('\n')}\n}`;
|
|
96
95
|
const fnKey = `pkGetter-${meta.uniqueName}`;
|
|
97
|
-
const pkSerializer = Utils.createFunction(context, code, this
|
|
98
|
-
this
|
|
96
|
+
const pkSerializer = Utils.createFunction(context, code, this.#config?.get('compiledFunctions'), fnKey);
|
|
97
|
+
this.#pkGetters.set(meta, pkSerializer);
|
|
99
98
|
return pkSerializer;
|
|
100
99
|
}
|
|
101
100
|
/**
|
|
102
101
|
* @internal Highly performance-sensitive method.
|
|
103
102
|
*/
|
|
104
103
|
getPkGetterConverted(meta) {
|
|
105
|
-
const exists = this
|
|
104
|
+
const exists = this.#pkGettersConverted.get(meta);
|
|
106
105
|
/* v8 ignore next */
|
|
107
106
|
if (exists) {
|
|
108
107
|
return exists;
|
|
@@ -142,25 +141,25 @@ export class EntityComparator {
|
|
|
142
141
|
lines.push(` return entity${this.wrap(pk)};`);
|
|
143
142
|
}
|
|
144
143
|
}
|
|
145
|
-
const code = `// compiled pk getter (with converted custom types) for entity ${meta.className}\n`
|
|
146
|
-
|
|
144
|
+
const code = `// compiled pk getter (with converted custom types) for entity ${meta.className}\n` +
|
|
145
|
+
`return function(entity) {\n${lines.join('\n')}\n}`;
|
|
147
146
|
const fnKey = `pkGetterConverted-${meta.uniqueName}`;
|
|
148
|
-
const pkSerializer = Utils.createFunction(context, code, this
|
|
149
|
-
this
|
|
147
|
+
const pkSerializer = Utils.createFunction(context, code, this.#config?.get('compiledFunctions'), fnKey);
|
|
148
|
+
this.#pkGettersConverted.set(meta, pkSerializer);
|
|
150
149
|
return pkSerializer;
|
|
151
150
|
}
|
|
152
151
|
/**
|
|
153
152
|
* @internal Highly performance-sensitive method.
|
|
154
153
|
*/
|
|
155
154
|
getPkSerializer(meta) {
|
|
156
|
-
const exists = this
|
|
155
|
+
const exists = this.#pkSerializers.get(meta);
|
|
157
156
|
/* v8 ignore next */
|
|
158
157
|
if (exists) {
|
|
159
158
|
return exists;
|
|
160
159
|
}
|
|
161
160
|
const lines = [];
|
|
162
161
|
const context = new Map();
|
|
163
|
-
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)));
|
|
164
163
|
context.set('getPrimaryKeyHash', (val) => Utils.getPrimaryKeyHash(Utils.asArray(val)));
|
|
165
164
|
if (meta.primaryKeys.length > 1) {
|
|
166
165
|
lines.push(` const pks = entity.__helper.__pk ? getCompositeKeyValue(entity.__helper.__pk) : [`);
|
|
@@ -187,7 +186,7 @@ export class EntityComparator {
|
|
|
187
186
|
}
|
|
188
187
|
else if (prop.customType) {
|
|
189
188
|
const convertorKey = this.registerCustomType(meta.properties[pk], context);
|
|
190
|
-
const idx = this
|
|
189
|
+
const idx = this.#tmpIndex++;
|
|
191
190
|
lines.push(` const val_${idx} = convertToDatabaseValue_${convertorKey}(entity${this.wrap(pk)});`);
|
|
192
191
|
lines.push(` return getPrimaryKeyHash(val_${idx});`);
|
|
193
192
|
}
|
|
@@ -195,26 +194,25 @@ export class EntityComparator {
|
|
|
195
194
|
lines.push(` return '' + entity${this.wrap(pk)};`);
|
|
196
195
|
}
|
|
197
196
|
}
|
|
198
|
-
const code = `// compiled pk serializer for entity ${meta.className}\n`
|
|
199
|
-
+ `return function(entity) {\n${lines.join('\n')}\n}`;
|
|
197
|
+
const code = `// compiled pk serializer for entity ${meta.className}\n` + `return function(entity) {\n${lines.join('\n')}\n}`;
|
|
200
198
|
const fnKey = `pkSerializer-${meta.uniqueName}`;
|
|
201
|
-
const pkSerializer = Utils.createFunction(context, code, this
|
|
202
|
-
this
|
|
199
|
+
const pkSerializer = Utils.createFunction(context, code, this.#config?.get('compiledFunctions'), fnKey);
|
|
200
|
+
this.#pkSerializers.set(meta, pkSerializer);
|
|
203
201
|
return pkSerializer;
|
|
204
202
|
}
|
|
205
203
|
/**
|
|
206
204
|
* @internal Highly performance-sensitive method.
|
|
207
205
|
*/
|
|
208
206
|
getSnapshotGenerator(entityName) {
|
|
209
|
-
const meta = this
|
|
210
|
-
const exists = this
|
|
207
|
+
const meta = this.#metadata.find(entityName);
|
|
208
|
+
const exists = this.#snapshotGenerators.get(meta);
|
|
211
209
|
if (exists) {
|
|
212
210
|
return exists;
|
|
213
211
|
}
|
|
214
212
|
const lines = [];
|
|
215
213
|
const context = new Map();
|
|
216
214
|
context.set('clone', clone);
|
|
217
|
-
context.set('cloneEmbeddable', (o) => this
|
|
215
|
+
context.set('cloneEmbeddable', (o) => this.#platform.cloneEmbeddable(o)); // do not clone prototypes
|
|
218
216
|
if (meta.root.inheritanceType === 'sti' && meta.discriminatorValue) {
|
|
219
217
|
lines.push(` ret${this.wrap(meta.root.discriminatorColumn)} = '${meta.discriminatorValue}'`);
|
|
220
218
|
}
|
|
@@ -228,8 +226,8 @@ export class EntityComparator {
|
|
|
228
226
|
.forEach(prop => lines.push(this.getPropertySnapshot(meta, prop, context, this.wrap(prop.name), this.wrap(prop.name), [prop.name])));
|
|
229
227
|
const code = `return function(entity) {\n const ret = {};\n${lines.join('\n')}\n return ret;\n}`;
|
|
230
228
|
const fnKey = `snapshotGenerator-${meta.uniqueName}`;
|
|
231
|
-
const snapshotGenerator = Utils.createFunction(context, code, this
|
|
232
|
-
this
|
|
229
|
+
const snapshotGenerator = Utils.createFunction(context, code, this.#config?.get('compiledFunctions'), fnKey);
|
|
230
|
+
this.#snapshotGenerators.set(meta, snapshotGenerator);
|
|
233
231
|
return snapshotGenerator;
|
|
234
232
|
}
|
|
235
233
|
/**
|
|
@@ -273,21 +271,21 @@ export class EntityComparator {
|
|
|
273
271
|
if (part.length === 1) {
|
|
274
272
|
return this.formatCompositeKeyPart(part[0]);
|
|
275
273
|
}
|
|
276
|
-
const formatted = part.map(this.formatCompositeKeyPart).join(', ');
|
|
274
|
+
const formatted = part.map(p => this.formatCompositeKeyPart(p)).join(', ');
|
|
277
275
|
return `[${formatted}]`;
|
|
278
276
|
}
|
|
279
277
|
/**
|
|
280
278
|
* @internal Highly performance-sensitive method.
|
|
281
279
|
*/
|
|
282
280
|
getResultMapper(meta) {
|
|
283
|
-
const exists = this
|
|
281
|
+
const exists = this.#mappers.get(meta);
|
|
284
282
|
if (exists) {
|
|
285
283
|
return exists;
|
|
286
284
|
}
|
|
287
285
|
const lines = [];
|
|
288
286
|
const context = new Map();
|
|
289
287
|
context.set('PolymorphicRef', PolymorphicRef);
|
|
290
|
-
const tz = this
|
|
288
|
+
const tz = this.#platform.getTimezone();
|
|
291
289
|
const parseDate = (key, value, padding = '') => {
|
|
292
290
|
lines.push(`${padding} if (${value} == null || ${value} instanceof Date) {`);
|
|
293
291
|
lines.push(`${padding} ${key} = ${value};`);
|
|
@@ -347,19 +345,19 @@ export class EntityComparator {
|
|
|
347
345
|
lines.push(`${padding} ${this.propName(prop.fieldNames[0], 'mapped')} = true;`);
|
|
348
346
|
lines.push(`${padding} }`);
|
|
349
347
|
}
|
|
350
|
-
else if (prop.runtimeType === 'Date' && !this
|
|
348
|
+
else if (prop.runtimeType === 'Date' && !this.#platform.isNumericProperty(prop)) {
|
|
351
349
|
lines.push(`${padding} if (typeof ${this.propName(prop.fieldNames[0])} !== 'undefined') {`);
|
|
352
|
-
context.set('parseDate', (value) => this
|
|
350
|
+
context.set('parseDate', (value) => this.#platform.parseDate(value));
|
|
353
351
|
parseDate('ret' + this.wrap(prop.name), this.propName(prop.fieldNames[0]), padding);
|
|
354
352
|
lines.push(`${padding} ${this.propName(prop.fieldNames[0], 'mapped')} = true;`);
|
|
355
353
|
lines.push(`${padding} }`);
|
|
356
354
|
}
|
|
357
355
|
else if (prop.kind === ReferenceKind.EMBEDDED && (prop.object || meta.embeddable)) {
|
|
358
|
-
const idx = this
|
|
356
|
+
const idx = this.#tmpIndex++;
|
|
359
357
|
context.set(`mapEmbeddedResult_${idx}`, (data) => {
|
|
360
358
|
const item = parseJsonSafe(data);
|
|
361
359
|
if (Array.isArray(item)) {
|
|
362
|
-
return item.map(row => row == null ? row : this.getResultMapper(prop.targetMeta)(row));
|
|
360
|
+
return item.map(row => (row == null ? row : this.getResultMapper(prop.targetMeta)(row)));
|
|
363
361
|
}
|
|
364
362
|
return item == null ? item : this.getResultMapper(prop.targetMeta)(item);
|
|
365
363
|
});
|
|
@@ -391,11 +389,11 @@ export class EntityComparator {
|
|
|
391
389
|
mapEntityProperties(meta);
|
|
392
390
|
}
|
|
393
391
|
lines.push(` for (let k in result) { if (Object.hasOwn(result, k) && !mapped[k] && ret[k] === undefined) ret[k] = result[k]; }`);
|
|
394
|
-
const code = `// compiled mapper for entity ${meta.className}\n`
|
|
395
|
-
|
|
392
|
+
const code = `// compiled mapper for entity ${meta.className}\n` +
|
|
393
|
+
`return function(result) {\n const ret = {};\n${lines.join('\n')}\n return ret;\n}`;
|
|
396
394
|
const fnKey = `resultMapper-${meta.uniqueName}`;
|
|
397
|
-
const resultMapper = Utils.createFunction(context, code, this
|
|
398
|
-
this
|
|
395
|
+
const resultMapper = Utils.createFunction(context, code, this.#config?.get('compiledFunctions'), fnKey);
|
|
396
|
+
this.#mappers.set(meta, resultMapper);
|
|
399
397
|
return resultMapper;
|
|
400
398
|
}
|
|
401
399
|
getPropertyCondition(path) {
|
|
@@ -406,12 +404,12 @@ export class EntityComparator {
|
|
|
406
404
|
let tail = '';
|
|
407
405
|
return parts
|
|
408
406
|
.map(k => {
|
|
409
|
-
if (
|
|
407
|
+
if (/^\[idx_\d+]$/.exec(k)) {
|
|
410
408
|
tail += k;
|
|
411
409
|
return '';
|
|
412
410
|
}
|
|
413
411
|
const mapped = `typeof entity${tail ? '.' + tail : ''}${this.wrap(k)} !== 'undefined'`;
|
|
414
|
-
tail += tail ?
|
|
412
|
+
tail += tail ? '.' + k : k;
|
|
415
413
|
return mapped;
|
|
416
414
|
})
|
|
417
415
|
.filter(k => k)
|
|
@@ -421,7 +419,7 @@ export class EntityComparator {
|
|
|
421
419
|
const entityKey = path.map(k => this.wrap(k)).join('');
|
|
422
420
|
const ret = [];
|
|
423
421
|
const padding = ' '.repeat(level * 2);
|
|
424
|
-
const idx = this
|
|
422
|
+
const idx = this.#tmpIndex++;
|
|
425
423
|
ret.push(`${padding}if (Array.isArray(entity${entityKey})) {`);
|
|
426
424
|
ret.push(`${padding} ret${dataKey} = [];`);
|
|
427
425
|
ret.push(`${padding} entity${entityKey}.forEach((_, idx_${idx}) => {`);
|
|
@@ -447,18 +445,22 @@ export class EntityComparator {
|
|
|
447
445
|
getEmbeddedPropertySnapshot(meta, prop, context, level, path, dataKey, object = prop.object) {
|
|
448
446
|
const padding = ' '.repeat(level * 2);
|
|
449
447
|
const nullCond = `entity${path.map(k => this.wrap(k)).join('')} === null`;
|
|
450
|
-
let ret =
|
|
448
|
+
let ret = level === 1 ? '' : '\n';
|
|
451
449
|
if (object) {
|
|
452
450
|
ret += `${padding}if (${nullCond}) ret${dataKey} = null;\n`;
|
|
453
451
|
}
|
|
454
452
|
else {
|
|
455
453
|
ret += `${padding}if (${nullCond}) {\n`;
|
|
456
|
-
ret +=
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
454
|
+
ret +=
|
|
455
|
+
meta.props
|
|
456
|
+
.filter(p => p.embedded?.[0] === prop.name &&
|
|
457
|
+
// object for JSON embeddable
|
|
458
|
+
(p.object || p.persist !== false))
|
|
459
|
+
.map(childProp => {
|
|
460
|
+
const childDataKey = meta.embeddable || prop.object ? dataKey + this.wrap(childProp.embedded[1]) : this.wrap(childProp.name);
|
|
461
|
+
return `${padding} ret${childDataKey} = null;`;
|
|
462
|
+
})
|
|
463
|
+
.join('\n') + `\n`;
|
|
462
464
|
ret += `${padding}}\n`;
|
|
463
465
|
}
|
|
464
466
|
const cond = `entity${path.map(k => this.wrap(k)).join('')} != null`;
|
|
@@ -475,28 +477,34 @@ export class EntityComparator {
|
|
|
475
477
|
}
|
|
476
478
|
return true;
|
|
477
479
|
}
|
|
478
|
-
ret +=
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
.split('\n').map(l => padding + l).join('\n');
|
|
490
|
-
}
|
|
491
|
-
if (shouldProcessCustomType(childProp)) {
|
|
492
|
-
const convertorKey = this.registerCustomType(childProp, context);
|
|
493
|
-
if (['number', 'string', 'boolean', 'bigint'].includes(childProp.customType.compareAsType().toLowerCase())) {
|
|
494
|
-
return `${padding} if (${childCond}) ret${childDataKey} = convertToDatabaseValue_${convertorKey}(entity${childEntityKey});`;
|
|
480
|
+
ret +=
|
|
481
|
+
meta.props
|
|
482
|
+
.filter(p => p.embedded?.[0] === prop.name &&
|
|
483
|
+
// object for JSON embeddable
|
|
484
|
+
(p.object || p.persist !== false))
|
|
485
|
+
.map(childProp => {
|
|
486
|
+
const childDataKey = meta.embeddable || prop.object ? dataKey + this.wrap(childProp.embedded[1]) : this.wrap(childProp.name);
|
|
487
|
+
const childEntityKey = [...path, childProp.embedded[1]].map(k => this.wrap(k)).join('');
|
|
488
|
+
const childCond = `typeof entity${childEntityKey} !== 'undefined'`;
|
|
489
|
+
if (childProp.kind === ReferenceKind.EMBEDDED) {
|
|
490
|
+
return this.getPropertySnapshot(meta, childProp, context, childDataKey, childEntityKey, [...path, childProp.embedded[1]], level + 1, prop.object);
|
|
495
491
|
}
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
492
|
+
if (childProp.kind !== ReferenceKind.SCALAR) {
|
|
493
|
+
return this.getPropertySnapshot(meta, childProp, context, childDataKey, childEntityKey, [...path, childProp.embedded[1]], level, prop.object)
|
|
494
|
+
.split('\n')
|
|
495
|
+
.map(l => padding + l)
|
|
496
|
+
.join('\n');
|
|
497
|
+
}
|
|
498
|
+
if (shouldProcessCustomType(childProp)) {
|
|
499
|
+
const convertorKey = this.registerCustomType(childProp, context);
|
|
500
|
+
if (['number', 'string', 'boolean', 'bigint'].includes(childProp.customType.compareAsType().toLowerCase())) {
|
|
501
|
+
return `${padding} if (${childCond}) ret${childDataKey} = convertToDatabaseValue_${convertorKey}(entity${childEntityKey});`;
|
|
502
|
+
}
|
|
503
|
+
return `${padding} if (${childCond}) ret${childDataKey} = clone(convertToDatabaseValue_${convertorKey}(entity${childEntityKey}));`;
|
|
504
|
+
}
|
|
505
|
+
return `${padding} if (${childCond}) ret${childDataKey} = clone(entity${childEntityKey});`;
|
|
506
|
+
})
|
|
507
|
+
.join('\n') + `\n`;
|
|
500
508
|
if (this.shouldSerialize(prop, dataKey)) {
|
|
501
509
|
return `${ret + padding} ret${dataKey} = cloneEmbeddable(ret${dataKey});\n${padding}}`;
|
|
502
510
|
}
|
|
@@ -509,7 +517,7 @@ export class EntityComparator {
|
|
|
509
517
|
if (Raw.isKnownFragment(val)) {
|
|
510
518
|
return val;
|
|
511
519
|
}
|
|
512
|
-
return prop.customType.convertToDatabaseValue(val, this
|
|
520
|
+
return prop.customType.convertToDatabaseValue(val, this.#platform, { mode: 'serialization' });
|
|
513
521
|
});
|
|
514
522
|
return convertorKey;
|
|
515
523
|
}
|
|
@@ -591,10 +599,10 @@ export class EntityComparator {
|
|
|
591
599
|
if (['number', 'string', 'boolean', 'bigint'].includes(prop.customType.compareAsType().toLowerCase())) {
|
|
592
600
|
return ret + ` ret${dataKey} = convertToDatabaseValue_${convertorKey}(entity${entityKey}${unwrap});\n }\n`;
|
|
593
601
|
}
|
|
594
|
-
return ret + ` ret${dataKey} = clone(convertToDatabaseValue_${convertorKey}(entity${entityKey}${unwrap}));\n }\n
|
|
602
|
+
return (ret + ` ret${dataKey} = clone(convertToDatabaseValue_${convertorKey}(entity${entityKey}${unwrap}));\n }\n`);
|
|
595
603
|
}
|
|
596
604
|
if (prop.runtimeType === 'Date') {
|
|
597
|
-
context.set('processDateProperty', this
|
|
605
|
+
context.set('processDateProperty', this.#platform.processDateProperty.bind(this.#platform));
|
|
598
606
|
return ret + ` ret${dataKey} = clone(processDateProperty(entity${entityKey}${unwrap}));\n }\n`;
|
|
599
607
|
}
|
|
600
608
|
return ret + ` ret${dataKey} = clone(entity${entityKey}${unwrap});\n }\n`;
|
|
@@ -603,8 +611,8 @@ export class EntityComparator {
|
|
|
603
611
|
* @internal Highly performance-sensitive method.
|
|
604
612
|
*/
|
|
605
613
|
getEntityComparator(entityName) {
|
|
606
|
-
const meta = this
|
|
607
|
-
const exists = this
|
|
614
|
+
const meta = this.#metadata.find(entityName);
|
|
615
|
+
const exists = this.#comparators.get(meta);
|
|
608
616
|
if (exists) {
|
|
609
617
|
return exists;
|
|
610
618
|
}
|
|
@@ -626,22 +634,22 @@ export class EntityComparator {
|
|
|
626
634
|
}
|
|
627
635
|
}
|
|
628
636
|
lines.push(`}`);
|
|
629
|
-
const code = `// compiled comparator for entity ${meta.className}\n`
|
|
630
|
-
|
|
637
|
+
const code = `// compiled comparator for entity ${meta.className}\n` +
|
|
638
|
+
`return function(last, current, options) {\n const diff = {};\n${lines.join('\n')}\n return diff;\n}`;
|
|
631
639
|
const fnKey = `comparator-${meta.uniqueName}`;
|
|
632
|
-
const comparator = Utils.createFunction(context, code, this
|
|
633
|
-
this
|
|
640
|
+
const comparator = Utils.createFunction(context, code, this.#config?.get('compiledFunctions'), fnKey);
|
|
641
|
+
this.#comparators.set(meta, comparator);
|
|
634
642
|
return comparator;
|
|
635
643
|
}
|
|
636
644
|
getGenericComparator(prop, cond) {
|
|
637
|
-
return ` if (current${prop} === null && last${prop} === undefined) {\n` +
|
|
645
|
+
return (` if (current${prop} === null && last${prop} === undefined) {\n` +
|
|
638
646
|
` diff${prop} = current${prop};\n` +
|
|
639
647
|
` } else if (current${prop} == null && last${prop} == null) {\n\n` +
|
|
640
648
|
` } else if ((current${prop} != null && last${prop} == null) || (current${prop} == null && last${prop} != null)) {\n` +
|
|
641
649
|
` diff${prop} = current${prop};\n` +
|
|
642
650
|
` } else if (${cond}) {\n` +
|
|
643
651
|
` diff${prop} = current${prop};\n` +
|
|
644
|
-
` }\n
|
|
652
|
+
` }\n`);
|
|
645
653
|
}
|
|
646
654
|
getPropertyComparator(prop, context) {
|
|
647
655
|
let type = prop.type.toLowerCase();
|
|
@@ -661,7 +669,7 @@ export class EntityComparator {
|
|
|
661
669
|
}
|
|
662
670
|
if (prop.customType) {
|
|
663
671
|
if (prop.customType.compareValues) {
|
|
664
|
-
const idx = this
|
|
672
|
+
const idx = this.#tmpIndex++;
|
|
665
673
|
context.set(`compareValues_${idx}`, (a, b) => {
|
|
666
674
|
if (Raw.isKnownFragment(a) || Raw.isKnownFragment(b)) {
|
|
667
675
|
return Raw.getKnownFragment(a) === Raw.getKnownFragment(b);
|
|
@@ -700,10 +708,10 @@ export class EntityComparator {
|
|
|
700
708
|
return this.getGenericComparator(this.wrap(prop.name), `!equals(last${this.wrap(prop.name)}, current${this.wrap(prop.name)})`);
|
|
701
709
|
}
|
|
702
710
|
wrap(key) {
|
|
703
|
-
if (
|
|
711
|
+
if (/^\[.*]$/.exec(key)) {
|
|
704
712
|
return key;
|
|
705
713
|
}
|
|
706
|
-
return
|
|
714
|
+
return /^\w+$/.exec(key) ? `.${key}` : `['${key}']`;
|
|
707
715
|
}
|
|
708
716
|
safeKey(key) {
|
|
709
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).
|