@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.
Files changed (94) hide show
  1. package/EntityManager.d.ts +2 -15
  2. package/EntityManager.js +155 -152
  3. package/MikroORM.d.ts +4 -6
  4. package/MikroORM.js +20 -20
  5. package/README.md +5 -4
  6. package/cache/FileCacheAdapter.d.ts +1 -5
  7. package/cache/FileCacheAdapter.js +22 -22
  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 +27 -11
  16. package/drivers/DatabaseDriver.d.ts +0 -2
  17. package/drivers/DatabaseDriver.js +2 -4
  18. package/entity/Collection.d.ts +1 -9
  19. package/entity/Collection.js +95 -105
  20. package/entity/EntityFactory.d.ts +1 -8
  21. package/entity/EntityFactory.js +48 -48
  22. package/entity/EntityLoader.d.ts +1 -3
  23. package/entity/EntityLoader.js +36 -39
  24. package/entity/Reference.d.ts +1 -2
  25. package/entity/Reference.js +11 -11
  26. package/entity/WrappedEntity.d.ts +4 -2
  27. package/entity/defineEntity.d.ts +18 -73
  28. package/enums.d.ts +2 -1
  29. package/enums.js +1 -0
  30. package/errors.d.ts +11 -11
  31. package/errors.js +3 -13
  32. package/events/EventManager.d.ts +1 -4
  33. package/events/EventManager.js +25 -22
  34. package/events/index.d.ts +1 -1
  35. package/events/index.js +0 -1
  36. package/exceptions.js +8 -6
  37. package/hydration/ObjectHydrator.d.ts +1 -2
  38. package/hydration/ObjectHydrator.js +16 -16
  39. package/logging/DefaultLogger.js +3 -2
  40. package/logging/Logger.d.ts +2 -1
  41. package/logging/colors.js +1 -1
  42. package/logging/index.d.ts +1 -1
  43. package/logging/index.js +0 -1
  44. package/metadata/EntitySchema.d.ts +1 -1
  45. package/metadata/MetadataDiscovery.d.ts +1 -9
  46. package/metadata/MetadataDiscovery.js +162 -149
  47. package/metadata/MetadataStorage.d.ts +1 -5
  48. package/metadata/MetadataStorage.js +36 -36
  49. package/metadata/discover-entities.js +1 -1
  50. package/metadata/index.d.ts +1 -1
  51. package/metadata/index.js +0 -1
  52. package/naming-strategy/AbstractNamingStrategy.js +1 -1
  53. package/naming-strategy/EntityCaseNamingStrategy.js +1 -1
  54. package/naming-strategy/index.d.ts +1 -1
  55. package/naming-strategy/index.js +0 -1
  56. package/package.json +1 -1
  57. package/platforms/Platform.d.ts +23 -1
  58. package/platforms/Platform.js +57 -4
  59. package/serialization/EntitySerializer.js +1 -1
  60. package/serialization/EntityTransformer.js +4 -1
  61. package/serialization/SerializationContext.d.ts +4 -8
  62. package/serialization/SerializationContext.js +20 -15
  63. package/types/UuidType.d.ts +2 -0
  64. package/types/UuidType.js +14 -2
  65. package/types/index.d.ts +2 -1
  66. package/typings.d.ts +12 -1
  67. package/unit-of-work/ChangeSetComputer.d.ts +1 -6
  68. package/unit-of-work/ChangeSetComputer.js +21 -21
  69. package/unit-of-work/ChangeSetPersister.d.ts +1 -9
  70. package/unit-of-work/ChangeSetPersister.js +52 -52
  71. package/unit-of-work/CommitOrderCalculator.d.ts +1 -4
  72. package/unit-of-work/CommitOrderCalculator.js +13 -13
  73. package/unit-of-work/IdentityMap.d.ts +2 -5
  74. package/unit-of-work/IdentityMap.js +18 -18
  75. package/unit-of-work/UnitOfWork.d.ts +5 -19
  76. package/unit-of-work/UnitOfWork.js +182 -174
  77. package/utils/AbstractMigrator.d.ts +1 -1
  78. package/utils/AbstractMigrator.js +7 -7
  79. package/utils/Configuration.d.ts +90 -189
  80. package/utils/Configuration.js +94 -78
  81. package/utils/Cursor.d.ts +3 -3
  82. package/utils/Cursor.js +4 -4
  83. package/utils/EntityComparator.d.ts +8 -15
  84. package/utils/EntityComparator.js +49 -49
  85. package/utils/QueryHelper.d.ts +16 -1
  86. package/utils/QueryHelper.js +70 -24
  87. package/utils/RawQueryFragment.d.ts +4 -4
  88. package/utils/TransactionManager.js +1 -2
  89. package/utils/Utils.d.ts +1 -1
  90. package/utils/Utils.js +5 -4
  91. package/utils/clone.js +5 -0
  92. package/utils/fs-utils.d.ts +3 -17
  93. package/utils/fs-utils.js +1 -1
  94. 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
- 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;
@@ -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.config?.get('compiledFunctions'), fnKey);
97
- this.pkGetters.set(meta, pkSerializer);
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.pkGettersConverted.get(meta);
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.config?.get('compiledFunctions'), fnKey);
148
- this.pkGettersConverted.set(meta, pkSerializer);
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.pkSerializers.get(meta);
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.platform)));
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.tmpIndex++;
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.config?.get('compiledFunctions'), fnKey);
200
- this.pkSerializers.set(meta, pkSerializer);
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.metadata.find(entityName);
208
- const exists = this.snapshotGenerators.get(meta);
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.platform.cloneEmbeddable(o)); // do not clone prototypes
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.config?.get('compiledFunctions'), fnKey);
230
- this.snapshotGenerators.set(meta, snapshotGenerator);
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.mappers.get(meta);
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.platform.getTimezone();
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.platform.isNumericProperty(prop)) {
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.platform.parseDate(value));
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.tmpIndex++;
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.config?.get('compiledFunctions'), fnKey);
396
- this.mappers.set(meta, resultMapper);
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 (k.match(/^\[idx_\d+]$/)) {
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.tmpIndex++;
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 = `${level === 1 ? '' : '\n'}`;
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.platform, { mode: 'serialization' });
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.platform.processDateProperty.bind(this.platform));
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.metadata.find(entityName);
615
- const exists = this.comparators.get(meta);
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.config?.get('compiledFunctions'), fnKey);
641
- this.comparators.set(meta, comparator);
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.tmpIndex++;
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 (key.match(/^\[.*]$/)) {
711
+ if (/^\[.*]$/.exec(key)) {
712
712
  return key;
713
713
  }
714
- return key.match(/^\w+$/) ? `.${key}` : `['${key}']`;
714
+ return /^\w+$/.exec(key) ? `.${key}` : `['${key}']`;
715
715
  }
716
716
  safeKey(key) {
717
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).
@@ -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 && Utils.isPlainObject(value) && !isRaw(value) && Object.keys(value)[0] !== '$eq';
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
- if (Utils.isPlainObject(value) && !Object.keys(value).some(k => Utils.isOperator(k))) {
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<any> | undefined;
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<string> & symbol;
106
- var now: (length?: number) => RawQueryFragment<string> & symbol;
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<string> & symbol;
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
- // eslint-disable-next-line dot-notation
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?: undefined | null, visited?: Set<unknown>): void;
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.0-rc.3';
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 => arg.match(/\.([mc]?ts|tsx)$/)) || // executing `.ts` file
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 = objectType.match(/^\[object (.+)]$/)[1];
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.indexOf(v) === -1 ? acc.concat(v) : 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
  }
@@ -1,5 +1,5 @@
1
1
  import { type Dictionary } from '../typings.js';
2
- export declare const fs: {
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 path.match(/^[/.]|[a-zA-Z]:/) || path.startsWith('!') ? path : './' + path;
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,
@@ -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.indexOf('.') === -1) {
104
+ if (!key.includes('.')) {
105
105
  return obj[key];
106
106
  }
107
107
  const parts = key.split('.');