@mikro-orm/core 7.0.0-dev.114 → 7.0.0-dev.115

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 (54) hide show
  1. package/EntityManager.d.ts +8 -8
  2. package/EntityManager.js +40 -60
  3. package/MikroORM.d.ts +1 -1
  4. package/MikroORM.js +2 -3
  5. package/drivers/DatabaseDriver.d.ts +11 -11
  6. package/drivers/DatabaseDriver.js +7 -8
  7. package/drivers/IDatabaseDriver.d.ts +10 -10
  8. package/entity/Collection.js +5 -5
  9. package/entity/EntityAssigner.js +9 -9
  10. package/entity/EntityFactory.js +14 -17
  11. package/entity/EntityHelper.d.ts +2 -2
  12. package/entity/EntityHelper.js +2 -2
  13. package/entity/EntityLoader.d.ts +3 -3
  14. package/entity/EntityLoader.js +17 -16
  15. package/entity/WrappedEntity.js +1 -1
  16. package/entity/defineEntity.d.ts +11 -11
  17. package/errors.d.ts +8 -8
  18. package/errors.js +14 -13
  19. package/hydration/ObjectHydrator.js +23 -16
  20. package/metadata/EntitySchema.d.ts +5 -5
  21. package/metadata/EntitySchema.js +23 -21
  22. package/metadata/MetadataDiscovery.d.ts +2 -3
  23. package/metadata/MetadataDiscovery.js +117 -90
  24. package/metadata/MetadataProvider.js +2 -0
  25. package/metadata/MetadataStorage.d.ts +13 -6
  26. package/metadata/MetadataStorage.js +64 -19
  27. package/metadata/MetadataValidator.d.ts +2 -2
  28. package/metadata/MetadataValidator.js +22 -28
  29. package/metadata/types.d.ts +3 -3
  30. package/package.json +1 -1
  31. package/serialization/EntitySerializer.js +2 -2
  32. package/serialization/EntityTransformer.js +6 -6
  33. package/serialization/SerializationContext.d.ts +6 -6
  34. package/typings.d.ts +16 -14
  35. package/typings.js +15 -10
  36. package/unit-of-work/ChangeSet.d.ts +2 -3
  37. package/unit-of-work/ChangeSet.js +2 -3
  38. package/unit-of-work/ChangeSetComputer.js +3 -3
  39. package/unit-of-work/ChangeSetPersister.js +14 -14
  40. package/unit-of-work/CommitOrderCalculator.d.ts +12 -10
  41. package/unit-of-work/CommitOrderCalculator.js +13 -13
  42. package/unit-of-work/UnitOfWork.d.ts +3 -3
  43. package/unit-of-work/UnitOfWork.js +46 -45
  44. package/utils/AbstractSchemaGenerator.js +7 -7
  45. package/utils/Configuration.d.ts +0 -5
  46. package/utils/DataloaderUtils.js +13 -11
  47. package/utils/EntityComparator.d.ts +6 -6
  48. package/utils/EntityComparator.js +22 -24
  49. package/utils/QueryHelper.d.ts +5 -5
  50. package/utils/QueryHelper.js +7 -7
  51. package/utils/TransactionManager.js +1 -1
  52. package/utils/Utils.d.ts +1 -1
  53. package/utils/Utils.js +1 -2
  54. package/utils/env-vars.js +0 -1
@@ -8,6 +8,7 @@ import { MetadataError } from '../errors.js';
8
8
  import { t, Type } from '../types/index.js';
9
9
  import { colors } from '../logging/colors.js';
10
10
  import { raw, Raw } from '../utils/RawQueryFragment.js';
11
+ import { BaseEntity } from '../entity/BaseEntity.js';
11
12
  export class MetadataDiscovery {
12
13
  metadata;
13
14
  platform;
@@ -62,9 +63,6 @@ export class MetadataDiscovery {
62
63
  void this.config.get('discovery').afterDiscovered?.(storage, this.platform);
63
64
  return storage;
64
65
  }
65
- validateDiscovered(metadata) {
66
- return this.validator.validateDiscovered(metadata, this.config.get('discovery'));
67
- }
68
66
  mapDiscoveredEntities() {
69
67
  const discovered = new MetadataStorage();
70
68
  this.discovered
@@ -72,8 +70,11 @@ export class MetadataDiscovery {
72
70
  .sort((a, b) => b.root.name.localeCompare(a.root.name))
73
71
  .forEach(meta => {
74
72
  this.platform.validateMetadata(meta);
75
- discovered.set(meta.className, meta);
73
+ discovered.set(meta.class, meta);
76
74
  });
75
+ for (const meta of discovered) {
76
+ meta.root = discovered.get(meta.root.class);
77
+ }
77
78
  return discovered;
78
79
  }
79
80
  initAccessors(meta) {
@@ -118,34 +119,40 @@ export class MetadataDiscovery {
118
119
  filtered.sort((a, b) => !a.embeddable === !b.embeddable ? 0 : (a.embeddable ? 1 : -1));
119
120
  filtered.forEach(meta => this.initSingleTableInheritance(meta, filtered));
120
121
  filtered.forEach(meta => this.defineBaseEntityProperties(meta));
121
- filtered.forEach(meta => this.metadata.set(meta.className, EntitySchema.fromMetadata(meta).init().meta));
122
+ filtered.forEach(meta => {
123
+ const newMeta = EntitySchema.fromMetadata(meta).init().meta;
124
+ return this.metadata.set(newMeta.class, newMeta);
125
+ });
122
126
  filtered.forEach(meta => this.initAutoincrement(meta));
123
- filtered.forEach(meta => Object.values(meta.properties).forEach(prop => this.initEmbeddables(meta, prop)));
124
- filtered.forEach(meta => Object.values(meta.properties).forEach(prop => this.initFactoryField(meta, prop)));
125
- filtered.forEach(meta => Object.values(meta.properties).forEach(prop => this.initFieldName(prop)));
126
- filtered.forEach(meta => Object.values(meta.properties).forEach(prop => this.initVersionProperty(meta, prop)));
127
- filtered.forEach(meta => Object.values(meta.properties).forEach(prop => this.initCustomType(meta, prop)));
128
- filtered.forEach(meta => Object.values(meta.properties).forEach(prop => this.initGeneratedColumn(meta, prop)));
127
+ const forEachProp = (cb) => {
128
+ filtered.forEach(meta => Object.values(meta.properties).forEach(prop => cb(meta, prop)));
129
+ };
130
+ forEachProp((m, p) => this.initFactoryField(m, p));
131
+ forEachProp((_m, p) => this.initRelation(p));
132
+ forEachProp((m, p) => this.initEmbeddables(m, p));
133
+ forEachProp((_m, p) => this.initFieldName(p));
134
+ forEachProp((m, p) => this.initVersionProperty(m, p));
135
+ forEachProp((m, p) => this.initCustomType(m, p));
136
+ forEachProp((m, p) => this.initGeneratedColumn(m, p));
129
137
  filtered.forEach(meta => this.initAutoincrement(meta)); // once again after we init custom types
130
138
  filtered.forEach(meta => this.initCheckConstraints(meta));
131
- for (const meta of filtered) {
132
- for (const prop of Object.values(meta.properties)) {
133
- this.initDefaultValue(prop);
134
- this.inferTypeFromDefault(prop);
135
- this.initColumnType(prop);
136
- }
137
- }
138
- filtered.forEach(meta => Object.values(meta.properties).forEach(prop => this.initIndexes(meta, prop)));
139
+ forEachProp((_m, p) => {
140
+ this.initDefaultValue(p);
141
+ this.inferTypeFromDefault(p);
142
+ this.initRelation(p);
143
+ this.initColumnType(p);
144
+ });
145
+ forEachProp((m, p) => this.initIndexes(m, p));
139
146
  filtered.forEach(meta => this.autoWireBidirectionalProperties(meta));
140
- filtered.forEach(meta => this.findReferencingProperties(meta, filtered));
141
147
  for (const meta of filtered) {
142
148
  discovered.push(...this.processEntity(meta));
143
149
  }
144
150
  discovered.forEach(meta => meta.sync(true));
145
151
  this.metadataProvider.combineCache();
146
152
  return discovered.map(meta => {
147
- meta = this.metadata.get(meta.className);
153
+ meta = this.metadata.get(meta.class);
148
154
  meta.sync(true);
155
+ this.findReferencingProperties(meta, filtered);
149
156
  return meta;
150
157
  });
151
158
  }
@@ -175,17 +182,22 @@ export class MetadataDiscovery {
175
182
  .replace(/\((.*)\)/, '$1'); // unwrap union types
176
183
  const missing = [];
177
184
  this.discovered.forEach(meta => Object.values(meta.properties).forEach(prop => {
178
- if (prop.kind === ReferenceKind.MANY_TO_MANY && prop.pivotEntity && !this.discovered.find(m => m.className === Utils.className(prop.pivotEntity))) {
179
- const target = typeof prop.pivotEntity === 'function'
180
- ? prop.pivotEntity()
181
- : prop.pivotEntity;
182
- missing.push(target);
185
+ if (prop.kind === ReferenceKind.MANY_TO_MANY && prop.pivotEntity) {
186
+ const pivotEntity = prop.pivotEntity;
187
+ const target = typeof pivotEntity === 'function' && !pivotEntity.prototype
188
+ ? pivotEntity()
189
+ : pivotEntity;
190
+ if (!this.discovered.find(m => m.className === Utils.className(target))) {
191
+ missing.push(target);
192
+ }
183
193
  }
184
- if (prop.kind !== ReferenceKind.SCALAR && !unwrap(prop.type).split(/ ?\| ?/).every(type => this.discovered.find(m => m.className === type))) {
185
- const target = typeof prop.entity === 'function'
194
+ if (prop.kind !== ReferenceKind.SCALAR) {
195
+ const target = typeof prop.entity === 'function' && !prop.entity.prototype
186
196
  ? prop.entity()
187
197
  : prop.type;
188
- missing.push(...Utils.asArray(target));
198
+ if (!unwrap(prop.type).split(/ ?\| ?/).every(type => this.discovered.find(m => m.className === type))) {
199
+ missing.push(...Utils.asArray(target));
200
+ }
189
201
  }
190
202
  }));
191
203
  if (missing.length > 0) {
@@ -195,7 +207,7 @@ export class MetadataDiscovery {
195
207
  tryDiscoverTargets(targets) {
196
208
  for (const target of targets) {
197
209
  const isDiscoverable = typeof target === 'function' || target instanceof EntitySchema;
198
- if (isDiscoverable && target.name && !this.metadata.has(target.name)) {
210
+ if (isDiscoverable && target.name && !this.metadata.has(target)) {
199
211
  this.discoverReferences([target], false);
200
212
  this.discoverMissingTargets();
201
213
  }
@@ -209,16 +221,16 @@ export class MetadataDiscovery {
209
221
  }
210
222
  const schema = this.getSchema(entity);
211
223
  const meta = schema.init().meta;
212
- this.metadata.set(meta.className, meta);
224
+ this.metadata.set(meta.class, meta);
213
225
  found.push(schema);
214
226
  }
215
227
  // discover parents (base entities) automatically
216
228
  for (const meta of this.metadata) {
217
229
  let parent = meta.extends;
218
- if (parent instanceof EntitySchema && !this.metadata.has(parent.meta.className)) {
230
+ if (parent instanceof EntitySchema && !this.metadata.has(parent.init().meta.class)) {
219
231
  this.discoverReferences([parent], false);
220
232
  }
221
- if (typeof parent === 'function' && parent.name && !this.metadata.has(parent.name)) {
233
+ if (typeof parent === 'function' && parent.name && !this.metadata.has(parent)) {
222
234
  this.discoverReferences([parent], false);
223
235
  }
224
236
  /* v8 ignore next */
@@ -226,7 +238,7 @@ export class MetadataDiscovery {
226
238
  continue;
227
239
  }
228
240
  parent = Object.getPrototypeOf(meta.class);
229
- if (parent.name !== '' && !this.metadata.has(parent.name)) {
241
+ if (parent.name !== '' && !this.metadata.has(parent) && parent !== BaseEntity) {
230
242
  this.discoverReferences([parent], false);
231
243
  }
232
244
  }
@@ -235,14 +247,14 @@ export class MetadataDiscovery {
235
247
  }
236
248
  this.discoverMissingTargets();
237
249
  if (validate) {
238
- this.validateDiscovered(this.discovered);
250
+ this.validator.validateDiscovered(this.discovered, this.config.get('discovery'));
239
251
  }
240
252
  return this.discovered.filter(meta => found.find(m => m.name === meta.className));
241
253
  }
242
- reset(className) {
243
- const exists = this.discovered.findIndex(m => m.className === className);
254
+ reset(entityName) {
255
+ const exists = this.discovered.findIndex(m => m.class === entityName || m.className === Utils.className(entityName));
244
256
  if (exists !== -1) {
245
- this.metadata.reset(this.discovered[exists].className);
257
+ this.metadata.reset(this.discovered[exists].class);
246
258
  this.discovered.splice(exists, 1);
247
259
  }
248
260
  }
@@ -258,17 +270,17 @@ export class MetadataDiscovery {
258
270
  if (path) {
259
271
  const meta = Utils.copy(MetadataStorage.getMetadata(entity.name, path), false);
260
272
  meta.path = path;
261
- this.metadata.set(entity.name, meta);
273
+ this.metadata.set(entity, meta);
262
274
  }
263
- const exists = this.metadata.has(entity.name);
264
- const meta = this.metadata.get(entity.name, true);
275
+ const exists = this.metadata.has(entity);
276
+ const meta = this.metadata.get(entity, true);
265
277
  meta.abstract ??= !(exists && meta.name);
266
278
  const schema = EntitySchema.fromMetadata(meta);
267
279
  schema.setClass(entity);
268
280
  return schema;
269
281
  }
270
282
  getRootEntity(meta) {
271
- const base = meta.extends && this.metadata.find(Utils.className(meta.extends));
283
+ const base = meta.extends && this.metadata.find(meta.extends);
272
284
  if (!base || base === meta) { // make sure we do not fall into infinite loop
273
285
  return meta;
274
286
  }
@@ -368,7 +380,7 @@ export class MetadataDiscovery {
368
380
  }
369
381
  }
370
382
  initManyToOneFieldName(prop, name) {
371
- const meta2 = this.metadata.get(prop.type);
383
+ const meta2 = prop.targetMeta;
372
384
  const ret = [];
373
385
  for (const primaryKey of meta2.primaryKeys) {
374
386
  this.initFieldName(meta2.properties[primaryKey]);
@@ -379,11 +391,11 @@ export class MetadataDiscovery {
379
391
  return ret;
380
392
  }
381
393
  initManyToManyFieldName(prop, name) {
382
- const meta2 = this.metadata.get(prop.type);
394
+ const meta2 = prop.targetMeta;
383
395
  return meta2.primaryKeys.map(() => this.namingStrategy.propertyToColumnName(name));
384
396
  }
385
397
  initManyToManyFields(meta, prop) {
386
- const meta2 = this.metadata.get(prop.type);
398
+ const meta2 = prop.targetMeta;
387
399
  Utils.defaultValue(prop, 'fixedOrder', !!prop.fixedOrderColumn);
388
400
  const pivotMeta = this.metadata.find(prop.pivotEntity);
389
401
  const props = Object.values(pivotMeta?.properties ?? {});
@@ -410,7 +422,7 @@ export class MetadataDiscovery {
410
422
  const prop2 = meta2.properties[prop.mappedBy];
411
423
  this.initManyToManyFields(meta2, prop2);
412
424
  prop.pivotTable = prop2.pivotTable;
413
- prop.pivotEntity = prop2.pivotEntity ?? prop2.pivotTable;
425
+ prop.pivotEntity = prop2.pivotEntity;
414
426
  prop.fixedOrder = prop2.fixedOrder;
415
427
  prop.fixedOrderColumn = prop2.fixedOrderColumn;
416
428
  prop.joinColumns = prop2.inverseJoinColumns;
@@ -421,7 +433,7 @@ export class MetadataDiscovery {
421
433
  prop.inverseJoinColumns ??= this.initManyToOneFieldName(prop, meta2.root.className);
422
434
  }
423
435
  initManyToOneFields(prop) {
424
- const meta2 = this.metadata.get(prop.type);
436
+ const meta2 = prop.targetMeta;
425
437
  const fieldNames = Utils.flatten(meta2.primaryKeys.map(primaryKey => meta2.properties[primaryKey].fieldNames));
426
438
  Utils.defaultValue(prop, 'referencedTableName', meta2.tableName);
427
439
  if (!prop.joinColumns) {
@@ -432,7 +444,7 @@ export class MetadataDiscovery {
432
444
  }
433
445
  }
434
446
  initOneToManyFields(prop) {
435
- const meta2 = this.metadata.get(prop.type);
447
+ const meta2 = prop.targetMeta;
436
448
  if (!prop.joinColumns) {
437
449
  prop.joinColumns = [this.namingStrategy.joinColumnName(prop.name)];
438
450
  }
@@ -450,7 +462,7 @@ export class MetadataDiscovery {
450
462
  pks[0].deleteRule ??= 'cascade';
451
463
  }
452
464
  meta.forceConstructor ??= this.shouldForceConstructorUsage(meta);
453
- this.validator.validateEntityDefinition(this.metadata, meta.className, this.config.get('discovery'));
465
+ this.validator.validateEntityDefinition(this.metadata, meta.class, this.config.get('discovery'));
454
466
  for (const prop of Object.values(meta.properties)) {
455
467
  this.initNullability(prop);
456
468
  this.applyNamingStrategy(meta, prop);
@@ -470,7 +482,14 @@ export class MetadataDiscovery {
470
482
  if (this.platform.usesPivotTable()) {
471
483
  return Object.values(meta.properties)
472
484
  .filter(prop => prop.kind === ReferenceKind.MANY_TO_MANY && prop.owner && prop.pivotTable)
473
- .map(prop => this.definePivotTableEntity(meta, prop));
485
+ .map(prop => {
486
+ const pivotMeta = this.definePivotTableEntity(meta, prop);
487
+ prop.pivotEntity = pivotMeta.class;
488
+ if (prop.inversedBy) {
489
+ prop.targetMeta.properties[prop.inversedBy].pivotEntity = pivotMeta.class;
490
+ }
491
+ return pivotMeta;
492
+ });
474
493
  }
475
494
  return [];
476
495
  }
@@ -487,8 +506,11 @@ export class MetadataDiscovery {
487
506
  ['mappedBy', 'inversedBy', 'pivotEntity'].forEach(type => {
488
507
  const value = prop[type];
489
508
  if (value instanceof Function) {
490
- const meta2 = this.metadata.get(prop.type);
509
+ const meta2 = prop.targetMeta ?? this.metadata.get(prop.target);
491
510
  prop[type] = value(meta2.properties)?.name;
511
+ if (type === 'pivotEntity' && value) {
512
+ prop[type] = value(meta2.properties);
513
+ }
492
514
  if (prop[type] == null) {
493
515
  throw MetadataError.fromWrongReference(meta, prop, type);
494
516
  }
@@ -504,9 +526,9 @@ export class MetadataDiscovery {
504
526
  }
505
527
  else if (fks.length >= 2) {
506
528
  [first, second] = fks;
507
- /* v8 ignore next */
508
529
  }
509
530
  else {
531
+ /* v8 ignore next */
510
532
  return [];
511
533
  }
512
534
  // wrong FK order, first FK needs to point to the owning side
@@ -520,7 +542,9 @@ export class MetadataDiscovery {
520
542
  return [first, second];
521
543
  }
522
544
  definePivotTableEntity(meta, prop) {
523
- const pivotMeta = this.metadata.find(prop.pivotEntity);
545
+ const pivotMeta = prop.pivotEntity
546
+ ? this.metadata.find(prop.pivotEntity)
547
+ : this.metadata.getByClassName(prop.pivotTable, false);
524
548
  // ensure inverse side exists so we can join it when populating via pivot tables
525
549
  if (!prop.inversedBy && prop.targetMeta) {
526
550
  const inverseName = `${meta.className}_${prop.name}__inverse`;
@@ -529,6 +553,8 @@ export class MetadataDiscovery {
529
553
  name: inverseName,
530
554
  kind: ReferenceKind.MANY_TO_MANY,
531
555
  type: meta.className,
556
+ target: meta.class,
557
+ targetMeta: meta,
532
558
  mappedBy: prop.name,
533
559
  pivotEntity: prop.pivotEntity,
534
560
  pivotTable: prop.pivotTable,
@@ -537,55 +563,51 @@ export class MetadataDiscovery {
537
563
  };
538
564
  this.applyNamingStrategy(prop.targetMeta, inverseProp);
539
565
  this.initCustomType(prop.targetMeta, inverseProp);
540
- this.initRelation(inverseProp);
541
566
  prop.targetMeta.properties[inverseName] = inverseProp;
542
567
  }
543
568
  if (pivotMeta) {
569
+ prop.pivotEntity = pivotMeta.class;
544
570
  this.ensureCorrectFKOrderInPivotEntity(pivotMeta, prop);
545
571
  return pivotMeta;
546
572
  }
547
- const exists = this.metadata.find(prop.pivotTable);
548
- if (exists) {
549
- prop.pivotEntity = exists.className;
550
- return exists;
551
- }
552
573
  let tableName = prop.pivotTable;
553
574
  let schemaName;
554
575
  if (prop.pivotTable.includes('.')) {
555
576
  [schemaName, tableName] = prop.pivotTable.split('.');
556
577
  }
557
578
  schemaName ??= meta.schema;
558
- const targetType = prop.targetMeta.className;
559
- const data = new EntityMetadata({
579
+ const targetMeta = prop.targetMeta;
580
+ const targetType = targetMeta.className;
581
+ const pivotMeta2 = new EntityMetadata({
560
582
  name: prop.pivotTable,
561
583
  className: prop.pivotTable,
562
584
  collection: tableName,
563
585
  schema: schemaName,
564
586
  pivotTable: true,
565
587
  });
566
- prop.pivotEntity = data.className;
588
+ prop.pivotEntity = pivotMeta2.class;
567
589
  if (prop.fixedOrder) {
568
- const primaryProp = this.defineFixedOrderProperty(prop, targetType);
569
- data.properties[primaryProp.name] = primaryProp;
590
+ const primaryProp = this.defineFixedOrderProperty(prop, targetMeta);
591
+ pivotMeta2.properties[primaryProp.name] = primaryProp;
570
592
  }
571
593
  else {
572
- data.compositePK = true;
594
+ pivotMeta2.compositePK = true;
573
595
  }
574
596
  // handle self-referenced m:n with same default field names
575
597
  if (meta.className === targetType && prop.joinColumns.every((joinColumn, idx) => joinColumn === prop.inverseJoinColumns[idx])) {
576
598
  prop.joinColumns = prop.referencedColumnNames.map(name => this.namingStrategy.joinKeyColumnName(meta.tableName + '_1', name, meta.compositePK));
577
599
  prop.inverseJoinColumns = prop.referencedColumnNames.map(name => this.namingStrategy.joinKeyColumnName(meta.tableName + '_2', name, meta.compositePK));
578
600
  if (prop.inversedBy) {
579
- const prop2 = this.metadata.get(targetType).properties[prop.inversedBy];
601
+ const prop2 = targetMeta.properties[prop.inversedBy];
580
602
  prop2.inverseJoinColumns = prop.joinColumns;
581
603
  prop2.joinColumns = prop.inverseJoinColumns;
582
604
  }
583
605
  }
584
- data.properties[meta.name + '_owner'] = this.definePivotProperty(prop, meta.name + '_owner', meta.className, targetType + '_inverse', true, meta.className === targetType);
585
- data.properties[targetType + '_inverse'] = this.definePivotProperty(prop, targetType + '_inverse', targetType, meta.name + '_owner', false, meta.className === targetType);
586
- return this.metadata.set(data.className, EntitySchema.fromMetadata(data).init().meta);
606
+ pivotMeta2.properties[meta.name + '_owner'] = this.definePivotProperty(prop, meta.name + '_owner', meta.class, targetType + '_inverse', true, meta.className === targetType);
607
+ pivotMeta2.properties[targetType + '_inverse'] = this.definePivotProperty(prop, targetType + '_inverse', targetMeta.class, meta.name + '_owner', false, meta.className === targetType);
608
+ return this.metadata.set(pivotMeta2.class, EntitySchema.fromMetadata(pivotMeta2).init().meta);
587
609
  }
588
- defineFixedOrderProperty(prop, targetType) {
610
+ defineFixedOrderProperty(prop, targetMeta) {
589
611
  const pk = prop.fixedOrderColumn || this.namingStrategy.referenceColumnName();
590
612
  const primaryProp = {
591
613
  name: pk,
@@ -599,7 +621,7 @@ export class MetadataDiscovery {
599
621
  this.initColumnType(primaryProp);
600
622
  prop.fixedOrderColumn = pk;
601
623
  if (prop.inversedBy) {
602
- const prop2 = this.metadata.get(targetType).properties[prop.inversedBy];
624
+ const prop2 = targetMeta.properties[prop.inversedBy];
603
625
  prop2.fixedOrder = true;
604
626
  prop2.fixedOrderColumn = pk;
605
627
  }
@@ -608,7 +630,8 @@ export class MetadataDiscovery {
608
630
  definePivotProperty(prop, name, type, inverse, owner, selfReferencing) {
609
631
  const ret = {
610
632
  name,
611
- type,
633
+ type: Utils.className(type),
634
+ target: type,
612
635
  kind: ReferenceKind.MANY_TO_ONE,
613
636
  cascade: [Cascade.ALL],
614
637
  fixedOrder: prop.fixedOrder,
@@ -666,7 +689,7 @@ export class MetadataDiscovery {
666
689
  Object.values(meta.properties)
667
690
  .filter(prop => prop.kind !== ReferenceKind.SCALAR && !prop.owner && prop.mappedBy)
668
691
  .forEach(prop => {
669
- const meta2 = this.metadata.get(prop.type);
692
+ const meta2 = prop.targetMeta;
670
693
  const prop2 = meta2.properties[prop.mappedBy];
671
694
  if (prop2 && !prop2.inversedBy) {
672
695
  prop2.inversedBy = prop.name;
@@ -674,7 +697,7 @@ export class MetadataDiscovery {
674
697
  });
675
698
  }
676
699
  defineBaseEntityProperties(meta) {
677
- const base = meta.extends && this.metadata.get(Utils.className(meta.extends));
700
+ const base = meta.extends && this.metadata.get(meta.extends);
678
701
  if (!base || base === meta) { // make sure we do not fall into infinite loop
679
702
  return 0;
680
703
  }
@@ -867,7 +890,7 @@ export class MetadataDiscovery {
867
890
  }
868
891
  initSingleTableInheritance(meta, metadata) {
869
892
  if (meta.root !== meta && !meta.__processed) {
870
- meta.root = metadata.find(m => m.className === meta.root.className);
893
+ meta.root = metadata.find(m => m.class === meta.root.class);
871
894
  meta.root.__processed = true;
872
895
  }
873
896
  else {
@@ -876,17 +899,23 @@ export class MetadataDiscovery {
876
899
  if (!meta.root.discriminatorColumn) {
877
900
  return;
878
901
  }
879
- if (!meta.root.discriminatorMap) {
902
+ if (meta.root.discriminatorMap) {
903
+ const map = meta.root.discriminatorMap;
904
+ Object.keys(map)
905
+ .filter(key => typeof map[key] === 'string')
906
+ .forEach(key => map[key] = this.metadata.getByClassName(map[key]).class);
907
+ }
908
+ else {
880
909
  meta.root.discriminatorMap = {};
881
910
  const children = metadata
882
- .filter(m => m.root.className === meta.root.className && !m.abstract)
911
+ .filter(m => m.root.class === meta.root.class && !m.abstract)
883
912
  .sort((a, b) => a.className.localeCompare(b.className));
884
913
  for (const m of children) {
885
914
  const name = m.discriminatorValue ?? this.namingStrategy.classToTableName(m.className);
886
- meta.root.discriminatorMap[name] = m.className;
915
+ meta.root.discriminatorMap[name] = m.class;
887
916
  }
888
917
  }
889
- meta.discriminatorValue = Object.entries(meta.root.discriminatorMap).find(([, className]) => className === meta.className)?.[0];
918
+ meta.discriminatorValue = Object.entries(meta.root.discriminatorMap).find(([, cls]) => cls === meta.class)?.[0];
890
919
  if (!meta.root.properties[meta.root.discriminatorColumn]) {
891
920
  this.createDiscriminatorProperty(meta.root);
892
921
  }
@@ -995,9 +1024,6 @@ export class MetadataDiscovery {
995
1024
  return '1';
996
1025
  }
997
1026
  inferDefaultValue(meta, prop) {
998
- if (!meta.class) {
999
- return;
1000
- }
1001
1027
  try {
1002
1028
  // try to create two entity instances to detect the value is stable
1003
1029
  const now = Date.now();
@@ -1153,9 +1179,9 @@ export class MetadataDiscovery {
1153
1179
  if (Type.isMappedType(prop.customType) && prop.kind === ReferenceKind.SCALAR && !isArray) {
1154
1180
  prop.type = prop.customType.name;
1155
1181
  }
1156
- if (!prop.customType && [ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(prop.kind) && this.metadata.get(prop.type).compositePK) {
1182
+ if (!prop.customType && [ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(prop.kind) && prop.targetMeta.compositePK) {
1157
1183
  prop.customTypes = [];
1158
- for (const pk of this.metadata.get(prop.type).getPrimaryProps()) {
1184
+ for (const pk of prop.targetMeta.getPrimaryProps()) {
1159
1185
  if (pk.customType) {
1160
1186
  prop.customTypes.push(pk.customType);
1161
1187
  prop.hasConvertToJSValueSQL ||= !!pk.customType.convertToJSValueSQL && pk.customType.convertToJSValueSQL('', this.platform) !== '';
@@ -1185,7 +1211,8 @@ export class MetadataDiscovery {
1185
1211
  if (prop.kind === ReferenceKind.SCALAR) {
1186
1212
  return;
1187
1213
  }
1188
- const meta2 = this.discovered.find(m => m.className === prop.type);
1214
+ // when the target is a polymorphic embedded entity, `prop.target` is an array of classes, we need to get the metadata by the type name instead
1215
+ const meta2 = this.metadata.find(prop.target) ?? this.metadata.getByClassName(prop.type);
1189
1216
  prop.referencedPKs = meta2.primaryKeys;
1190
1217
  prop.targetMeta = meta2;
1191
1218
  if (!prop.formula && prop.persist === false && [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && !prop.embedded) {
@@ -1194,7 +1221,7 @@ export class MetadataDiscovery {
1194
1221
  }
1195
1222
  initColumnType(prop) {
1196
1223
  this.initUnsigned(prop);
1197
- this.metadata.find(prop.type)?.getPrimaryProps().map(pk => {
1224
+ prop.targetMeta?.getPrimaryProps().map(pk => {
1198
1225
  prop.length ??= pk.length;
1199
1226
  prop.precision ??= pk.precision;
1200
1227
  prop.scale ??= pk.scale;
@@ -1211,7 +1238,6 @@ export class MetadataDiscovery {
1211
1238
  const mappedType = this.getMappedType(prop);
1212
1239
  const SCALAR_TYPES = ['string', 'number', 'boolean', 'bigint', 'Date', 'Buffer', 'RegExp', 'any', 'unknown'];
1213
1240
  if (mappedType instanceof t.unknown
1214
- && !prop.columnTypes
1215
1241
  // it could be a runtime type from reflect-metadata
1216
1242
  && !SCALAR_TYPES.includes(prop.type)
1217
1243
  // or it might be inferred via ts-morph to some generic type alias
@@ -1224,11 +1250,12 @@ export class MetadataDiscovery {
1224
1250
  }
1225
1251
  return;
1226
1252
  }
1227
- if (prop.kind === ReferenceKind.EMBEDDED && prop.object && !prop.columnTypes) {
1253
+ /* v8 ignore next */
1254
+ if (prop.kind === ReferenceKind.EMBEDDED && prop.object) {
1228
1255
  prop.columnTypes = [this.platform.getJsonDeclarationSQL()];
1229
1256
  return;
1230
1257
  }
1231
- const targetMeta = this.metadata.get(prop.type);
1258
+ const targetMeta = prop.targetMeta;
1232
1259
  prop.columnTypes = [];
1233
1260
  for (const pk of targetMeta.getPrimaryProps()) {
1234
1261
  this.initCustomType(targetMeta, pk);
@@ -1278,7 +1305,7 @@ export class MetadataDiscovery {
1278
1305
  return;
1279
1306
  }
1280
1307
  if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind)) {
1281
- const meta2 = this.metadata.get(prop.type);
1308
+ const meta2 = prop.targetMeta;
1282
1309
  prop.unsigned = meta2.getPrimaryProps().some(pk => {
1283
1310
  this.initUnsigned(pk);
1284
1311
  return pk.unsigned;
@@ -1,4 +1,5 @@
1
1
  import { Utils } from '../utils/Utils.js';
2
+ import { EntitySchema } from './EntitySchema.js';
2
3
  export class MetadataProvider {
3
4
  config;
4
5
  constructor(config) {
@@ -13,6 +14,7 @@ export class MetadataProvider {
13
14
  else if (prop.entity) {
14
15
  const tmp = prop.entity();
15
16
  prop.type = Array.isArray(tmp) ? tmp.map(t => Utils.className(t)).sort().join(' | ') : Utils.className(tmp);
17
+ prop.target = tmp instanceof EntitySchema ? tmp.meta.class : tmp;
16
18
  }
17
19
  else if (!prop.type && !(prop.enum && (prop.items?.length ?? 0) > 0)) {
18
20
  throw new Error(`Please provide either 'type' or 'entity' attribute in ${meta.className}.${prop.name}.`);
@@ -1,20 +1,27 @@
1
- import { EntityMetadata, type Dictionary, type EntityName } from '../typings.js';
1
+ import { type Dictionary, EntityMetadata, type EntityName } from '../typings.js';
2
2
  import type { EntityManager } from '../EntityManager.js';
3
3
  export declare class MetadataStorage {
4
4
  static readonly PATH_SYMBOL: unique symbol;
5
5
  private static readonly metadata;
6
6
  private readonly metadata;
7
+ private readonly idMap;
8
+ private readonly classNameMap;
9
+ private readonly uniqueNameMap;
7
10
  constructor(metadata?: Dictionary<EntityMetadata>);
8
11
  static getMetadata(): Dictionary<EntityMetadata>;
9
12
  static getMetadata<T = any>(entity: string, path: string): EntityMetadata<T>;
10
13
  static isKnownEntity(name: string): boolean;
11
14
  static clear(): void;
12
- getAll(): Dictionary<EntityMetadata>;
13
- get<T = any>(entityName: EntityName<T>, init?: boolean, validate?: boolean): EntityMetadata<T>;
15
+ getAll(): Map<EntityName, EntityMetadata>;
16
+ get<T = any>(entityName: EntityName<T>, init?: boolean): EntityMetadata<T>;
14
17
  find<T = any>(entityName: EntityName<T>): EntityMetadata<T> | undefined;
15
- has(entity: string): boolean;
16
- set(entity: string, meta: EntityMetadata): EntityMetadata;
17
- reset(entity: string): void;
18
+ has<T>(entityName: EntityName<T>): boolean;
19
+ set<T>(entityName: EntityName<T>, meta: EntityMetadata): EntityMetadata;
20
+ reset<T>(entityName: EntityName<T>): void;
18
21
  decorate(em: EntityManager): void;
19
22
  [Symbol.iterator](): IterableIterator<EntityMetadata>;
23
+ getById<T>(id: number): EntityMetadata<T>;
24
+ getByClassName<T = any, V extends boolean = true>(className: string, validate?: V): V extends true ? EntityMetadata<T> : EntityMetadata<T> | undefined;
25
+ getByUniqueName<T = any, V extends boolean = true>(uniqueName: string, validate?: V): V extends true ? EntityMetadata<T> : EntityMetadata<T> | undefined;
26
+ private validate;
20
27
  }