@mikro-orm/core 7.0.0-rc.2 → 7.0.0-rc.3

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 (65) hide show
  1. package/EntityManager.d.ts +2 -1
  2. package/EntityManager.js +106 -42
  3. package/MikroORM.js +4 -4
  4. package/cache/FileCacheAdapter.js +1 -3
  5. package/connections/Connection.js +16 -3
  6. package/drivers/DatabaseDriver.js +26 -8
  7. package/drivers/IDatabaseDriver.d.ts +43 -0
  8. package/entity/Collection.js +43 -17
  9. package/entity/EntityAssigner.js +23 -11
  10. package/entity/EntityFactory.js +32 -12
  11. package/entity/EntityHelper.js +25 -16
  12. package/entity/EntityLoader.js +55 -22
  13. package/entity/Reference.d.ts +1 -1
  14. package/entity/Reference.js +37 -8
  15. package/entity/WrappedEntity.js +5 -1
  16. package/entity/defineEntity.d.ts +24 -12
  17. package/entity/utils.js +28 -26
  18. package/entity/validators.js +2 -1
  19. package/enums.js +12 -17
  20. package/errors.js +18 -8
  21. package/events/EventManager.js +1 -1
  22. package/exceptions.js +7 -2
  23. package/hydration/ObjectHydrator.js +27 -13
  24. package/index.d.ts +1 -1
  25. package/index.js +1 -1
  26. package/logging/DefaultLogger.js +3 -5
  27. package/logging/colors.js +3 -6
  28. package/metadata/EntitySchema.d.ts +2 -2
  29. package/metadata/EntitySchema.js +12 -2
  30. package/metadata/MetadataDiscovery.js +106 -47
  31. package/metadata/MetadataProvider.js +26 -1
  32. package/metadata/MetadataStorage.js +2 -4
  33. package/metadata/MetadataValidator.js +20 -5
  34. package/metadata/types.d.ts +2 -2
  35. package/naming-strategy/AbstractNamingStrategy.js +5 -2
  36. package/not-supported.js +5 -1
  37. package/package.json +38 -38
  38. package/platforms/Platform.d.ts +1 -0
  39. package/platforms/Platform.js +49 -23
  40. package/serialization/EntitySerializer.js +7 -3
  41. package/serialization/SerializationContext.js +1 -1
  42. package/typings.d.ts +23 -23
  43. package/typings.js +9 -9
  44. package/unit-of-work/ChangeSet.js +4 -4
  45. package/unit-of-work/ChangeSetComputer.js +8 -6
  46. package/unit-of-work/ChangeSetPersister.js +13 -8
  47. package/unit-of-work/CommitOrderCalculator.js +4 -2
  48. package/unit-of-work/UnitOfWork.d.ts +7 -1
  49. package/unit-of-work/UnitOfWork.js +51 -22
  50. package/utils/AbstractMigrator.d.ts +1 -1
  51. package/utils/AbstractMigrator.js +3 -5
  52. package/utils/AbstractSchemaGenerator.js +2 -1
  53. package/utils/AsyncContext.js +1 -1
  54. package/utils/Configuration.js +8 -4
  55. package/utils/Cursor.js +4 -2
  56. package/utils/DataloaderUtils.js +15 -12
  57. package/utils/EntityComparator.js +51 -43
  58. package/utils/QueryHelper.js +38 -26
  59. package/utils/RawQueryFragment.js +3 -2
  60. package/utils/TransactionManager.js +2 -1
  61. package/utils/Utils.d.ts +1 -1
  62. package/utils/Utils.js +36 -30
  63. package/utils/env-vars.js +6 -5
  64. package/utils/fs-utils.js +2 -5
  65. package/utils/upsert-utils.js +6 -3
@@ -33,7 +33,9 @@ export class MetadataDiscovery {
33
33
  async discover(preferTs = true) {
34
34
  this.discovered.length = 0;
35
35
  const startTime = Date.now();
36
- const suffix = this.metadataProvider.constructor === MetadataProvider ? '' : `, using ${colors.cyan(this.metadataProvider.constructor.name)}`;
36
+ const suffix = this.metadataProvider.constructor === MetadataProvider
37
+ ? ''
38
+ : `, using ${colors.cyan(this.metadataProvider.constructor.name)}`;
37
39
  this.logger.log('discovery', `ORM entity discovery started${suffix}`);
38
40
  await this.findEntities(preferTs);
39
41
  for (const meta of this.discovered) {
@@ -51,7 +53,9 @@ export class MetadataDiscovery {
51
53
  discoverSync() {
52
54
  this.discovered.length = 0;
53
55
  const startTime = Date.now();
54
- const suffix = this.metadataProvider.constructor === MetadataProvider ? '' : `, using ${colors.cyan(this.metadataProvider.constructor.name)}`;
56
+ const suffix = this.metadataProvider.constructor === MetadataProvider
57
+ ? ''
58
+ : `, using ${colors.cyan(this.metadataProvider.constructor.name)}`;
55
59
  this.logger.log('discovery', `ORM entity discovery started${suffix} in sync mode`);
56
60
  const refs = this.config.get('entities');
57
61
  this.discoverReferences(refs);
@@ -91,6 +95,7 @@ export class MetadataDiscovery {
91
95
  }
92
96
  const desc = Object.getOwnPropertyDescriptor(meta.prototype, prop.name);
93
97
  if (desc?.get || desc?.set) {
98
+ this.initRelation(prop);
94
99
  this.initFieldName(prop);
95
100
  const accessor = prop.name;
96
101
  prop.name = typeof prop.accessor === 'string' ? prop.accessor : prop.name;
@@ -106,7 +111,10 @@ export class MetadataDiscovery {
106
111
  }
107
112
  else {
108
113
  const name = prop.name;
109
- prop.name = prop.accessor;
114
+ if (prop.kind === ReferenceKind.SCALAR || prop.kind === ReferenceKind.EMBEDDED) {
115
+ prop.name = prop.accessor;
116
+ }
117
+ this.initRelation(prop);
110
118
  this.initFieldName(prop);
111
119
  prop.serializedName ??= prop.accessor;
112
120
  prop.name = name;
@@ -123,7 +131,7 @@ export class MetadataDiscovery {
123
131
  // ignore base entities (not annotated with @Entity)
124
132
  const filtered = discovered.filter(meta => meta.root.name);
125
133
  // sort so we discover entities first to get around issues with nested embeddables
126
- filtered.sort((a, b) => !a.embeddable === !b.embeddable ? 0 : (a.embeddable ? 1 : -1));
134
+ filtered.sort((a, b) => (!a.embeddable === !b.embeddable ? 0 : a.embeddable ? 1 : -1));
127
135
  filtered.forEach(meta => this.initSingleTableInheritance(meta, filtered));
128
136
  filtered.forEach(meta => this.initTPTRelationships(meta, filtered));
129
137
  filtered.forEach(meta => this.defineBaseEntityProperties(meta));
@@ -172,7 +180,7 @@ export class MetadataDiscovery {
172
180
  }
173
181
  async findEntities(preferTs) {
174
182
  const { entities, entitiesTs, baseDir } = this.config.getAll();
175
- const targets = (preferTs && entitiesTs.length > 0) ? entitiesTs : entities;
183
+ const targets = preferTs && entitiesTs.length > 0 ? entitiesTs : entities;
176
184
  const processed = [];
177
185
  const paths = [];
178
186
  for (const entity of targets) {
@@ -185,7 +193,7 @@ export class MetadataDiscovery {
185
193
  }
186
194
  if (paths.length > 0) {
187
195
  const { discoverEntities } = await import('@mikro-orm/core/file-discovery');
188
- processed.push(...await discoverEntities(paths, { baseDir }));
196
+ processed.push(...(await discoverEntities(paths, { baseDir })));
189
197
  }
190
198
  return this.discoverReferences(processed);
191
199
  }
@@ -206,10 +214,10 @@ export class MetadataDiscovery {
206
214
  }
207
215
  }
208
216
  if (prop.kind !== ReferenceKind.SCALAR) {
209
- const target = typeof prop.entity === 'function' && !prop.entity.prototype
210
- ? prop.entity()
211
- : prop.type;
212
- if (!unwrap(prop.type).split(/ ?\| ?/).every(type => this.discovered.find(m => m.className === type))) {
217
+ const target = typeof prop.entity === 'function' && !prop.entity.prototype ? prop.entity() : prop.type;
218
+ if (!unwrap(prop.type)
219
+ .split(/ ?\| ?/)
220
+ .every(type => this.discovered.find(m => m.className === type))) {
213
221
  missing.push(...Utils.asArray(target));
214
222
  }
215
223
  }
@@ -301,7 +309,8 @@ export class MetadataDiscovery {
301
309
  }
302
310
  getRootEntity(meta) {
303
311
  const base = meta.extends && this.metadata.find(meta.extends);
304
- if (!base || base === meta) { // make sure we do not fall into infinite loop
312
+ if (!base || base === meta) {
313
+ // make sure we do not fall into infinite loop
305
314
  return meta;
306
315
  }
307
316
  const root = this.getRootEntity(base);
@@ -361,7 +370,10 @@ export class MetadataDiscovery {
361
370
  initOwnColumns(meta) {
362
371
  meta.sync();
363
372
  for (const prop of meta.props) {
364
- if (!prop.joinColumns || !prop.columnTypes || prop.ownColumns || ![ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind)) {
373
+ if (!prop.joinColumns ||
374
+ !prop.columnTypes ||
375
+ prop.ownColumns ||
376
+ ![ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind)) {
365
377
  continue;
366
378
  }
367
379
  // For polymorphic relations, ownColumns should include all fieldNames
@@ -549,7 +561,8 @@ export class MetadataDiscovery {
549
561
  this.initRelation(prop);
550
562
  }
551
563
  this.initOwnColumns(meta);
552
- meta.simplePK = pks.length === 1 && pks[0].kind === ReferenceKind.SCALAR && !pks[0].customType && pks[0].runtimeType !== 'Date';
564
+ meta.simplePK =
565
+ pks.length === 1 && pks[0].kind === ReferenceKind.SCALAR && !pks[0].customType && pks[0].runtimeType !== 'Date';
553
566
  meta.serializedPrimaryKey ??= meta.props.find(prop => prop.serializedPrimaryKey)?.name;
554
567
  if (meta.serializedPrimaryKey && meta.serializedPrimaryKey !== meta.primaryKeys[0]) {
555
568
  meta.properties[meta.serializedPrimaryKey].persist ??= false;
@@ -681,7 +694,8 @@ export class MetadataDiscovery {
681
694
  pivotMeta2.compositePK = true;
682
695
  }
683
696
  // handle self-referenced m:n with same default field names
684
- if (meta.className === targetType && prop.joinColumns.every((joinColumn, idx) => joinColumn === prop.inverseJoinColumns[idx])) {
697
+ if (meta.className === targetType &&
698
+ prop.joinColumns.every((joinColumn, idx) => joinColumn === prop.inverseJoinColumns[idx])) {
685
699
  // use tableName only when explicitly provided by user, otherwise use className for backwards compatibility
686
700
  const baseName = this.isExplicitTableName(meta) ? meta.tableName : meta.className;
687
701
  prop.joinColumns = prop.referencedColumnNames.map(name => this.namingStrategy.joinKeyColumnName(baseName + '_1', name, meta.compositePK));
@@ -771,7 +785,9 @@ export class MetadataDiscovery {
771
785
  if (isCompositePK) {
772
786
  // Create separate properties for each PK column (nullable for other entity types)
773
787
  for (let i = 0; i < prop.joinColumns.length; i++) {
774
- pivotMeta.properties[prop.joinColumns[i]] = this.createPivotScalarProperty(prop.joinColumns[i], [columnTypes[i]]);
788
+ pivotMeta.properties[prop.joinColumns[i]] = this.createPivotScalarProperty(prop.joinColumns[i], [
789
+ columnTypes[i],
790
+ ]);
775
791
  }
776
792
  // Virtual property combining all columns (for compatibility)
777
793
  pivotMeta.properties[prop.discriminator] = this.createPivotScalarProperty(prop.discriminator, columnTypes, [...prop.joinColumns], { type: meta.className, persist: false });
@@ -911,7 +927,8 @@ export class MetadataDiscovery {
911
927
  }
912
928
  defineBaseEntityProperties(meta) {
913
929
  const base = meta.extends && this.metadata.get(meta.extends);
914
- if (!base || base === meta) { // make sure we do not fall into infinite loop
930
+ if (!base || base === meta) {
931
+ // make sure we do not fall into infinite loop
915
932
  return 0;
916
933
  }
917
934
  let order = this.defineBaseEntityProperties(base);
@@ -923,10 +940,12 @@ export class MetadataDiscovery {
923
940
  meta.properties[prop.name] = prop;
924
941
  }
925
942
  });
926
- ownProps.forEach(prop => meta.properties[prop.name] = prop);
943
+ ownProps.forEach(prop => (meta.properties[prop.name] = prop));
927
944
  meta.filters = { ...base.filters, ...meta.filters };
928
945
  if (!meta.discriminatorValue) {
929
- Object.values(base.properties).filter(prop => !old.includes(prop.name)).forEach(prop => {
946
+ Object.values(base.properties)
947
+ .filter(prop => !old.includes(prop.name))
948
+ .forEach(prop => {
930
949
  meta.properties[prop.name] = { ...prop };
931
950
  meta.propertyOrder.set(prop.name, (order += 0.01));
932
951
  });
@@ -934,7 +953,9 @@ export class MetadataDiscovery {
934
953
  meta.indexes = Utils.unique([...base.indexes, ...meta.indexes]);
935
954
  meta.uniques = Utils.unique([...base.uniques, ...meta.uniques]);
936
955
  meta.checks = Utils.unique([...base.checks, ...meta.checks]);
937
- const pks = Object.values(meta.properties).filter(p => p.primary).map(p => p.name);
956
+ const pks = Object.values(meta.properties)
957
+ .filter(p => p.primary)
958
+ .map(p => p.name);
938
959
  if (pks.length > 0 && meta.primaryKeys.length === 0) {
939
960
  meta.primaryKeys = pks;
940
961
  }
@@ -967,7 +988,7 @@ export class MetadataDiscovery {
967
988
  properties[prop.name].runtimeType = 'any';
968
989
  return properties[prop.name];
969
990
  }
970
- return properties[prop.name] = prop;
991
+ return (properties[prop.name] = prop);
971
992
  });
972
993
  };
973
994
  const processExtensions = (meta) => {
@@ -985,7 +1006,10 @@ export class MetadataDiscovery {
985
1006
  inlineProperties(meta);
986
1007
  processExtensions(meta);
987
1008
  });
988
- const name = polymorphs.map(t => t.className).sort().join(' | ');
1009
+ const name = polymorphs
1010
+ .map(t => t.className)
1011
+ .sort()
1012
+ .join(' | ');
989
1013
  embeddable = new EntityMetadata({
990
1014
  name,
991
1015
  className: name,
@@ -997,7 +1021,7 @@ export class MetadataDiscovery {
997
1021
  });
998
1022
  embeddable.sync();
999
1023
  discovered.push(embeddable);
1000
- polymorphs.forEach(meta => meta.root = embeddable);
1024
+ polymorphs.forEach(meta => (meta.root = embeddable));
1001
1025
  }
1002
1026
  }
1003
1027
  initPolymorphicRelation(meta, prop, discovered) {
@@ -1167,7 +1191,7 @@ export class MetadataDiscovery {
1167
1191
  const map = meta.root.discriminatorMap;
1168
1192
  Object.keys(map)
1169
1193
  .filter(key => typeof map[key] === 'string')
1170
- .forEach(key => map[key] = this.metadata.getByClassName(map[key]).class);
1194
+ .forEach(key => (map[key] = this.metadata.getByClassName(map[key]).class));
1171
1195
  }
1172
1196
  else {
1173
1197
  meta.root.discriminatorMap = {};
@@ -1191,7 +1215,9 @@ export class MetadataDiscovery {
1191
1215
  Object.values(meta.properties).forEach(prop => {
1192
1216
  const newProp = { ...prop };
1193
1217
  const rootProp = meta.root.properties[prop.name];
1194
- if (rootProp && (rootProp.type !== prop.type || (rootProp.fieldNames && prop.fieldNames && !compareArrays(rootProp.fieldNames, prop.fieldNames)))) {
1218
+ if (rootProp &&
1219
+ (rootProp.type !== prop.type ||
1220
+ (rootProp.fieldNames && prop.fieldNames && !compareArrays(rootProp.fieldNames, prop.fieldNames)))) {
1195
1221
  const name = newProp.name;
1196
1222
  this.initFieldName(newProp, newProp.object);
1197
1223
  newProp.renamedFrom = name;
@@ -1206,7 +1232,8 @@ export class MetadataDiscovery {
1206
1232
  // Find which discriminator owns the original fieldNames
1207
1233
  for (const [discValue, childClass] of Object.entries(meta.root.discriminatorMap)) {
1208
1234
  const childMeta = this.metadata.find(childClass);
1209
- if (childMeta?.properties[prop.name]?.fieldNames && compareArrays(childMeta.properties[prop.name].fieldNames, rootProp.fieldNames)) {
1235
+ if (childMeta?.properties[prop.name]?.fieldNames &&
1236
+ compareArrays(childMeta.properties[prop.name].fieldNames, rootProp.fieldNames)) {
1210
1237
  rootProp.stiFieldNameMap[discValue] = rootProp.fieldNames[0];
1211
1238
  break;
1212
1239
  }
@@ -1438,7 +1465,10 @@ export class MetadataDiscovery {
1438
1465
  }
1439
1466
  if (this.platform.usesEnumCheckConstraints() && !meta.embeddable) {
1440
1467
  for (const prop of meta.props) {
1441
- if (prop.enum && !prop.nativeEnumName && prop.items?.every(item => typeof item === 'string')) {
1468
+ if (prop.enum &&
1469
+ prop.persist !== false &&
1470
+ !prop.nativeEnumName &&
1471
+ prop.items?.every(item => typeof item === 'string')) {
1442
1472
  this.initFieldName(prop);
1443
1473
  meta.checks.push({
1444
1474
  name: this.namingStrategy.indexName(meta.tableName, prop.fieldNames, 'check'),
@@ -1491,7 +1521,11 @@ export class MetadataDiscovery {
1491
1521
  const entity1 = new meta.class();
1492
1522
  const entity2 = new meta.class();
1493
1523
  // we compare the two values by reference, this will discard things like `new Date()` or `Date.now()`
1494
- if (this.config.get('discovery').inferDefaultValues && prop.default === undefined && entity1[prop.name] != null && entity1[prop.name] === entity2[prop.name] && entity1[prop.name] !== now) {
1524
+ if (this.config.get('discovery').inferDefaultValues &&
1525
+ prop.default === undefined &&
1526
+ entity1[prop.name] != null &&
1527
+ entity1[prop.name] === entity2[prop.name] &&
1528
+ entity1[prop.name] !== now) {
1495
1529
  prop.default ??= entity1[prop.name];
1496
1530
  }
1497
1531
  // if the default value is null, infer nullability
@@ -1558,7 +1592,9 @@ export class MetadataDiscovery {
1558
1592
  prop.type = prop.customType.constructor.name;
1559
1593
  }
1560
1594
  // `prop.type` might also be custom type class (not instance), so `typeof MyType` will give us `function`, not `object`
1561
- if (typeof prop.type === 'function' && Type.isMappedType(prop.type.prototype) && !prop.customType) {
1595
+ if (typeof prop.type === 'function' &&
1596
+ Type.isMappedType(prop.type.prototype) &&
1597
+ !prop.customType) {
1562
1598
  // if the type is an ORM defined mapped type without `ensureComparable: true`,
1563
1599
  // we use just the type name, to have more performant hydration code
1564
1600
  const type = Utils.keys(t).find(type => {
@@ -1578,7 +1614,10 @@ export class MetadataDiscovery {
1578
1614
  if (!prop.customType && ['json', 'jsonb'].includes(prop.type?.toLowerCase())) {
1579
1615
  prop.customType = new t.json();
1580
1616
  }
1581
- if (prop.kind === ReferenceKind.SCALAR && !prop.customType && prop.columnTypes && ['json', 'jsonb'].includes(prop.columnTypes[0])) {
1617
+ if (prop.kind === ReferenceKind.SCALAR &&
1618
+ !prop.customType &&
1619
+ prop.columnTypes &&
1620
+ ['json', 'jsonb'].includes(prop.columnTypes[0])) {
1582
1621
  prop.customType = new t.json();
1583
1622
  }
1584
1623
  if (prop.kind === ReferenceKind.EMBEDDED && !prop.customType && (prop.object || prop.array)) {
@@ -1609,10 +1648,12 @@ export class MetadataDiscovery {
1609
1648
  if (prop.fieldNames?.length === 1 && !prop.customType) {
1610
1649
  [t.bigint, t.double, t.decimal, t.interval, t.date]
1611
1650
  .filter(type => mappedType instanceof type)
1612
- .forEach((type) => prop.customType = new type());
1651
+ .forEach((type) => (prop.customType = new type()));
1613
1652
  }
1614
1653
  if (prop.customType && !prop.columnTypes) {
1615
- const mappedType = this.getMappedType({ columnTypes: [prop.customType.getColumnType(prop, this.platform)] });
1654
+ const mappedType = this.getMappedType({
1655
+ columnTypes: [prop.customType.getColumnType(prop, this.platform)],
1656
+ });
1616
1657
  if (prop.customType.compareAsType() === 'any' && ![t.json].some(t => prop.customType instanceof t)) {
1617
1658
  prop.runtimeType ??= mappedType.runtimeType;
1618
1659
  }
@@ -1631,23 +1672,33 @@ export class MetadataDiscovery {
1631
1672
  prop.customType.meta = meta;
1632
1673
  prop.customType.prop = prop;
1633
1674
  prop.columnTypes ??= [prop.customType.getColumnType(prop, this.platform)];
1634
- prop.hasConvertToJSValueSQL = !!prop.customType.convertToJSValueSQL && prop.customType.convertToJSValueSQL('', this.platform) !== '';
1635
- prop.hasConvertToDatabaseValueSQL = !!prop.customType.convertToDatabaseValueSQL && prop.customType.convertToDatabaseValueSQL('', this.platform) !== '';
1636
- if (prop.customType instanceof t.bigint && ['string', 'bigint', 'number'].includes(prop.runtimeType.toLowerCase())) {
1675
+ prop.hasConvertToJSValueSQL =
1676
+ !!prop.customType.convertToJSValueSQL && prop.customType.convertToJSValueSQL('', this.platform) !== '';
1677
+ prop.hasConvertToDatabaseValueSQL =
1678
+ !!prop.customType.convertToDatabaseValueSQL &&
1679
+ prop.customType.convertToDatabaseValueSQL('', this.platform) !== '';
1680
+ if (prop.customType instanceof t.bigint &&
1681
+ ['string', 'bigint', 'number'].includes(prop.runtimeType.toLowerCase())) {
1637
1682
  prop.customType.mode = prop.runtimeType.toLowerCase();
1638
1683
  }
1639
1684
  }
1640
1685
  if (Type.isMappedType(prop.customType) && prop.kind === ReferenceKind.SCALAR && !isArray) {
1641
1686
  prop.type = prop.customType.name;
1642
1687
  }
1643
- if (!prop.customType && [ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(prop.kind) && !prop.polymorphic && prop.targetMeta.compositePK) {
1688
+ if (!prop.customType &&
1689
+ [ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(prop.kind) &&
1690
+ !prop.polymorphic &&
1691
+ prop.targetMeta.compositePK) {
1644
1692
  prop.customTypes = [];
1645
1693
  for (const pk of prop.targetMeta.getPrimaryProps()) {
1646
1694
  if (pk.customType) {
1647
1695
  prop.customTypes.push(pk.customType);
1648
- prop.hasConvertToJSValueSQL ||= !!pk.customType.convertToJSValueSQL && pk.customType.convertToJSValueSQL('', this.platform) !== '';
1696
+ prop.hasConvertToJSValueSQL ||=
1697
+ !!pk.customType.convertToJSValueSQL && pk.customType.convertToJSValueSQL('', this.platform) !== '';
1649
1698
  /* v8 ignore next */
1650
- prop.hasConvertToDatabaseValueSQL ||= !!pk.customType.convertToDatabaseValueSQL && pk.customType.convertToDatabaseValueSQL('', this.platform) !== '';
1699
+ prop.hasConvertToDatabaseValueSQL ||=
1700
+ !!pk.customType.convertToDatabaseValueSQL &&
1701
+ pk.customType.convertToDatabaseValueSQL('', this.platform) !== '';
1651
1702
  }
1652
1703
  else {
1653
1704
  prop.customTypes.push(undefined);
@@ -1655,7 +1706,11 @@ export class MetadataDiscovery {
1655
1706
  }
1656
1707
  }
1657
1708
  if (prop.kind === ReferenceKind.SCALAR && !(mappedType instanceof t.unknown)) {
1658
- if (!prop.columnTypes && prop.nativeEnumName && meta.schema !== this.platform.getDefaultSchemaName() && meta.schema && !prop.nativeEnumName.includes('.')) {
1709
+ if (!prop.columnTypes &&
1710
+ prop.nativeEnumName &&
1711
+ meta.schema !== this.platform.getDefaultSchemaName() &&
1712
+ meta.schema &&
1713
+ !prop.nativeEnumName.includes('.')) {
1659
1714
  prop.columnTypes = [`${meta.schema}.${prop.nativeEnumName}`];
1660
1715
  }
1661
1716
  else {
@@ -1682,7 +1737,10 @@ export class MetadataDiscovery {
1682
1737
  }
1683
1738
  // Auto-generate formula for persist: false relations, but only for single-column FKs
1684
1739
  // Composite FK relations need standard JOIN conditions, not formula-based
1685
- if (!prop.formula && prop.persist === false && [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && !prop.embedded) {
1740
+ if (!prop.formula &&
1741
+ prop.persist === false &&
1742
+ [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) &&
1743
+ !prop.embedded) {
1686
1744
  this.initFieldName(prop);
1687
1745
  if (prop.fieldNames?.length === 1) {
1688
1746
  prop.formula = table => `${table}.${this.platform.quoteIdentifier(prop.fieldNames[0])}`;
@@ -1693,7 +1751,9 @@ export class MetadataDiscovery {
1693
1751
  this.initUnsigned(prop);
1694
1752
  // Get the target properties for FK relations - use targetKey property if specified, otherwise PKs
1695
1753
  const targetProps = prop.targetMeta
1696
- ? (prop.targetKey ? [prop.targetMeta.properties[prop.targetKey]] : prop.targetMeta.getPrimaryProps())
1754
+ ? prop.targetKey
1755
+ ? [prop.targetMeta.properties[prop.targetKey]]
1756
+ : prop.targetMeta.getPrimaryProps()
1697
1757
  : [];
1698
1758
  targetProps.map(targetProp => {
1699
1759
  prop.length ??= targetProp.length;
@@ -1711,11 +1771,11 @@ export class MetadataDiscovery {
1711
1771
  if (prop.kind === ReferenceKind.SCALAR) {
1712
1772
  const mappedType = this.getMappedType(prop);
1713
1773
  const SCALAR_TYPES = ['string', 'number', 'boolean', 'bigint', 'Date', 'Buffer', 'RegExp', 'any', 'unknown'];
1714
- if (mappedType instanceof t.unknown
1774
+ if (mappedType instanceof t.unknown &&
1715
1775
  // it could be a runtime type from reflect-metadata
1716
- && !SCALAR_TYPES.includes(prop.type)
1776
+ !SCALAR_TYPES.includes(prop.type) &&
1717
1777
  // or it might be inferred via ts-morph to some generic type alias
1718
- && !prop.type.match(/[<>:"';{}]/)) {
1778
+ !prop.type.match(/[<>:"';{}]/)) {
1719
1779
  const type = prop.length != null && !prop.type.endsWith(`(${prop.length})`) ? `${prop.type}(${prop.length})` : prop.type;
1720
1780
  prop.columnTypes = [type];
1721
1781
  }
@@ -1732,9 +1792,7 @@ export class MetadataDiscovery {
1732
1792
  const targetMeta = prop.targetMeta;
1733
1793
  prop.columnTypes = [];
1734
1794
  // Use targetKey property if specified, otherwise use primary key properties
1735
- const referencedProps = prop.targetKey
1736
- ? [targetMeta.properties[prop.targetKey]]
1737
- : targetMeta.getPrimaryProps();
1795
+ const referencedProps = prop.targetKey ? [targetMeta.properties[prop.targetKey]] : targetMeta.getPrimaryProps();
1738
1796
  if (prop.polymorphic && prop.polymorphTargets) {
1739
1797
  prop.columnTypes.push(this.platform.getVarcharTypeDeclarationSQL(prop));
1740
1798
  }
@@ -1792,7 +1850,8 @@ export class MetadataDiscovery {
1792
1850
  });
1793
1851
  return;
1794
1852
  }
1795
- prop.unsigned ??= (prop.primary || prop.unsigned) && this.platform.isNumericProperty(prop) && this.platform.supportsUnsigned();
1853
+ prop.unsigned ??=
1854
+ (prop.primary || prop.unsigned) && this.platform.isNumericProperty(prop) && this.platform.supportsUnsigned();
1796
1855
  }
1797
1856
  initIndexes(meta, prop) {
1798
1857
  const hasIndex = meta.indexes.some(idx => idx.properties?.length === 1 && idx.properties[0] === prop.name);
@@ -13,7 +13,12 @@ export class MetadataProvider {
13
13
  }
14
14
  else if (prop.entity) {
15
15
  const tmp = prop.entity();
16
- prop.type = Array.isArray(tmp) ? tmp.map(t => Utils.className(t)).sort().join(' | ') : Utils.className(tmp);
16
+ prop.type = Array.isArray(tmp)
17
+ ? tmp
18
+ .map(t => Utils.className(t))
19
+ .sort()
20
+ .join(' | ')
21
+ : Utils.className(tmp);
17
22
  prop.target = tmp instanceof EntitySchema ? tmp.meta.class : tmp;
18
23
  }
19
24
  else if (!prop.type && !((prop.enum || prop.array) && (prop.items?.length ?? 0) > 0)) {
@@ -29,7 +34,27 @@ export class MetadataProvider {
29
34
  delete prop.items;
30
35
  }
31
36
  });
37
+ // Preserve function expressions from indexes/uniques — they can't survive JSON cache serialization
38
+ const expressionMap = new Map();
39
+ for (const arr of [meta.indexes, meta.uniques]) {
40
+ for (const idx of arr ?? []) {
41
+ if (typeof idx.expression === 'function' && idx.name) {
42
+ expressionMap.set(idx.name, idx.expression);
43
+ }
44
+ }
45
+ }
32
46
  Utils.mergeConfig(meta, cache);
47
+ // Restore function expressions that were lost during JSON serialization
48
+ if (expressionMap.size > 0) {
49
+ for (const arr of [meta.indexes, meta.uniques]) {
50
+ for (const idx of arr ?? []) {
51
+ const fn = idx.name && expressionMap.get(idx.name);
52
+ if (fn && typeof idx.expression !== 'function') {
53
+ idx.expression = fn;
54
+ }
55
+ }
56
+ }
57
+ }
33
58
  }
34
59
  static useCache() {
35
60
  return false;
@@ -9,7 +9,7 @@ function getGlobalStorage(namespace) {
9
9
  return globalThis[key];
10
10
  }
11
11
  export class MetadataStorage {
12
- static PATH_SYMBOL = Symbol('MetadataStorage.PATH_SYMBOL');
12
+ static PATH_SYMBOL = Symbol.for('@mikro-orm/core/MetadataStorage.PATH_SYMBOL');
13
13
  static metadata = getGlobalStorage('metadata');
14
14
  metadata = new Map();
15
15
  idMap;
@@ -90,9 +90,7 @@ export class MetadataStorage {
90
90
  }
91
91
  }
92
92
  decorate(em) {
93
- [...this.metadata.values()]
94
- .filter(meta => meta.prototype)
95
- .forEach(meta => EntityHelper.decorate(meta, em));
93
+ [...this.metadata.values()].filter(meta => meta.prototype).forEach(meta => EntityHelper.decorate(meta, em));
96
94
  }
97
95
  *[Symbol.iterator]() {
98
96
  for (const meta of this.metadata.values()) {
@@ -63,7 +63,11 @@ export class MetadataValidator {
63
63
  }
64
64
  // Validate no mixing of STI and TPT in the same hierarchy
65
65
  this.validateInheritanceStrategies(discovered);
66
- const tableNames = discovered.filter(meta => !meta.abstract && !meta.embeddable && meta === meta.root && (meta.tableName || meta.collection) && meta.schema !== '*');
66
+ const tableNames = discovered.filter(meta => !meta.abstract &&
67
+ !meta.embeddable &&
68
+ meta === meta.root &&
69
+ (meta.tableName || meta.collection) &&
70
+ meta.schema !== '*');
67
71
  const duplicateTableNames = Utils.findDuplicates(tableNames.map(meta => {
68
72
  const tableName = meta.tableName || meta.collection;
69
73
  return (meta.schema ? '.' + meta.schema : '') + tableName;
@@ -88,7 +92,10 @@ export class MetadataValidator {
88
92
  const pivotProps = new Map();
89
93
  // check for not discovered entities
90
94
  discovered.forEach(meta => Object.values(meta.properties).forEach(prop => {
91
- if (prop.kind !== ReferenceKind.SCALAR && !unwrap(prop.type).split(/ ?\| ?/).every(type => discovered.find(m => m.className === type))) {
95
+ if (prop.kind !== ReferenceKind.SCALAR &&
96
+ !unwrap(prop.type)
97
+ .split(/ ?\| ?/)
98
+ .every(type => discovered.find(m => m.className === type))) {
92
99
  throw MetadataError.fromUnknownEntity(prop.type, `${meta.className}.${prop.name}`);
93
100
  }
94
101
  if (prop.pivotEntity) {
@@ -122,7 +129,10 @@ export class MetadataValidator {
122
129
  if (targetMeta.abstract && !targetMeta.root?.inheritanceType && !targetMeta.embeddable) {
123
130
  throw MetadataError.targetIsAbstract(meta, prop);
124
131
  }
125
- if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && prop.persist === false && targetMeta.compositePK && options.checkNonPersistentCompositeProps) {
132
+ if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) &&
133
+ prop.persist === false &&
134
+ targetMeta.compositePK &&
135
+ options.checkNonPersistentCompositeProps) {
126
136
  throw MetadataError.nonPersistentCompositeProp(meta, prop);
127
137
  }
128
138
  this.validateTargetKey(meta, prop, targetMeta);
@@ -248,7 +258,9 @@ export class MetadataValidator {
248
258
  // has correct `mappedBy` reference type
249
259
  // For polymorphic relations, check if this entity is one of the polymorphic targets
250
260
  const isValidPolymorphicInverse = owner.polymorphic && owner.polymorphTargets?.some(target => target.class === meta.root.class);
251
- if (!isValidPolymorphicInverse && owner.type !== meta.className && owner.targetMeta?.root.class !== meta.root.class) {
261
+ if (!isValidPolymorphicInverse &&
262
+ owner.type !== meta.className &&
263
+ owner.targetMeta?.root.class !== meta.root.class) {
252
264
  throw MetadataError.fromWrongReference(meta, prop, 'mappedBy', owner);
253
265
  }
254
266
  // owning side is not defined as inverse
@@ -280,7 +292,10 @@ export class MetadataValidator {
280
292
  }
281
293
  validateDuplicateFieldNames(meta, options) {
282
294
  const candidates = Object.values(meta.properties)
283
- .filter(prop => prop.persist !== false && !prop.inherited && prop.fieldNames?.length === 1 && (prop.kind !== ReferenceKind.EMBEDDED || prop.object))
295
+ .filter(prop => prop.persist !== false &&
296
+ !prop.inherited &&
297
+ prop.fieldNames?.length === 1 &&
298
+ (prop.kind !== ReferenceKind.EMBEDDED || prop.object))
284
299
  .map(prop => prop.fieldNames[0]);
285
300
  const duplicates = Utils.findDuplicates(candidates);
286
301
  if (duplicates.length > 0 && options.checkDuplicateFieldNames) {
@@ -526,7 +526,7 @@ export interface IndexColumnOptions {
526
526
  }
527
527
  interface BaseOptions<T, H extends string> {
528
528
  name?: string;
529
- properties?: (T extends EntityClass<infer P> ? Properties<P, H> : Properties<T, H>);
529
+ properties?: T extends EntityClass<infer P> ? Properties<P, H> : Properties<T, H>;
530
530
  options?: Dictionary;
531
531
  expression?: string | (T extends EntityClass<infer P> ? IndexCallback<P> : IndexCallback<T>);
532
532
  /**
@@ -540,7 +540,7 @@ interface BaseOptions<T, H extends string> {
540
540
  * Columns to include in the index but not as part of the key (PostgreSQL, MSSQL).
541
541
  * These columns are stored in the leaf level of the index but not used for searching.
542
542
  */
543
- include?: (T extends EntityClass<infer P> ? Properties<P, H> : Properties<T, H>);
543
+ include?: T extends EntityClass<infer P> ? Properties<P, H> : Properties<T, H>;
544
544
  /** Fill factor for the index as a percentage 0-100 (PostgreSQL, MSSQL). */
545
545
  fillFactor?: number;
546
546
  }
@@ -35,10 +35,13 @@ export class AbstractNamingStrategy {
35
35
  */
36
36
  getEntityName(tableName, schemaName) {
37
37
  const name = tableName.match(/^[^$_\p{ID_Start}]/u) ? `E_${tableName}` : tableName;
38
- return this.getClassName(name.replaceAll(/[^\u200C\u200D\p{ID_Continue}]+/ug, r => r.split('').map(c => `$${c.codePointAt(0)}`).join('')), '_');
38
+ return this.getClassName(name.replaceAll(/[^\u200C\u200D\p{ID_Continue}]+/gu, r => r
39
+ .split('')
40
+ .map(c => `$${c.codePointAt(0)}`)
41
+ .join('')), '_');
39
42
  }
40
43
  columnNameToProperty(columnName) {
41
- const propName = columnName.replace(/[_\- ]+(\w)/ug, (_, p1) => p1.toUpperCase());
44
+ const propName = columnName.replace(/[_\- ]+(\w)/gu, (_, p1) => p1.toUpperCase());
42
45
  if (populatePathMembers.includes(propName.replace(/^\${2,}/u, '$$').replace(/^\$\*$/u, '*'))) {
43
46
  return `$${propName}`;
44
47
  }
package/not-supported.js CHANGED
@@ -1,4 +1,8 @@
1
1
  export function discoverEntities() {
2
2
  throw new Error('Folder-based discovery is not supported in this environment.');
3
3
  }
4
- export const fs = new Proxy({}, { get: () => { throw new Error('File system is not supported in this environment.'); } });
4
+ export const fs = new Proxy({}, {
5
+ get: () => {
6
+ throw new Error('File system is not supported in this environment.');
7
+ },
8
+ });