@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.
Files changed (114) hide show
  1. package/EntityManager.d.ts +4 -16
  2. package/EntityManager.js +248 -181
  3. package/MikroORM.d.ts +4 -6
  4. package/MikroORM.js +24 -24
  5. package/README.md +5 -4
  6. package/cache/FileCacheAdapter.d.ts +1 -5
  7. package/cache/FileCacheAdapter.js +22 -24
  8. package/cache/GeneratedCacheAdapter.d.ts +1 -1
  9. package/cache/GeneratedCacheAdapter.js +6 -6
  10. package/cache/MemoryCacheAdapter.d.ts +1 -2
  11. package/cache/MemoryCacheAdapter.js +8 -8
  12. package/cache/index.d.ts +1 -1
  13. package/cache/index.js +0 -1
  14. package/connections/Connection.d.ts +1 -0
  15. package/connections/Connection.js +43 -14
  16. package/drivers/DatabaseDriver.d.ts +0 -2
  17. package/drivers/DatabaseDriver.js +28 -12
  18. package/drivers/IDatabaseDriver.d.ts +43 -0
  19. package/entity/Collection.d.ts +1 -9
  20. package/entity/Collection.js +124 -108
  21. package/entity/EntityAssigner.js +23 -11
  22. package/entity/EntityFactory.d.ts +1 -8
  23. package/entity/EntityFactory.js +79 -59
  24. package/entity/EntityHelper.js +25 -16
  25. package/entity/EntityLoader.d.ts +1 -3
  26. package/entity/EntityLoader.js +90 -60
  27. package/entity/Reference.d.ts +2 -3
  28. package/entity/Reference.js +48 -19
  29. package/entity/WrappedEntity.d.ts +4 -2
  30. package/entity/WrappedEntity.js +5 -1
  31. package/entity/defineEntity.d.ts +42 -85
  32. package/entity/utils.js +28 -26
  33. package/entity/validators.js +2 -1
  34. package/enums.d.ts +2 -1
  35. package/enums.js +13 -17
  36. package/errors.d.ts +11 -11
  37. package/errors.js +8 -8
  38. package/events/EventManager.d.ts +1 -4
  39. package/events/EventManager.js +26 -23
  40. package/events/index.d.ts +1 -1
  41. package/events/index.js +0 -1
  42. package/exceptions.js +9 -2
  43. package/hydration/ObjectHydrator.d.ts +1 -2
  44. package/hydration/ObjectHydrator.js +41 -27
  45. package/index.d.ts +1 -1
  46. package/index.js +1 -1
  47. package/logging/DefaultLogger.js +6 -7
  48. package/logging/Logger.d.ts +2 -1
  49. package/logging/colors.js +2 -5
  50. package/logging/index.d.ts +1 -1
  51. package/logging/index.js +0 -1
  52. package/metadata/EntitySchema.d.ts +3 -3
  53. package/metadata/EntitySchema.js +12 -2
  54. package/metadata/MetadataDiscovery.d.ts +1 -9
  55. package/metadata/MetadataDiscovery.js +251 -179
  56. package/metadata/MetadataProvider.js +26 -1
  57. package/metadata/MetadataStorage.d.ts +1 -5
  58. package/metadata/MetadataStorage.js +37 -39
  59. package/metadata/MetadataValidator.js +20 -5
  60. package/metadata/discover-entities.js +1 -1
  61. package/metadata/index.d.ts +1 -1
  62. package/metadata/index.js +0 -1
  63. package/metadata/types.d.ts +2 -2
  64. package/naming-strategy/AbstractNamingStrategy.js +6 -3
  65. package/naming-strategy/EntityCaseNamingStrategy.js +1 -1
  66. package/naming-strategy/index.d.ts +1 -1
  67. package/naming-strategy/index.js +0 -1
  68. package/not-supported.js +5 -1
  69. package/package.json +38 -38
  70. package/platforms/Platform.d.ts +24 -1
  71. package/platforms/Platform.js +106 -27
  72. package/serialization/EntitySerializer.js +8 -4
  73. package/serialization/EntityTransformer.js +4 -1
  74. package/serialization/SerializationContext.d.ts +4 -8
  75. package/serialization/SerializationContext.js +21 -16
  76. package/types/UuidType.d.ts +2 -0
  77. package/types/UuidType.js +14 -2
  78. package/types/index.d.ts +2 -1
  79. package/typings.d.ts +35 -24
  80. package/typings.js +9 -9
  81. package/unit-of-work/ChangeSet.js +4 -4
  82. package/unit-of-work/ChangeSetComputer.d.ts +1 -6
  83. package/unit-of-work/ChangeSetComputer.js +29 -27
  84. package/unit-of-work/ChangeSetPersister.d.ts +1 -9
  85. package/unit-of-work/ChangeSetPersister.js +63 -58
  86. package/unit-of-work/CommitOrderCalculator.d.ts +1 -4
  87. package/unit-of-work/CommitOrderCalculator.js +17 -15
  88. package/unit-of-work/IdentityMap.d.ts +2 -5
  89. package/unit-of-work/IdentityMap.js +18 -18
  90. package/unit-of-work/UnitOfWork.d.ts +12 -20
  91. package/unit-of-work/UnitOfWork.js +228 -191
  92. package/utils/AbstractMigrator.d.ts +2 -2
  93. package/utils/AbstractMigrator.js +10 -12
  94. package/utils/AbstractSchemaGenerator.js +2 -1
  95. package/utils/AsyncContext.js +1 -1
  96. package/utils/Configuration.d.ts +90 -189
  97. package/utils/Configuration.js +97 -77
  98. package/utils/Cursor.d.ts +3 -3
  99. package/utils/Cursor.js +8 -6
  100. package/utils/DataloaderUtils.js +15 -12
  101. package/utils/EntityComparator.d.ts +8 -15
  102. package/utils/EntityComparator.js +100 -92
  103. package/utils/QueryHelper.d.ts +16 -1
  104. package/utils/QueryHelper.js +108 -50
  105. package/utils/RawQueryFragment.d.ts +4 -4
  106. package/utils/RawQueryFragment.js +3 -2
  107. package/utils/TransactionManager.js +3 -3
  108. package/utils/Utils.d.ts +2 -2
  109. package/utils/Utils.js +39 -32
  110. package/utils/clone.js +5 -0
  111. package/utils/env-vars.js +6 -5
  112. package/utils/fs-utils.d.ts +3 -17
  113. package/utils/fs-utils.js +2 -5
  114. 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
- metadata;
10
- platform;
11
- config;
12
- comparators = new Map();
13
- mappers = new Map();
14
- snapshotGenerators = new Map();
15
- pkGetters = new Map();
16
- pkGettersConverted = new Map();
17
- pkSerializers = new Map();
18
- tmpIndex = 0;
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.metadata = metadata;
21
- this.platform = platform;
22
- this.config = config;
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.pkGetters.get(meta);
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.config?.get('compiledFunctions'), fnKey);
98
- this.pkGetters.set(meta, pkSerializer);
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.pkGettersConverted.get(meta);
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
- + `return function(entity) {\n${lines.join('\n')}\n}`;
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.config?.get('compiledFunctions'), fnKey);
149
- this.pkGettersConverted.set(meta, pkSerializer);
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.pkSerializers.get(meta);
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.platform)));
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.tmpIndex++;
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.config?.get('compiledFunctions'), fnKey);
202
- this.pkSerializers.set(meta, pkSerializer);
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.metadata.find(entityName);
210
- const exists = this.snapshotGenerators.get(meta);
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.platform.cloneEmbeddable(o)); // do not clone prototypes
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.config?.get('compiledFunctions'), fnKey);
232
- this.snapshotGenerators.set(meta, snapshotGenerator);
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.mappers.get(meta);
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.platform.getTimezone();
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.platform.isNumericProperty(prop)) {
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.platform.parseDate(value));
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.tmpIndex++;
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
- + `return function(result) {\n const ret = {};\n${lines.join('\n')}\n return ret;\n}`;
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.config?.get('compiledFunctions'), fnKey);
398
- this.mappers.set(meta, resultMapper);
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 (k.match(/^\[idx_\d+]$/)) {
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 ? ('.' + k) : k;
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.tmpIndex++;
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 = `${level === 1 ? '' : '\n'}`;
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 += meta.props.filter(p => p.embedded?.[0] === prop.name
457
- // object for JSON embeddable
458
- && (p.object || (p.persist !== false))).map(childProp => {
459
- const childDataKey = meta.embeddable || prop.object ? dataKey + this.wrap(childProp.embedded[1]) : this.wrap(childProp.name);
460
- return `${padding} ret${childDataKey} = null;`;
461
- }).join('\n') + `\n`;
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 += meta.props.filter(p => p.embedded?.[0] === prop.name
479
- // object for JSON embeddable
480
- && (p.object || (p.persist !== false))).map(childProp => {
481
- const childDataKey = meta.embeddable || prop.object ? dataKey + this.wrap(childProp.embedded[1]) : this.wrap(childProp.name);
482
- const childEntityKey = [...path, childProp.embedded[1]].map(k => this.wrap(k)).join('');
483
- const childCond = `typeof entity${childEntityKey} !== 'undefined'`;
484
- if (childProp.kind === ReferenceKind.EMBEDDED) {
485
- return this.getPropertySnapshot(meta, childProp, context, childDataKey, childEntityKey, [...path, childProp.embedded[1]], level + 1, prop.object);
486
- }
487
- if (childProp.kind !== ReferenceKind.SCALAR) {
488
- return this.getPropertySnapshot(meta, childProp, context, childDataKey, childEntityKey, [...path, childProp.embedded[1]], level, prop.object)
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
- return `${padding} if (${childCond}) ret${childDataKey} = clone(convertToDatabaseValue_${convertorKey}(entity${childEntityKey}));`;
497
- }
498
- return `${padding} if (${childCond}) ret${childDataKey} = clone(entity${childEntityKey});`;
499
- }).join('\n') + `\n`;
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.platform, { mode: 'serialization' });
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.platform.processDateProperty.bind(this.platform));
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.metadata.find(entityName);
607
- const exists = this.comparators.get(meta);
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
- + `return function(last, current, options) {\n const diff = {};\n${lines.join('\n')}\n return diff;\n}`;
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.config?.get('compiledFunctions'), fnKey);
633
- this.comparators.set(meta, comparator);
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.tmpIndex++;
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 (key.match(/^\[.*]$/)) {
711
+ if (/^\[.*]$/.exec(key)) {
704
712
  return key;
705
713
  }
706
- return key.match(/^\w+$/) ? `.${key}` : `['${key}']`;
714
+ return /^\w+$/.exec(key) ? `.${key}` : `['${key}']`;
707
715
  }
708
716
  safeKey(key) {
709
717
  return key.replace(/\W/g, '_');
@@ -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).