@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
@@ -2,6 +2,7 @@ import { EntityMetadata } from '../typings.js';
2
2
  import { Utils } from '../utils/Utils.js';
3
3
  import { MetadataError } from '../errors.js';
4
4
  import { EntityHelper } from '../entity/EntityHelper.js';
5
+ import { EntitySchema } from './EntitySchema.js';
5
6
  function getGlobalStorage(namespace) {
6
7
  const key = `mikro-orm-${namespace}`;
7
8
  globalThis[key] = globalThis[key] || {};
@@ -10,9 +11,19 @@ function getGlobalStorage(namespace) {
10
11
  export class MetadataStorage {
11
12
  static PATH_SYMBOL = Symbol('MetadataStorage.PATH_SYMBOL');
12
13
  static metadata = getGlobalStorage('metadata');
13
- metadata;
14
+ metadata = new Map();
15
+ idMap;
16
+ classNameMap;
17
+ uniqueNameMap;
14
18
  constructor(metadata = {}) {
15
- this.metadata = Utils.copy(metadata, false);
19
+ this.idMap = {};
20
+ this.uniqueNameMap = {};
21
+ this.classNameMap = Utils.copy(metadata, false);
22
+ for (const meta of Object.values(this.classNameMap)) {
23
+ this.idMap[meta._id] = meta;
24
+ this.uniqueNameMap[meta.uniqueName] = meta;
25
+ this.metadata.set(meta.class, meta);
26
+ }
16
27
  }
17
28
  static getMetadata(entity, path) {
18
29
  const key = entity && path ? entity + '-' + Utils.hash(path) : null;
@@ -33,40 +44,74 @@ export class MetadataStorage {
33
44
  getAll() {
34
45
  return this.metadata;
35
46
  }
36
- get(entityName, init = false, validate = true) {
37
- entityName = Utils.className(entityName);
38
- if (validate && !init && !this.has(entityName)) {
39
- throw MetadataError.missingMetadata(entityName);
47
+ get(entityName, init = false) {
48
+ const exists = this.find(entityName);
49
+ if (exists) {
50
+ return exists;
40
51
  }
41
- if (init && !this.has(entityName)) {
42
- this.metadata[entityName] = new EntityMetadata();
52
+ const className = Utils.className(entityName);
53
+ if (!init) {
54
+ throw MetadataError.missingMetadata(className);
43
55
  }
44
- return this.metadata[entityName];
56
+ const meta = new EntityMetadata({ class: entityName, name: className });
57
+ this.set(entityName, meta);
58
+ return meta;
45
59
  }
46
60
  find(entityName) {
47
61
  if (!entityName) {
48
62
  return;
49
63
  }
50
- entityName = Utils.className(entityName);
51
- return this.metadata[entityName];
64
+ const meta = this.metadata.get(entityName);
65
+ if (meta) {
66
+ return meta;
67
+ }
68
+ if (entityName instanceof EntitySchema) {
69
+ return this.metadata.get(entityName.meta.class) ?? entityName.meta;
70
+ }
71
+ return this.classNameMap[Utils.className(entityName)];
52
72
  }
53
- has(entity) {
54
- return entity in this.metadata;
73
+ has(entityName) {
74
+ return this.metadata.has(entityName);
55
75
  }
56
- set(entity, meta) {
57
- return this.metadata[entity] = meta;
76
+ set(entityName, meta) {
77
+ this.metadata.set(entityName, meta);
78
+ this.idMap[meta._id] = meta;
79
+ this.uniqueNameMap[meta.uniqueName] = meta;
80
+ this.classNameMap[Utils.className(entityName)] = meta;
81
+ return meta;
58
82
  }
59
- reset(entity) {
60
- delete this.metadata[entity];
83
+ reset(entityName) {
84
+ const meta = this.find(entityName);
85
+ if (meta) {
86
+ this.metadata.delete(meta.class);
87
+ delete this.idMap[meta._id];
88
+ delete this.uniqueNameMap[meta.uniqueName];
89
+ delete this.classNameMap[meta.className];
90
+ }
61
91
  }
62
92
  decorate(em) {
63
- Object.values(this.metadata)
93
+ [...this.metadata.values()]
64
94
  .filter(meta => meta.prototype)
65
95
  .forEach(meta => EntityHelper.decorate(meta, em));
66
96
  }
67
97
  *[Symbol.iterator]() {
68
- for (const meta of Object.values(this.metadata)) {
98
+ for (const meta of this.metadata.values()) {
69
99
  yield meta;
70
100
  }
71
101
  }
102
+ getById(id) {
103
+ return this.idMap[id];
104
+ }
105
+ getByClassName(className, validate = true) {
106
+ return this.validate(this.classNameMap[className], className, validate);
107
+ }
108
+ getByUniqueName(uniqueName, validate = true) {
109
+ return this.validate(this.uniqueNameMap[uniqueName], uniqueName, validate);
110
+ }
111
+ validate(meta, id, validate) {
112
+ if (!meta && validate) {
113
+ throw MetadataError.missingMetadata(id);
114
+ }
115
+ return meta;
116
+ }
72
117
  }
@@ -1,11 +1,11 @@
1
- import type { EntityMetadata } from '../typings.js';
1
+ import type { EntityMetadata, EntityName } from '../typings.js';
2
2
  import { type MetadataDiscoveryOptions } from '../utils/Configuration.js';
3
3
  import type { MetadataStorage } from './MetadataStorage.js';
4
4
  /**
5
5
  * @internal
6
6
  */
7
7
  export declare class MetadataValidator {
8
- validateEntityDefinition<T>(metadata: MetadataStorage, name: string, options: MetadataDiscoveryOptions): void;
8
+ validateEntityDefinition<T>(metadata: MetadataStorage, name: EntityName<T>, options: MetadataDiscoveryOptions): void;
9
9
  validateDiscovered(discovered: EntityMetadata[], options: MetadataDiscoveryOptions): void;
10
10
  private validateReference;
11
11
  private validateBidirectional;
@@ -28,11 +28,11 @@ export class MetadataValidator {
28
28
  this.validateIndexes(meta, meta.uniques ?? [], 'unique');
29
29
  for (const prop of Utils.values(meta.properties)) {
30
30
  if (prop.kind !== ReferenceKind.SCALAR) {
31
- this.validateReference(meta, prop, metadata, options);
32
- this.validateBidirectional(meta, prop, metadata);
31
+ this.validateReference(meta, prop, options);
32
+ this.validateBidirectional(meta, prop);
33
33
  }
34
- else if (metadata.has(prop.type)) {
35
- throw MetadataError.propertyTargetsEntityType(meta, prop, metadata.get(prop.type));
34
+ else if (metadata.getByClassName(prop.type, false)) {
35
+ throw MetadataError.propertyTargetsEntityType(meta, prop, metadata.getByClassName(prop.type));
36
36
  }
37
37
  }
38
38
  }
@@ -40,17 +40,13 @@ export class MetadataValidator {
40
40
  if (discovered.length === 0 && options.warnWhenNoEntities) {
41
41
  throw MetadataError.noEntityDiscovered();
42
42
  }
43
- const duplicates = Utils.findDuplicates(discovered.map(meta => meta.className));
44
- if (duplicates.length > 0 && options.checkDuplicateEntities) {
45
- throw MetadataError.duplicateEntityDiscovered(duplicates);
46
- }
47
43
  const tableNames = discovered.filter(meta => !meta.abstract && meta === meta.root && (meta.tableName || meta.collection) && meta.schema !== '*');
48
44
  const duplicateTableNames = Utils.findDuplicates(tableNames.map(meta => {
49
45
  const tableName = meta.tableName || meta.collection;
50
46
  return (meta.schema ? '.' + meta.schema : '') + tableName;
51
47
  }));
52
- if (duplicateTableNames.length > 0 && options.checkDuplicateTableNames && options.checkDuplicateEntities) {
53
- throw MetadataError.duplicateEntityDiscovered(duplicateTableNames, 'table names');
48
+ if (duplicateTableNames.length > 0 && options.checkDuplicateTableNames) {
49
+ throw MetadataError.duplicateEntityDiscovered(duplicateTableNames);
54
50
  }
55
51
  // validate we found at least one entity (not just abstract/base entities)
56
52
  if (discovered.filter(meta => meta.name).length === 0 && options.warnWhenNoEntities) {
@@ -61,7 +57,7 @@ export class MetadataValidator {
61
57
  .replace(/\[]$/, '') // remove array suffix
62
58
  .replace(/\((.*)\)/, '$1'); // unwrap union types
63
59
  const name = (p) => {
64
- if (typeof p === 'function') {
60
+ if (typeof p === 'function' && !p.prototype) {
65
61
  return Utils.className(p());
66
62
  }
67
63
  return Utils.className(p);
@@ -85,12 +81,12 @@ export class MetadataValidator {
85
81
  }
86
82
  });
87
83
  }
88
- validateReference(meta, prop, metadata, options) {
84
+ validateReference(meta, prop, options) {
89
85
  // references do have types
90
86
  if (!prop.type) {
91
87
  throw MetadataError.fromWrongTypeDefinition(meta, prop);
92
88
  }
93
- const targetMeta = metadata.find(prop.type);
89
+ const targetMeta = prop.targetMeta;
94
90
  // references do have type of known entity
95
91
  if (!targetMeta) {
96
92
  throw MetadataError.fromWrongTypeDefinition(meta, prop);
@@ -102,30 +98,27 @@ export class MetadataValidator {
102
98
  throw MetadataError.nonPersistentCompositeProp(meta, prop);
103
99
  }
104
100
  }
105
- validateBidirectional(meta, prop, metadata) {
101
+ validateBidirectional(meta, prop) {
106
102
  if (prop.inversedBy) {
107
- const inverse = metadata.get(prop.type).properties[prop.inversedBy];
108
- this.validateOwningSide(meta, prop, inverse, metadata);
103
+ this.validateOwningSide(meta, prop);
109
104
  }
110
105
  else if (prop.mappedBy) {
111
- const inverse = metadata.get(prop.type).properties[prop.mappedBy];
112
- this.validateInverseSide(meta, prop, inverse, metadata);
106
+ this.validateInverseSide(meta, prop);
113
107
  }
114
- else {
108
+ else if (prop.kind === ReferenceKind.ONE_TO_MANY && !prop.mappedBy) {
115
109
  // 1:m property has `mappedBy`
116
- if (prop.kind === ReferenceKind.ONE_TO_MANY && !prop.mappedBy) {
117
- throw MetadataError.fromMissingOption(meta, prop, 'mappedBy');
118
- }
110
+ throw MetadataError.fromMissingOption(meta, prop, 'mappedBy');
119
111
  }
120
112
  }
121
- validateOwningSide(meta, prop, inverse, metadata) {
113
+ validateOwningSide(meta, prop) {
114
+ const inverse = prop.targetMeta.properties[prop.inversedBy];
122
115
  // has correct `inversedBy` on owning side
123
116
  if (!inverse) {
124
117
  throw MetadataError.fromWrongReference(meta, prop, 'inversedBy');
125
118
  }
126
- const targetClassName = metadata.find(inverse.type)?.root.className;
119
+ const targetClass = inverse.targetMeta?.root.class;
127
120
  // has correct `inversedBy` reference type
128
- if (inverse.type !== meta.className && targetClassName !== meta.root.className) {
121
+ if (inverse.type !== meta.className && targetClass !== meta.root.class) {
129
122
  throw MetadataError.fromWrongReference(meta, prop, 'inversedBy', inverse);
130
123
  }
131
124
  // inverse side is not defined as owner
@@ -133,13 +126,14 @@ export class MetadataValidator {
133
126
  throw MetadataError.fromWrongOwnership(meta, prop, 'inversedBy');
134
127
  }
135
128
  }
136
- validateInverseSide(meta, prop, owner, metadata) {
129
+ validateInverseSide(meta, prop) {
130
+ const owner = prop.targetMeta.properties[prop.mappedBy];
137
131
  // has correct `mappedBy` on inverse side
138
132
  if (prop.mappedBy && !owner) {
139
133
  throw MetadataError.fromWrongReference(meta, prop, 'mappedBy');
140
134
  }
141
135
  // has correct `mappedBy` reference type
142
- if (owner.type !== meta.className && metadata.find(owner.type)?.root.className !== meta.root.className) {
136
+ if (owner.type !== meta.className && owner.targetMeta?.root.class !== meta.root.class) {
143
137
  throw MetadataError.fromWrongReference(meta, prop, 'mappedBy', owner);
144
138
  }
145
139
  // owning side is not defined as inverse
@@ -182,7 +176,7 @@ export class MetadataValidator {
182
176
  return [prop.embedded ? prop.embedded.join('.') : prop.name, prop.fieldNames[0]];
183
177
  });
184
178
  });
185
- throw MetadataError.duplicateFieldName(meta.className, pairs);
179
+ throw MetadataError.duplicateFieldName(meta.class, pairs);
186
180
  }
187
181
  }
188
182
  validateVersionField(meta) {
@@ -308,7 +308,7 @@ export interface PropertyOptions<Owner> {
308
308
  }
309
309
  export interface ReferenceOptions<Owner, Target> extends PropertyOptions<Owner> {
310
310
  /** Set target entity type. */
311
- entity?: string | (() => EntityName<Target>);
311
+ entity?: () => EntityName<Target>;
312
312
  /** Set what actions on owning entity should be cascaded to the relationship. Defaults to [Cascade.PERSIST, Cascade.MERGE] (see {@doclink cascading}). */
313
313
  cascade?: Cascade[];
314
314
  /** Always load the relationship. Discouraged for use with to-many relations for performance reasons. */
@@ -417,7 +417,7 @@ export interface ManyToManyOptions<Owner, Target> extends ReferenceOptions<Owner
417
417
  /** Override default name for pivot table (see {@doclink naming-strategy | Naming Strategy}). */
418
418
  pivotTable?: string;
419
419
  /** Set pivot entity for this relation (see {@doclink collections#custom-pivot-table-entity | Custom pivot table entity}). */
420
- pivotEntity?: string | (() => EntityName<any>);
420
+ pivotEntity?: () => EntityName;
421
421
  /** Override the default database column name on the owning side (see {@doclink naming-strategy | Naming Strategy}). This option is only for simple properties represented by a single column. */
422
422
  joinColumn?: string;
423
423
  /** Override the default database column name on the owning side (see {@doclink naming-strategy | Naming Strategy}). This option is suitable for composite keys, where one property is represented by multiple columns. */
@@ -438,7 +438,7 @@ export interface ManyToManyOptions<Owner, Target> extends ReferenceOptions<Owner
438
438
  createForeignKeyConstraint?: boolean;
439
439
  }
440
440
  export interface EmbeddedOptions<Owner, Target> extends PropertyOptions<Owner> {
441
- entity?: string | (() => EntityName<Target> | EntityName<Target>[]);
441
+ entity?: () => EntityName<Target> | EntityName<Target>[];
442
442
  prefix?: string | boolean;
443
443
  prefixMode?: EmbeddedPrefixMode;
444
444
  object?: boolean;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mikro-orm/core",
3
3
  "type": "module",
4
- "version": "7.0.0-dev.114",
4
+ "version": "7.0.0-dev.115",
5
5
  "description": "TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, PostgreSQL and SQLite databases as well as usage with vanilla JavaScript.",
6
6
  "exports": {
7
7
  "./package.json": "./package.json",
@@ -69,13 +69,13 @@ export class EntitySerializer {
69
69
  if (!isVisible(meta, prop, options)) {
70
70
  continue;
71
71
  }
72
- const cycle = root.visit(meta.className, prop);
72
+ const cycle = root.visit(meta.class, prop);
73
73
  if (cycle && visited) {
74
74
  continue;
75
75
  }
76
76
  const val = this.processProperty(prop, entity, options);
77
77
  if (!cycle) {
78
- root.leave(meta.className, prop);
78
+ root.leave(meta.class, prop);
79
79
  }
80
80
  if (options.skipNull && Utils.isPlainObject(val)) {
81
81
  Utils.dropUndefinedProperties(val, null);
@@ -57,19 +57,19 @@ export class EntityTransformer {
57
57
  if (!visible) {
58
58
  continue;
59
59
  }
60
- const populated = root.isMarkedAsPopulated(meta.className, prop);
61
- const partiallyLoaded = root.isPartiallyLoaded(meta.className, prop);
60
+ const populated = root.isMarkedAsPopulated(meta.class, prop);
61
+ const partiallyLoaded = root.isPartiallyLoaded(meta.class, prop);
62
62
  const isPrimary = includePrimaryKeys && meta.properties[prop].primary;
63
63
  if (!partiallyLoaded && !populated && !isPrimary) {
64
64
  continue;
65
65
  }
66
- const cycle = root.visit(meta.className, prop);
66
+ const cycle = root.visit(meta.class, prop);
67
67
  if (cycle && visited) {
68
68
  continue;
69
69
  }
70
70
  const val = EntityTransformer.processProperty(prop, entity, raw, populated);
71
71
  if (!cycle) {
72
- root.leave(meta.className, prop);
72
+ root.leave(meta.class, prop);
73
73
  }
74
74
  if (isRaw(val)) {
75
75
  throw new Error(`Trying to serialize raw SQL fragment: '${val.sql}'`);
@@ -86,7 +86,7 @@ export class EntityTransformer {
86
86
  // decorated get methods
87
87
  if (prop.getterName != null) {
88
88
  const visible = !prop.hidden && entity[prop.getterName] instanceof Function;
89
- const populated = root.isMarkedAsPopulated(meta.className, prop.name);
89
+ const populated = root.isMarkedAsPopulated(meta.class, prop.name);
90
90
  if (visible) {
91
91
  ret[this.propertyName(meta, prop.name, raw)] = this.processProperty(prop.getterName, entity, raw, populated);
92
92
  }
@@ -94,7 +94,7 @@ export class EntityTransformer {
94
94
  else {
95
95
  // decorated getters
96
96
  const visible = !prop.hidden && typeof entity[prop.name] !== 'undefined';
97
- const populated = root.isMarkedAsPopulated(meta.className, prop.name);
97
+ const populated = root.isMarkedAsPopulated(meta.class, prop.name);
98
98
  if (visible) {
99
99
  ret[this.propertyName(meta, prop.name, raw)] = this.processProperty(prop.name, entity, raw, populated);
100
100
  }
@@ -1,4 +1,4 @@
1
- import type { AnyEntity, EntityMetadata, PopulateOptions } from '../typings.js';
1
+ import type { AnyEntity, EntityMetadata, EntityName, PopulateOptions } from '../typings.js';
2
2
  import type { Configuration } from '../utils/Configuration.js';
3
3
  /**
4
4
  * Helper that allows to keep track of where we are currently at when serializing complex entity graph with cycles.
@@ -10,21 +10,21 @@ export declare class SerializationContext<T extends object> {
10
10
  private readonly populate;
11
11
  private readonly fields?;
12
12
  private readonly exclude?;
13
- readonly path: [string, string][];
13
+ readonly path: [EntityName, string][];
14
14
  readonly visited: Set<Partial<any>>;
15
15
  private entities;
16
16
  constructor(config: Configuration, populate?: PopulateOptions<T>[], fields?: Set<string> | undefined, exclude?: string[] | undefined);
17
17
  /**
18
18
  * Returns true when there is a cycle detected.
19
19
  */
20
- visit(entityName: string, prop: string): boolean;
21
- leave<U>(entityName: string, prop: string): void;
20
+ visit(entityName: EntityName, prop: string): boolean;
21
+ leave(entityName: EntityName, prop: string): void;
22
22
  close(): void;
23
23
  /**
24
24
  * When initializing new context, we need to propagate it to the whole entity graph recursively.
25
25
  */
26
26
  static propagate(root: SerializationContext<any>, entity: AnyEntity, isVisible: (meta: EntityMetadata, prop: string) => boolean): void;
27
- isMarkedAsPopulated(entityName: string, prop: string): boolean;
28
- isPartiallyLoaded(entityName: string, prop: string): boolean;
27
+ isMarkedAsPopulated(entityName: EntityName, prop: string): boolean;
28
+ isPartiallyLoaded(entityName: EntityName, prop: string): boolean;
29
29
  private register;
30
30
  }
package/typings.d.ts CHANGED
@@ -206,10 +206,10 @@ export interface IWrappedEntityInternal<Entity extends object> extends IWrappedE
206
206
  };
207
207
  }
208
208
  export type AnyEntity<T = any> = Partial<T>;
209
- export type EntityClass<T> = Function & {
209
+ export type EntityClass<T = any> = Function & {
210
210
  prototype: T;
211
211
  };
212
- export type EntityName<T> = string | EntityClass<T> | EntitySchema<T, any> | {
212
+ export type EntityName<T = any> = EntityClass<T> | EntitySchema<T, any> | {
213
213
  name: string;
214
214
  };
215
215
  export type GetRepository<Entity extends {
@@ -326,6 +326,7 @@ export type AnyString = string & {};
326
326
  export interface EntityProperty<Owner = any, Target = any> {
327
327
  name: EntityKey<Owner>;
328
328
  entity: () => EntityName<Owner>;
329
+ target: EntityClass<Target>;
329
330
  type: keyof typeof types | AnyString;
330
331
  runtimeType: 'number' | 'string' | 'boolean' | 'bigint' | 'Buffer' | 'Date' | 'object' | 'any' | AnyString;
331
332
  targetMeta?: EntityMetadata<Target>;
@@ -396,7 +397,7 @@ export interface EntityProperty<Owner = any, Target = any> {
396
397
  fixedOrder?: boolean;
397
398
  fixedOrderColumn?: string;
398
399
  pivotTable: string;
399
- pivotEntity: string;
400
+ pivotEntity: EntityClass<Target>;
400
401
  joinColumns: string[];
401
402
  ownColumns: string[];
402
403
  inverseJoinColumns: string[];
@@ -420,13 +421,14 @@ export declare class EntityMetadata<T = any> {
420
421
  readonly _id: number;
421
422
  readonly propertyOrder: Map<string, number>;
422
423
  constructor(meta?: Partial<EntityMetadata>);
423
- addProperty(prop: Partial<EntityProperty<T>>, sync?: boolean): void;
424
+ addProperty(prop: Partial<EntityProperty<T>>): void;
424
425
  removeProperty(name: string, sync?: boolean): void;
425
426
  getPrimaryProps(flatten?: boolean): EntityProperty<T>[];
426
427
  getPrimaryProp(): EntityProperty<T>;
427
428
  createColumnMappingObject(): Dictionary<any>;
428
429
  get tableName(): string;
429
430
  set tableName(name: string);
431
+ get uniqueName(): string;
430
432
  sync(initIndexes?: boolean, config?: Configuration): void;
431
433
  private initIndexes;
432
434
  /** @internal */
@@ -446,11 +448,11 @@ export interface EntityMetadata<T = any> {
446
448
  expression?: string | ((em: any, where: ObjectQuery<T>, options: FindOptions<T, any, any, any>, stream?: boolean) => MaybePromise<Raw | object | string>);
447
449
  discriminatorColumn?: EntityKey<T> | AnyString;
448
450
  discriminatorValue?: number | string;
449
- discriminatorMap?: Dictionary<string>;
451
+ discriminatorMap?: Dictionary<EntityClass>;
450
452
  embeddable: boolean;
451
453
  constructorParams?: (keyof T)[];
452
454
  forceConstructor: boolean;
453
- extends: string;
455
+ extends?: EntityName<T>;
454
456
  collection: string;
455
457
  path: string;
456
458
  primaryKeys: EntityKey<T>[];
@@ -714,13 +716,13 @@ export interface MigrationObject {
714
716
  type EntityFromInput<T> = T extends readonly EntityName<infer U>[] ? U : T extends EntityName<infer U> ? U : never;
715
717
  type FilterDefResolved<T extends object = any> = {
716
718
  name: string;
717
- cond: FilterQuery<T> | ((args: Dictionary, type: 'read' | 'update' | 'delete', em: any, options?: FindOptions<T, any, any, any> | FindOneOptions<T, any, any, any>, entityName?: EntityName<T>) => MaybePromise<FilterQuery<T>>);
719
+ cond: FilterQuery<T> | ((args: Dictionary, type: 'read' | 'update' | 'delete', em: any, options?: FindOptions<T, any, any, any> | FindOneOptions<T, any, any, any>, entityName?: string) => MaybePromise<FilterQuery<T>>);
718
720
  default?: boolean;
719
721
  entity?: EntityName<T> | EntityName<T>[];
720
722
  args?: boolean;
721
723
  strict?: boolean;
722
724
  };
723
- export type FilterDef<T extends EntityName<any> | readonly EntityName<any>[] = any> = FilterDefResolved<EntityFromInput<T>> & {
725
+ export type FilterDef<T extends EntityName | readonly EntityName[] = any> = FilterDefResolved<EntityFromInput<T>> & {
724
726
  entity?: T;
725
727
  };
726
728
  export type Populate<T, P extends string = never> = readonly AutoPath<T, P, `${PopulatePath}`>[] | false;
@@ -813,12 +815,12 @@ export interface Highlighter {
813
815
  highlight(text: string): string;
814
816
  }
815
817
  export interface IMetadataStorage {
816
- getAll(): Dictionary<EntityMetadata>;
817
- get<T = any>(entity: string, init?: boolean, validate?: boolean): EntityMetadata<T>;
818
- find<T = any>(entity: string): EntityMetadata<T> | undefined;
819
- has(entity: string): boolean;
820
- set(entity: string, meta: EntityMetadata): EntityMetadata;
821
- reset(entity: string): void;
818
+ getAll(): Map<EntityName, EntityMetadata>;
819
+ get<T = any>(entity: EntityName<T>, init?: boolean, validate?: boolean): EntityMetadata<T>;
820
+ find<T = any>(entity: EntityName<T>): EntityMetadata<T> | undefined;
821
+ has<T>(entity: EntityName<T>): boolean;
822
+ set<T>(entity: EntityName<T>, meta: EntityMetadata): EntityMetadata;
823
+ reset<T>(entity: EntityName<T>): void;
822
824
  }
823
825
  export interface IHydrator {
824
826
  /**
package/typings.js CHANGED
@@ -25,22 +25,20 @@ export class EntityMetadata {
25
25
  this.referencingProperties = [];
26
26
  this.concurrencyCheckKeys = new Set();
27
27
  Object.assign(this, meta);
28
- }
29
- addProperty(prop, sync = true) {
30
- if (prop.pivotTable && !prop.pivotEntity) {
31
- prop.pivotEntity = prop.pivotTable;
28
+ const name = meta.className ?? meta.name;
29
+ if (!this.class && name) {
30
+ this.class = ({ [name]: class {
31
+ } })[name];
32
32
  }
33
+ }
34
+ addProperty(prop) {
33
35
  this.properties[prop.name] = prop;
34
36
  this.propertyOrder.set(prop.name, this.props.length);
35
- /* v8 ignore next */
36
- if (sync) {
37
- this.sync();
38
- }
37
+ this.sync();
39
38
  }
40
39
  removeProperty(name, sync = true) {
41
40
  delete this.properties[name];
42
41
  this.propertyOrder.delete(name);
43
- /* v8 ignore next */
44
42
  if (sync) {
45
43
  this.sync();
46
44
  }
@@ -74,6 +72,9 @@ export class EntityMetadata {
74
72
  set tableName(name) {
75
73
  this.collection = name;
76
74
  }
75
+ get uniqueName() {
76
+ return this.tableName + '_' + this._id;
77
+ }
77
78
  sync(initIndexes = false, config) {
78
79
  this.root ??= this;
79
80
  const props = Object.values(this.properties).sort((a, b) => this.propertyOrder.get(a.name) - this.propertyOrder.get(b.name));
@@ -100,7 +101,7 @@ export class EntityMetadata {
100
101
  return !prop.getter && !prop.setter && [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind);
101
102
  });
102
103
  this.selfReferencing = this.relations.some(prop => {
103
- return [this.className, this.root.className].includes(prop.targetMeta?.root.className ?? prop.type);
104
+ return this.root.uniqueName === prop.targetMeta?.root.uniqueName;
104
105
  });
105
106
  this.hasUniqueProps = this.uniques.length + this.uniqueProps.length > 0;
106
107
  this.virtual = !!this.expression;
@@ -191,4 +192,8 @@ export class EntityMetadata {
191
192
  clone() {
192
193
  return this;
193
194
  }
195
+ /** @ignore */
196
+ [Symbol.for('nodejs.util.inspect.custom')]() {
197
+ return `[${this.constructor.name}<${this.className}>]`;
198
+ }
194
199
  }
@@ -11,9 +11,8 @@ export declare class ChangeSet<T extends object> {
11
11
  getSerializedPrimaryKey(): string | null;
12
12
  }
13
13
  export interface ChangeSet<T> {
14
- name: string;
15
- rootName: string;
16
- collection: string;
14
+ meta: EntityMetadata<T>;
15
+ rootMeta: EntityMetadata<T>;
17
16
  schema?: string;
18
17
  type: ChangeSetType;
19
18
  entity: T;
@@ -13,9 +13,8 @@ export class ChangeSet {
13
13
  this.type = type;
14
14
  this.payload = payload;
15
15
  this.meta = meta;
16
- this.name = meta.className;
17
- this.rootName = meta.root.className;
18
- this.collection = meta.root.collection;
16
+ this.meta = meta;
17
+ this.rootMeta = meta.root;
19
18
  this.schema = helper(entity).__schema ?? meta.root.schema;
20
19
  }
21
20
  getPrimaryKey(object = false) {
@@ -19,7 +19,7 @@ export class ChangeSetComputer {
19
19
  this.comparator = this.config.getComparator(this.metadata);
20
20
  }
21
21
  computeChangeSet(entity) {
22
- const meta = this.metadata.get(entity.constructor.name);
22
+ const meta = this.metadata.get(entity.constructor);
23
23
  if (meta.readonly) {
24
24
  return null;
25
25
  }
@@ -91,7 +91,7 @@ export class ChangeSetComputer {
91
91
  computePayload(entity, ignoreUndefined = false) {
92
92
  const data = this.comparator.prepareEntity(entity);
93
93
  const wrapped = helper(entity);
94
- const entityName = wrapped.__meta.className;
94
+ const entityName = wrapped.__meta.class;
95
95
  const originalEntityData = wrapped.__originalEntityData;
96
96
  if (!wrapped.__initialized) {
97
97
  for (const prop of wrapped.__meta.primaryKeys) {
@@ -132,7 +132,7 @@ export class ChangeSetComputer {
132
132
  const targets = Utils.unwrapProperty(changeSet.entity, changeSet.meta, prop);
133
133
  targets.forEach(([target, idx]) => {
134
134
  if (!target.__helper.hasPrimaryKey()) {
135
- Utils.setPayloadProperty(changeSet.payload, this.metadata.find(changeSet.name), prop, target.__helper.__identifier, idx);
135
+ Utils.setPayloadProperty(changeSet.payload, changeSet.meta, prop, target.__helper.__identifier, idx);
136
136
  }
137
137
  });
138
138
  }