@mikro-orm/core 7.0.0-dev.12 → 7.0.0-dev.120

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 (207) hide show
  1. package/EntityManager.d.ts +85 -56
  2. package/EntityManager.js +332 -293
  3. package/MikroORM.d.ts +41 -32
  4. package/MikroORM.js +100 -140
  5. package/README.md +3 -2
  6. package/cache/FileCacheAdapter.d.ts +1 -1
  7. package/cache/FileCacheAdapter.js +8 -7
  8. package/cache/GeneratedCacheAdapter.d.ts +0 -1
  9. package/cache/GeneratedCacheAdapter.js +0 -2
  10. package/cache/index.d.ts +0 -1
  11. package/cache/index.js +0 -1
  12. package/connections/Connection.d.ts +16 -7
  13. package/connections/Connection.js +23 -14
  14. package/drivers/DatabaseDriver.d.ts +25 -16
  15. package/drivers/DatabaseDriver.js +35 -19
  16. package/drivers/IDatabaseDriver.d.ts +38 -17
  17. package/entity/BaseEntity.d.ts +0 -1
  18. package/entity/BaseEntity.js +0 -3
  19. package/entity/Collection.d.ts +95 -30
  20. package/entity/Collection.js +439 -99
  21. package/entity/EntityAssigner.d.ts +1 -1
  22. package/entity/EntityAssigner.js +26 -18
  23. package/entity/EntityFactory.d.ts +7 -0
  24. package/entity/EntityFactory.js +72 -53
  25. package/entity/EntityHelper.d.ts +2 -2
  26. package/entity/EntityHelper.js +30 -15
  27. package/entity/EntityLoader.d.ts +7 -6
  28. package/entity/EntityLoader.js +84 -72
  29. package/entity/EntityRepository.d.ts +1 -1
  30. package/entity/EntityRepository.js +2 -2
  31. package/entity/Reference.d.ts +6 -5
  32. package/entity/Reference.js +34 -9
  33. package/entity/WrappedEntity.d.ts +2 -7
  34. package/entity/WrappedEntity.js +3 -8
  35. package/entity/defineEntity.d.ts +568 -0
  36. package/entity/defineEntity.js +529 -0
  37. package/entity/index.d.ts +3 -2
  38. package/entity/index.js +3 -2
  39. package/entity/utils.d.ts +7 -0
  40. package/entity/utils.js +16 -4
  41. package/entity/validators.d.ts +11 -0
  42. package/entity/validators.js +65 -0
  43. package/enums.d.ts +21 -6
  44. package/enums.js +14 -1
  45. package/errors.d.ts +17 -9
  46. package/errors.js +41 -21
  47. package/events/EventManager.d.ts +2 -1
  48. package/events/EventManager.js +19 -11
  49. package/hydration/Hydrator.js +1 -2
  50. package/hydration/ObjectHydrator.d.ts +4 -4
  51. package/hydration/ObjectHydrator.js +50 -33
  52. package/index.d.ts +2 -2
  53. package/index.js +1 -2
  54. package/logging/DefaultLogger.d.ts +1 -1
  55. package/logging/DefaultLogger.js +1 -0
  56. package/logging/SimpleLogger.d.ts +1 -1
  57. package/logging/colors.d.ts +1 -1
  58. package/logging/colors.js +7 -6
  59. package/logging/index.d.ts +1 -0
  60. package/logging/index.js +1 -0
  61. package/logging/inspect.d.ts +2 -0
  62. package/logging/inspect.js +11 -0
  63. package/metadata/EntitySchema.d.ts +13 -17
  64. package/metadata/EntitySchema.js +67 -51
  65. package/metadata/MetadataDiscovery.d.ts +6 -10
  66. package/metadata/MetadataDiscovery.js +289 -298
  67. package/metadata/MetadataProvider.d.ts +11 -2
  68. package/metadata/MetadataProvider.js +46 -2
  69. package/metadata/MetadataStorage.d.ts +13 -11
  70. package/metadata/MetadataStorage.js +70 -37
  71. package/metadata/MetadataValidator.d.ts +2 -9
  72. package/metadata/MetadataValidator.js +22 -38
  73. package/metadata/discover-entities.d.ts +5 -0
  74. package/metadata/discover-entities.js +40 -0
  75. package/metadata/index.d.ts +1 -1
  76. package/metadata/index.js +1 -1
  77. package/metadata/types.d.ts +480 -0
  78. package/metadata/types.js +1 -0
  79. package/naming-strategy/AbstractNamingStrategy.d.ts +8 -4
  80. package/naming-strategy/AbstractNamingStrategy.js +8 -2
  81. package/naming-strategy/EntityCaseNamingStrategy.d.ts +3 -3
  82. package/naming-strategy/EntityCaseNamingStrategy.js +6 -5
  83. package/naming-strategy/MongoNamingStrategy.d.ts +3 -3
  84. package/naming-strategy/MongoNamingStrategy.js +6 -6
  85. package/naming-strategy/NamingStrategy.d.ts +14 -4
  86. package/naming-strategy/UnderscoreNamingStrategy.d.ts +3 -3
  87. package/naming-strategy/UnderscoreNamingStrategy.js +6 -6
  88. package/not-supported.d.ts +2 -0
  89. package/not-supported.js +4 -0
  90. package/package.json +19 -11
  91. package/platforms/ExceptionConverter.js +1 -1
  92. package/platforms/Platform.d.ts +6 -13
  93. package/platforms/Platform.js +17 -43
  94. package/serialization/EntitySerializer.d.ts +5 -0
  95. package/serialization/EntitySerializer.js +47 -27
  96. package/serialization/EntityTransformer.js +28 -18
  97. package/serialization/SerializationContext.d.ts +6 -6
  98. package/serialization/SerializationContext.js +16 -13
  99. package/types/ArrayType.d.ts +1 -1
  100. package/types/ArrayType.js +2 -3
  101. package/types/BigIntType.d.ts +8 -6
  102. package/types/BigIntType.js +1 -1
  103. package/types/BlobType.d.ts +0 -1
  104. package/types/BlobType.js +0 -3
  105. package/types/BooleanType.d.ts +2 -1
  106. package/types/BooleanType.js +3 -0
  107. package/types/DecimalType.d.ts +6 -4
  108. package/types/DecimalType.js +3 -3
  109. package/types/DoubleType.js +2 -2
  110. package/types/EnumArrayType.js +1 -2
  111. package/types/JsonType.d.ts +1 -1
  112. package/types/JsonType.js +7 -2
  113. package/types/TinyIntType.js +1 -1
  114. package/types/Type.d.ts +2 -4
  115. package/types/Type.js +3 -3
  116. package/types/Uint8ArrayType.d.ts +0 -1
  117. package/types/Uint8ArrayType.js +1 -4
  118. package/types/index.d.ts +1 -1
  119. package/typings.d.ts +124 -86
  120. package/typings.js +50 -42
  121. package/unit-of-work/ChangeSet.d.ts +2 -6
  122. package/unit-of-work/ChangeSet.js +4 -5
  123. package/unit-of-work/ChangeSetComputer.d.ts +1 -3
  124. package/unit-of-work/ChangeSetComputer.js +14 -12
  125. package/unit-of-work/ChangeSetPersister.d.ts +5 -4
  126. package/unit-of-work/ChangeSetPersister.js +65 -33
  127. package/unit-of-work/CommitOrderCalculator.d.ts +12 -10
  128. package/unit-of-work/CommitOrderCalculator.js +13 -13
  129. package/unit-of-work/UnitOfWork.d.ts +10 -3
  130. package/unit-of-work/UnitOfWork.js +139 -96
  131. package/utils/AbstractSchemaGenerator.d.ts +5 -5
  132. package/utils/AbstractSchemaGenerator.js +18 -16
  133. package/utils/AsyncContext.d.ts +6 -0
  134. package/utils/AsyncContext.js +42 -0
  135. package/utils/Configuration.d.ts +753 -207
  136. package/utils/Configuration.js +145 -190
  137. package/utils/ConfigurationLoader.d.ts +1 -54
  138. package/utils/ConfigurationLoader.js +1 -352
  139. package/utils/Cursor.d.ts +0 -3
  140. package/utils/Cursor.js +9 -6
  141. package/utils/DataloaderUtils.d.ts +15 -5
  142. package/utils/DataloaderUtils.js +65 -17
  143. package/utils/EntityComparator.d.ts +13 -9
  144. package/utils/EntityComparator.js +85 -43
  145. package/utils/QueryHelper.d.ts +14 -6
  146. package/utils/QueryHelper.js +87 -25
  147. package/utils/RawQueryFragment.d.ts +48 -25
  148. package/utils/RawQueryFragment.js +66 -70
  149. package/utils/RequestContext.js +2 -2
  150. package/utils/TransactionContext.js +2 -2
  151. package/utils/TransactionManager.d.ts +65 -0
  152. package/utils/TransactionManager.js +223 -0
  153. package/utils/Utils.d.ts +12 -119
  154. package/utils/Utils.js +97 -373
  155. package/utils/clone.js +8 -23
  156. package/utils/env-vars.d.ts +7 -0
  157. package/utils/env-vars.js +97 -0
  158. package/utils/fs-utils.d.ts +32 -0
  159. package/utils/fs-utils.js +178 -0
  160. package/utils/index.d.ts +2 -1
  161. package/utils/index.js +2 -1
  162. package/utils/upsert-utils.d.ts +9 -4
  163. package/utils/upsert-utils.js +55 -4
  164. package/decorators/Check.d.ts +0 -3
  165. package/decorators/Check.js +0 -13
  166. package/decorators/CreateRequestContext.d.ts +0 -3
  167. package/decorators/CreateRequestContext.js +0 -32
  168. package/decorators/Embeddable.d.ts +0 -8
  169. package/decorators/Embeddable.js +0 -11
  170. package/decorators/Embedded.d.ts +0 -18
  171. package/decorators/Embedded.js +0 -18
  172. package/decorators/Entity.d.ts +0 -18
  173. package/decorators/Entity.js +0 -12
  174. package/decorators/Enum.d.ts +0 -9
  175. package/decorators/Enum.js +0 -16
  176. package/decorators/Filter.d.ts +0 -2
  177. package/decorators/Filter.js +0 -8
  178. package/decorators/Formula.d.ts +0 -4
  179. package/decorators/Formula.js +0 -15
  180. package/decorators/Indexed.d.ts +0 -19
  181. package/decorators/Indexed.js +0 -20
  182. package/decorators/ManyToMany.d.ts +0 -40
  183. package/decorators/ManyToMany.js +0 -14
  184. package/decorators/ManyToOne.d.ts +0 -30
  185. package/decorators/ManyToOne.js +0 -14
  186. package/decorators/OneToMany.d.ts +0 -28
  187. package/decorators/OneToMany.js +0 -17
  188. package/decorators/OneToOne.d.ts +0 -24
  189. package/decorators/OneToOne.js +0 -7
  190. package/decorators/PrimaryKey.d.ts +0 -8
  191. package/decorators/PrimaryKey.js +0 -20
  192. package/decorators/Property.d.ts +0 -250
  193. package/decorators/Property.js +0 -32
  194. package/decorators/Transactional.d.ts +0 -13
  195. package/decorators/Transactional.js +0 -28
  196. package/decorators/hooks.d.ts +0 -16
  197. package/decorators/hooks.js +0 -47
  198. package/decorators/index.d.ts +0 -17
  199. package/decorators/index.js +0 -17
  200. package/entity/ArrayCollection.d.ts +0 -116
  201. package/entity/ArrayCollection.js +0 -402
  202. package/entity/EntityValidator.d.ts +0 -19
  203. package/entity/EntityValidator.js +0 -150
  204. package/metadata/ReflectMetadataProvider.d.ts +0 -8
  205. package/metadata/ReflectMetadataProvider.js +0 -44
  206. package/utils/resolveContextProvider.d.ts +0 -10
  207. package/utils/resolveContextProvider.js +0 -28
@@ -1,5 +1,3 @@
1
- import { basename, extname } from 'node:path';
2
- import globby from 'globby';
3
1
  import { EntityMetadata, } from '../typings.js';
4
2
  import { Utils } from '../utils/Utils.js';
5
3
  import { MetadataValidator } from './MetadataValidator.js';
@@ -7,16 +5,16 @@ import { MetadataStorage } from './MetadataStorage.js';
7
5
  import { EntitySchema } from './EntitySchema.js';
8
6
  import { Cascade, ReferenceKind } from '../enums.js';
9
7
  import { MetadataError } from '../errors.js';
10
- import { ArrayType, BigIntType, BlobType, DateType, DecimalType, DoubleType, EnumArrayType, IntervalType, JsonType, t, Type, Uint8ArrayType, UnknownType, } from '../types/index.js';
8
+ import { t, Type } from '../types/index.js';
11
9
  import { colors } from '../logging/colors.js';
12
- import { raw, RawQueryFragment } from '../utils/RawQueryFragment.js';
10
+ import { raw, Raw } from '../utils/RawQueryFragment.js';
11
+ import { BaseEntity } from '../entity/BaseEntity.js';
13
12
  export class MetadataDiscovery {
14
13
  metadata;
15
14
  platform;
16
15
  config;
17
16
  namingStrategy;
18
17
  metadataProvider;
19
- cache;
20
18
  logger;
21
19
  schemaHelper;
22
20
  validator = new MetadataValidator();
@@ -27,11 +25,11 @@ export class MetadataDiscovery {
27
25
  this.config = config;
28
26
  this.namingStrategy = this.config.getNamingStrategy();
29
27
  this.metadataProvider = this.config.getMetadataProvider();
30
- this.cache = this.config.getMetadataCacheAdapter();
31
28
  this.logger = this.config.getLogger();
32
29
  this.schemaHelper = this.platform.getSchemaHelper();
33
30
  }
34
31
  async discover(preferTs = true) {
32
+ this.discovered.length = 0;
35
33
  const startTime = Date.now();
36
34
  this.logger.log('discovery', `ORM entity discovery started, using ${colors.cyan(this.metadataProvider.constructor.name)}`);
37
35
  await this.findEntities(preferTs);
@@ -47,10 +45,12 @@ export class MetadataDiscovery {
47
45
  await this.config.get('discovery').afterDiscovered?.(storage, this.platform);
48
46
  return storage;
49
47
  }
50
- discoverSync(preferTs = true) {
48
+ discoverSync() {
49
+ this.discovered.length = 0;
51
50
  const startTime = Date.now();
52
51
  this.logger.log('discovery', `ORM entity discovery started, using ${colors.cyan(this.metadataProvider.constructor.name)} in sync mode`);
53
- this.findEntities(preferTs, true);
52
+ const refs = this.config.get('entities');
53
+ this.discoverReferences(refs);
54
54
  for (const meta of this.discovered) {
55
55
  /* v8 ignore next */
56
56
  void this.config.get('discovery').onMetadata?.(meta, this.platform);
@@ -70,15 +70,48 @@ export class MetadataDiscovery {
70
70
  .sort((a, b) => b.root.name.localeCompare(a.root.name))
71
71
  .forEach(meta => {
72
72
  this.platform.validateMetadata(meta);
73
- discovered.set(meta.className, meta);
73
+ discovered.set(meta.class, meta);
74
74
  });
75
+ for (const meta of discovered) {
76
+ meta.root = discovered.get(meta.root.class);
77
+ }
75
78
  return discovered;
76
79
  }
80
+ initAccessors(meta) {
81
+ for (const prop of Object.values(meta.properties)) {
82
+ if (!prop.accessor || meta.properties[prop.accessor]) {
83
+ continue;
84
+ }
85
+ const desc = Object.getOwnPropertyDescriptor(meta.prototype, prop.name);
86
+ if (desc?.get || desc?.set) {
87
+ this.initFieldName(prop);
88
+ const accessor = prop.name;
89
+ prop.name = typeof prop.accessor === 'string' ? prop.accessor : prop.name;
90
+ if (prop.accessor === true) {
91
+ prop.getter = prop.setter = true;
92
+ }
93
+ else {
94
+ prop.getter = prop.setter = false;
95
+ }
96
+ prop.accessor = accessor;
97
+ prop.serializedName ??= accessor;
98
+ Utils.renameKey(meta.properties, accessor, prop.name);
99
+ }
100
+ else {
101
+ const name = prop.name;
102
+ prop.name = prop.accessor;
103
+ this.initFieldName(prop);
104
+ prop.serializedName ??= prop.accessor;
105
+ prop.name = name;
106
+ }
107
+ }
108
+ }
77
109
  processDiscoveredEntities(discovered) {
78
110
  for (const meta of discovered) {
79
111
  let i = 1;
80
112
  Object.values(meta.properties).forEach(prop => meta.propertyOrder.set(prop.name, i++));
81
113
  Object.values(meta.properties).forEach(prop => this.initPolyEmbeddables(prop, discovered));
114
+ this.initAccessors(meta);
82
115
  }
83
116
  // ignore base entities (not annotated with @Entity)
84
117
  const filtered = discovered.filter(meta => meta.root.name);
@@ -86,66 +119,61 @@ export class MetadataDiscovery {
86
119
  filtered.sort((a, b) => !a.embeddable === !b.embeddable ? 0 : (a.embeddable ? 1 : -1));
87
120
  filtered.forEach(meta => this.initSingleTableInheritance(meta, filtered));
88
121
  filtered.forEach(meta => this.defineBaseEntityProperties(meta));
89
- 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
+ });
90
126
  filtered.forEach(meta => this.initAutoincrement(meta));
91
- filtered.forEach(meta => Object.values(meta.properties).forEach(prop => this.initEmbeddables(meta, prop)));
92
- filtered.forEach(meta => Object.values(meta.properties).forEach(prop => this.initFactoryField(meta, prop)));
93
- filtered.forEach(meta => Object.values(meta.properties).forEach(prop => this.initFieldName(prop)));
94
- filtered.forEach(meta => Object.values(meta.properties).forEach(prop => this.initVersionProperty(meta, prop)));
95
- filtered.forEach(meta => Object.values(meta.properties).forEach(prop => this.initCustomType(meta, prop)));
96
- 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));
97
137
  filtered.forEach(meta => this.initAutoincrement(meta)); // once again after we init custom types
98
138
  filtered.forEach(meta => this.initCheckConstraints(meta));
99
- for (const meta of filtered) {
100
- for (const prop of Object.values(meta.properties)) {
101
- this.initDefaultValue(prop);
102
- this.inferTypeFromDefault(prop);
103
- this.initColumnType(prop);
104
- // change tracking on scalars is used only for "auto" flushMode
105
- if (this.config.get('flushMode') !== 'auto' && [ReferenceKind.SCALAR, ReferenceKind.EMBEDDED].includes(prop.kind)) {
106
- prop.trackChanges = false;
107
- }
108
- }
109
- }
110
- 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));
111
146
  filtered.forEach(meta => this.autoWireBidirectionalProperties(meta));
112
- filtered.forEach(meta => this.findReferencingProperties(meta, filtered));
113
147
  for (const meta of filtered) {
114
148
  discovered.push(...this.processEntity(meta));
115
149
  }
116
150
  discovered.forEach(meta => meta.sync(true));
117
- const combinedCachePath = this.cache.combine?.();
118
- // override the path in the options, so we can log it from the CLI in `cache:generate` command
119
- if (combinedCachePath) {
120
- this.config.get('metadataCache').combined = combinedCachePath;
121
- }
151
+ this.metadataProvider.combineCache();
122
152
  return discovered.map(meta => {
123
- meta = this.metadata.get(meta.className);
153
+ meta = this.metadata.get(meta.class);
124
154
  meta.sync(true);
155
+ this.findReferencingProperties(meta, filtered);
125
156
  return meta;
126
157
  });
127
158
  }
128
- findEntities(preferTs, sync = false) {
129
- this.discovered.length = 0;
130
- const options = this.config.get('discovery');
131
- const key = (preferTs && this.config.get('preferTs', Utils.detectTypeScriptSupport()) && this.config.get('entitiesTs').length > 0) ? 'entitiesTs' : 'entities';
132
- const paths = this.config.get(key).filter(item => Utils.isString(item));
133
- const refs = this.config.get(key).filter(item => !Utils.isString(item));
134
- if (paths.length > 0) {
135
- if (sync || options.requireEntitiesArray) {
136
- throw new Error(`[requireEntitiesArray] Explicit list of entities is required, please use the 'entities' option.`);
159
+ async findEntities(preferTs) {
160
+ const { entities, entitiesTs, baseDir } = this.config.getAll();
161
+ const targets = (preferTs && entitiesTs.length > 0) ? entitiesTs : entities;
162
+ const processed = [];
163
+ const paths = [];
164
+ for (const entity of targets) {
165
+ if (typeof entity === 'string') {
166
+ paths.push(entity);
167
+ }
168
+ else {
169
+ processed.push(entity);
137
170
  }
138
- return this.discoverDirectories(paths).then(() => {
139
- this.discoverReferences(refs);
140
- this.discoverMissingTargets();
141
- this.validator.validateDiscovered(this.discovered, options);
142
- return this.discovered;
143
- });
144
171
  }
145
- this.discoverReferences(refs);
146
- this.discoverMissingTargets();
147
- this.validator.validateDiscovered(this.discovered, options);
148
- return this.discovered;
172
+ if (paths.length > 0) {
173
+ const { discoverEntities } = await import('@mikro-orm/core/file-discovery');
174
+ processed.push(...await discoverEntities(paths, { baseDir }));
175
+ }
176
+ return this.discoverReferences(processed);
149
177
  }
150
178
  discoverMissingTargets() {
151
179
  const unwrap = (type) => type
@@ -154,17 +182,22 @@ export class MetadataDiscovery {
154
182
  .replace(/\((.*)\)/, '$1'); // unwrap union types
155
183
  const missing = [];
156
184
  this.discovered.forEach(meta => Object.values(meta.properties).forEach(prop => {
157
- if (prop.kind === ReferenceKind.MANY_TO_MANY && prop.pivotEntity && !this.discovered.find(m => m.className === Utils.className(prop.pivotEntity))) {
158
- const target = typeof prop.pivotEntity === 'function'
159
- ? prop.pivotEntity()
160
- : prop.pivotEntity;
161
- 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
+ }
162
193
  }
163
- if (prop.kind !== ReferenceKind.SCALAR && !unwrap(prop.type).split(/ ?\| ?/).every(type => this.discovered.find(m => m.className === type))) {
164
- const target = typeof prop.entity === 'function'
194
+ if (prop.kind !== ReferenceKind.SCALAR) {
195
+ const target = typeof prop.entity === 'function' && !prop.entity.prototype
165
196
  ? prop.entity()
166
197
  : prop.type;
167
- 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
+ }
168
201
  }
169
202
  }));
170
203
  if (missing.length > 0) {
@@ -173,122 +206,99 @@ export class MetadataDiscovery {
173
206
  }
174
207
  tryDiscoverTargets(targets) {
175
208
  for (const target of targets) {
176
- if (typeof target === 'function' && target.name && !this.metadata.has(target.name)) {
177
- this.discoverReferences([target]);
209
+ const isDiscoverable = typeof target === 'function' || target instanceof EntitySchema;
210
+ if (isDiscoverable && target.name && !this.metadata.has(target)) {
211
+ this.discoverReferences([target], false);
178
212
  this.discoverMissingTargets();
179
213
  }
180
214
  }
181
215
  }
182
- async discoverDirectories(paths) {
183
- paths = paths.map(path => Utils.normalizePath(path));
184
- const files = await globby(paths, { cwd: Utils.normalizePath(this.config.get('baseDir')) });
185
- this.logger.log('discovery', `- processing ${colors.cyan('' + files.length)} files`);
186
- const found = [];
187
- for (const filepath of files) {
188
- const filename = basename(filepath);
189
- if (!filename.match(/\.[cm]?[jt]s$/) ||
190
- filename.endsWith('.js.map') ||
191
- filename.match(/\.d\.[cm]?ts/) ||
192
- filename.startsWith('.') ||
193
- filename.match(/index\.[cm]?[jt]s$/)) {
194
- this.logger.log('discovery', `- ignoring file ${filename}`);
195
- continue;
196
- }
197
- const name = this.namingStrategy.getClassName(filename);
198
- const path = Utils.normalizePath(this.config.get('baseDir'), filepath);
199
- const targets = await this.getEntityClassOrSchema(path, name);
200
- for (const target of targets) {
201
- if (!(target instanceof Function) && !(target instanceof EntitySchema)) {
202
- this.logger.log('discovery', `- ignoring file ${filename}`);
203
- continue;
204
- }
205
- const entity = this.prepare(target);
206
- const schema = this.getSchema(entity, path);
207
- const meta = schema.init().meta;
208
- this.metadata.set(meta.className, meta);
209
- found.push([schema, path]);
210
- }
211
- }
212
- for (const [schema, path] of found) {
213
- this.discoverEntity(schema, path);
214
- }
215
- }
216
- discoverReferences(refs) {
216
+ discoverReferences(refs, validate = true) {
217
217
  const found = [];
218
218
  for (const entity of refs) {
219
- const schema = this.getSchema(this.prepare(entity));
219
+ if (typeof entity === 'string') {
220
+ throw new Error('Folder based discovery requires the async `MikroORM.init()` method.');
221
+ }
222
+ const schema = this.getSchema(entity);
220
223
  const meta = schema.init().meta;
221
- this.metadata.set(meta.className, meta);
224
+ this.metadata.set(meta.class, meta);
222
225
  found.push(schema);
223
226
  }
224
227
  // discover parents (base entities) automatically
225
228
  for (const meta of this.metadata) {
226
229
  let parent = meta.extends;
227
- if (parent instanceof EntitySchema && !this.metadata.has(parent.meta.className)) {
228
- this.discoverReferences([parent]);
230
+ if (parent instanceof EntitySchema && !this.metadata.has(parent.init().meta.class)) {
231
+ this.discoverReferences([parent], false);
229
232
  }
230
- /* v8 ignore next 3 */
233
+ if (typeof parent === 'function' && parent.name && !this.metadata.has(parent)) {
234
+ this.discoverReferences([parent], false);
235
+ }
236
+ /* v8 ignore next */
231
237
  if (!meta.class) {
232
238
  continue;
233
239
  }
234
240
  parent = Object.getPrototypeOf(meta.class);
235
- if (parent.name !== '' && !this.metadata.has(parent.name)) {
236
- this.discoverReferences([parent]);
241
+ if (parent.name !== '' && !this.metadata.has(parent) && parent !== BaseEntity) {
242
+ this.discoverReferences([parent], false);
237
243
  }
238
244
  }
239
245
  for (const schema of found) {
240
246
  this.discoverEntity(schema);
241
247
  }
248
+ this.discoverMissingTargets();
249
+ if (validate) {
250
+ this.validator.validateDiscovered(this.discovered, this.config.get('discovery'));
251
+ }
242
252
  return this.discovered.filter(meta => found.find(m => m.name === meta.className));
243
253
  }
244
- reset(className) {
245
- 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));
246
256
  if (exists !== -1) {
247
- this.metadata.reset(this.discovered[exists].className);
257
+ this.metadata.reset(this.discovered[exists].class);
248
258
  this.discovered.splice(exists, 1);
249
259
  }
250
260
  }
251
- prepare(entity) {
252
- /* v8 ignore next 3 */
253
- if ('schema' in entity && entity.schema instanceof EntitySchema) {
254
- return entity.schema;
255
- }
261
+ getSchema(entity) {
256
262
  if (EntitySchema.REGISTRY.has(entity)) {
257
- return EntitySchema.REGISTRY.get(entity);
263
+ entity = EntitySchema.REGISTRY.get(entity);
258
264
  }
259
- return entity;
260
- }
261
- getSchema(entity, filepath) {
262
265
  if (entity instanceof EntitySchema) {
263
- if (filepath) {
264
- // initialize global metadata for given entity
265
- MetadataStorage.getMetadata(entity.meta.className, filepath);
266
- }
267
- return entity;
266
+ const meta = Utils.copy(entity.meta, false);
267
+ return EntitySchema.fromMetadata(meta);
268
268
  }
269
269
  const path = entity[MetadataStorage.PATH_SYMBOL];
270
270
  if (path) {
271
271
  const meta = Utils.copy(MetadataStorage.getMetadata(entity.name, path), false);
272
- meta.path = Utils.relativePath(path, this.config.get('baseDir'));
273
- this.metadata.set(entity.name, meta);
272
+ meta.path = path;
273
+ this.metadata.set(entity, meta);
274
274
  }
275
- const exists = this.metadata.has(entity.name);
276
- const meta = this.metadata.get(entity.name, true);
275
+ const exists = this.metadata.has(entity);
276
+ const meta = this.metadata.get(entity, true);
277
277
  meta.abstract ??= !(exists && meta.name);
278
278
  const schema = EntitySchema.fromMetadata(meta);
279
279
  schema.setClass(entity);
280
280
  return schema;
281
281
  }
282
- discoverEntity(schema, path) {
283
- this.logger.log('discovery', `- processing entity ${colors.cyan(schema.meta.className)}${colors.grey(path ? ` (${path})` : '')}`);
282
+ getRootEntity(meta) {
283
+ const base = meta.extends && this.metadata.find(meta.extends);
284
+ if (!base || base === meta) { // make sure we do not fall into infinite loop
285
+ return meta;
286
+ }
287
+ const root = this.getRootEntity(base);
288
+ if (root.discriminatorColumn) {
289
+ return root;
290
+ }
291
+ return meta;
292
+ }
293
+ discoverEntity(schema) {
284
294
  const meta = schema.meta;
285
- const root = Utils.getRootEntity(this.metadata, meta);
286
- schema.meta.path = Utils.relativePath(path || meta.path, this.config.get('baseDir'));
287
- const cache = this.metadataProvider.useCache() && meta.path && this.cache.get(meta.className + extname(meta.path));
295
+ const path = meta.path;
296
+ this.logger.log('discovery', `- processing entity ${colors.cyan(meta.className)}${colors.grey(path ? ` (${path})` : '')}`);
297
+ const root = this.getRootEntity(meta);
298
+ schema.meta.path = meta.path;
299
+ const cache = this.metadataProvider.getCachedMetadata(meta, root);
288
300
  if (cache) {
289
301
  this.logger.log('discovery', `- using cached metadata for entity ${colors.cyan(meta.className)}`);
290
- this.metadataProvider.loadFromCache(meta, cache);
291
- meta.root = root;
292
302
  this.discovered.push(meta);
293
303
  return;
294
304
  }
@@ -297,50 +307,18 @@ export class MetadataDiscovery {
297
307
  this.inferDefaultValue(meta, prop);
298
308
  }
299
309
  // if the definition is using EntitySchema we still want it to go through the metadata provider to validate no types are missing
300
- this.metadataProvider.loadEntityMetadata(meta, meta.className);
301
- if (!meta.collection && meta.name) {
310
+ this.metadataProvider.loadEntityMetadata(meta);
311
+ if (!meta.tableName && meta.name) {
302
312
  const entityName = root.discriminatorColumn ? root.name : meta.name;
303
- meta.collection = this.namingStrategy.classToTableName(entityName);
313
+ meta.tableName = this.namingStrategy.classToTableName(entityName);
304
314
  }
305
- delete meta.root; // to allow caching (as root can contain cycles)
306
- this.saveToCache(meta);
315
+ this.metadataProvider.saveToCache(meta);
307
316
  meta.root = root;
308
317
  this.discovered.push(meta);
309
318
  }
310
- saveToCache(meta) {
311
- if (!this.metadataProvider.useCache()) {
312
- return;
313
- }
314
- const copy = Utils.copy(meta, false);
315
- for (const prop of copy.props) {
316
- if (Type.isMappedType(prop.type)) {
317
- Reflect.deleteProperty(prop, 'type');
318
- Reflect.deleteProperty(prop, 'customType');
319
- }
320
- if (prop.default) {
321
- const raw = RawQueryFragment.getKnownFragment(prop.default);
322
- if (raw) {
323
- prop.defaultRaw ??= this.platform.formatQuery(raw.sql, raw.params);
324
- Reflect.deleteProperty(prop, 'default');
325
- }
326
- }
327
- Reflect.deleteProperty(prop, 'targetMeta');
328
- }
329
- [
330
- 'prototype', 'props', 'referencingProperties', 'propertyOrder', 'relations',
331
- 'concurrencyCheckKeys', 'checks',
332
- ].forEach(key => delete copy[key]);
333
- // base entity without properties might not have path, but nothing to cache there
334
- if (meta.path) {
335
- this.cache.set(meta.className + extname(meta.path), copy, meta.path);
336
- }
337
- }
338
319
  initNullability(prop) {
339
- if (prop.kind === ReferenceKind.MANY_TO_ONE) {
340
- return Utils.defaultValue(prop, 'nullable', prop.optional || prop.cascade.includes(Cascade.REMOVE) || prop.cascade.includes(Cascade.ALL));
341
- }
342
320
  if (prop.kind === ReferenceKind.ONE_TO_ONE) {
343
- return Utils.defaultValue(prop, 'nullable', prop.optional || !prop.owner || prop.cascade.includes(Cascade.REMOVE) || prop.cascade.includes(Cascade.ALL));
321
+ return Utils.defaultValue(prop, 'nullable', prop.optional || !prop.owner);
344
322
  }
345
323
  return Utils.defaultValue(prop, 'nullable', prop.optional);
346
324
  }
@@ -375,7 +353,7 @@ export class MetadataDiscovery {
375
353
  if (prop.joinColumns.length !== prop.columnTypes.length) {
376
354
  prop.columnTypes = prop.joinColumns.flatMap(field => {
377
355
  const matched = meta.props.find(p => p.fieldNames?.includes(field));
378
- /* v8 ignore next 3 */
356
+ /* v8 ignore next */
379
357
  if (!matched) {
380
358
  throw MetadataError.fromWrongForeignKey(meta, prop, 'columnTypes');
381
359
  }
@@ -402,7 +380,7 @@ export class MetadataDiscovery {
402
380
  }
403
381
  }
404
382
  initManyToOneFieldName(prop, name) {
405
- const meta2 = this.metadata.get(prop.type);
383
+ const meta2 = prop.targetMeta;
406
384
  const ret = [];
407
385
  for (const primaryKey of meta2.primaryKeys) {
408
386
  this.initFieldName(meta2.properties[primaryKey]);
@@ -413,11 +391,11 @@ export class MetadataDiscovery {
413
391
  return ret;
414
392
  }
415
393
  initManyToManyFieldName(prop, name) {
416
- const meta2 = this.metadata.get(prop.type);
394
+ const meta2 = prop.targetMeta;
417
395
  return meta2.primaryKeys.map(() => this.namingStrategy.propertyToColumnName(name));
418
396
  }
419
397
  initManyToManyFields(meta, prop) {
420
- const meta2 = this.metadata.get(prop.type);
398
+ const meta2 = prop.targetMeta;
421
399
  Utils.defaultValue(prop, 'fixedOrder', !!prop.fixedOrderColumn);
422
400
  const pivotMeta = this.metadata.find(prop.pivotEntity);
423
401
  const props = Object.values(pivotMeta?.properties ?? {});
@@ -438,26 +416,26 @@ export class MetadataDiscovery {
438
416
  prop.inverseJoinColumns ??= second.fieldNames;
439
417
  }
440
418
  if (!prop.pivotTable && prop.owner && this.platform.usesPivotTable()) {
441
- prop.pivotTable = this.namingStrategy.joinTableName(meta.tableName, meta2.tableName, prop.name);
419
+ prop.pivotTable = this.namingStrategy.joinTableName(meta.className, meta2.tableName, prop.name, meta.tableName);
442
420
  }
443
421
  if (prop.mappedBy) {
444
422
  const prop2 = meta2.properties[prop.mappedBy];
445
423
  this.initManyToManyFields(meta2, prop2);
446
424
  prop.pivotTable = prop2.pivotTable;
447
- prop.pivotEntity = prop2.pivotEntity ?? prop2.pivotTable;
425
+ prop.pivotEntity = prop2.pivotEntity;
448
426
  prop.fixedOrder = prop2.fixedOrder;
449
427
  prop.fixedOrderColumn = prop2.fixedOrderColumn;
450
428
  prop.joinColumns = prop2.inverseJoinColumns;
451
429
  prop.inverseJoinColumns = prop2.joinColumns;
452
430
  }
453
431
  prop.referencedColumnNames ??= Utils.flatten(meta.primaryKeys.map(primaryKey => meta.properties[primaryKey].fieldNames));
454
- prop.joinColumns ??= prop.referencedColumnNames.map(referencedColumnName => this.namingStrategy.joinKeyColumnName(meta.root.className, referencedColumnName, meta.compositePK));
432
+ prop.joinColumns ??= prop.referencedColumnNames.map(referencedColumnName => this.namingStrategy.joinKeyColumnName(meta.root.className, referencedColumnName, meta.compositePK, meta.root.tableName));
455
433
  prop.inverseJoinColumns ??= this.initManyToOneFieldName(prop, meta2.root.className);
456
434
  }
457
435
  initManyToOneFields(prop) {
458
- const meta2 = this.metadata.get(prop.type);
436
+ const meta2 = prop.targetMeta;
459
437
  const fieldNames = Utils.flatten(meta2.primaryKeys.map(primaryKey => meta2.properties[primaryKey].fieldNames));
460
- Utils.defaultValue(prop, 'referencedTableName', meta2.collection);
438
+ Utils.defaultValue(prop, 'referencedTableName', meta2.tableName);
461
439
  if (!prop.joinColumns) {
462
440
  prop.joinColumns = fieldNames.map(fieldName => this.namingStrategy.joinKeyColumnName(prop.name, fieldName, fieldNames.length > 1));
463
441
  }
@@ -466,7 +444,7 @@ export class MetadataDiscovery {
466
444
  }
467
445
  }
468
446
  initOneToManyFields(prop) {
469
- const meta2 = this.metadata.get(prop.type);
447
+ const meta2 = prop.targetMeta;
470
448
  if (!prop.joinColumns) {
471
449
  prop.joinColumns = [this.namingStrategy.joinColumnName(prop.name)];
472
450
  }
@@ -484,7 +462,7 @@ export class MetadataDiscovery {
484
462
  pks[0].deleteRule ??= 'cascade';
485
463
  }
486
464
  meta.forceConstructor ??= this.shouldForceConstructorUsage(meta);
487
- this.validator.validateEntityDefinition(this.metadata, meta.className, this.config.get('discovery'));
465
+ this.validator.validateEntityDefinition(this.metadata, meta.class, this.config.get('discovery'));
488
466
  for (const prop of Object.values(meta.properties)) {
489
467
  this.initNullability(prop);
490
468
  this.applyNamingStrategy(meta, prop);
@@ -497,15 +475,21 @@ export class MetadataDiscovery {
497
475
  }
498
476
  this.initOwnColumns(meta);
499
477
  meta.simplePK = pks.length === 1 && pks[0].kind === ReferenceKind.SCALAR && !pks[0].customType && pks[0].runtimeType !== 'Date';
500
- meta.serializedPrimaryKey = this.platform.getSerializedPrimaryKeyField(meta.primaryKeys[0]);
501
- const serializedPKProp = meta.properties[meta.serializedPrimaryKey];
502
- if (serializedPKProp && meta.serializedPrimaryKey !== meta.primaryKeys[0]) {
503
- serializedPKProp.persist = false;
478
+ meta.serializedPrimaryKey ??= meta.props.find(prop => prop.serializedPrimaryKey)?.name;
479
+ if (meta.serializedPrimaryKey && meta.serializedPrimaryKey !== meta.primaryKeys[0]) {
480
+ meta.properties[meta.serializedPrimaryKey].persist ??= false;
504
481
  }
505
482
  if (this.platform.usesPivotTable()) {
506
483
  return Object.values(meta.properties)
507
484
  .filter(prop => prop.kind === ReferenceKind.MANY_TO_MANY && prop.owner && prop.pivotTable)
508
- .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
+ });
509
493
  }
510
494
  return [];
511
495
  }
@@ -522,8 +506,11 @@ export class MetadataDiscovery {
522
506
  ['mappedBy', 'inversedBy', 'pivotEntity'].forEach(type => {
523
507
  const value = prop[type];
524
508
  if (value instanceof Function) {
525
- const meta2 = this.metadata.get(prop.type);
509
+ const meta2 = prop.targetMeta ?? this.metadata.get(prop.target);
526
510
  prop[type] = value(meta2.properties)?.name;
511
+ if (type === 'pivotEntity' && value) {
512
+ prop[type] = value(meta2.properties);
513
+ }
527
514
  if (prop[type] == null) {
528
515
  throw MetadataError.fromWrongReference(meta, prop, type);
529
516
  }
@@ -539,9 +526,9 @@ export class MetadataDiscovery {
539
526
  }
540
527
  else if (fks.length >= 2) {
541
528
  [first, second] = fks;
542
- /* v8 ignore next 3 */
543
529
  }
544
530
  else {
531
+ /* v8 ignore next */
545
532
  return [];
546
533
  }
547
534
  // wrong FK order, first FK needs to point to the owning side
@@ -555,7 +542,9 @@ export class MetadataDiscovery {
555
542
  return [first, second];
556
543
  }
557
544
  definePivotTableEntity(meta, prop) {
558
- 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);
559
548
  // ensure inverse side exists so we can join it when populating via pivot tables
560
549
  if (!prop.inversedBy && prop.targetMeta) {
561
550
  const inverseName = `${meta.className}_${prop.name}__inverse`;
@@ -564,6 +553,8 @@ export class MetadataDiscovery {
564
553
  name: inverseName,
565
554
  kind: ReferenceKind.MANY_TO_MANY,
566
555
  type: meta.className,
556
+ target: meta.class,
557
+ targetMeta: meta,
567
558
  mappedBy: prop.name,
568
559
  pivotEntity: prop.pivotEntity,
569
560
  pivotTable: prop.pivotTable,
@@ -572,55 +563,51 @@ export class MetadataDiscovery {
572
563
  };
573
564
  this.applyNamingStrategy(prop.targetMeta, inverseProp);
574
565
  this.initCustomType(prop.targetMeta, inverseProp);
575
- this.initRelation(inverseProp);
576
566
  prop.targetMeta.properties[inverseName] = inverseProp;
577
567
  }
578
568
  if (pivotMeta) {
569
+ prop.pivotEntity = pivotMeta.class;
579
570
  this.ensureCorrectFKOrderInPivotEntity(pivotMeta, prop);
580
571
  return pivotMeta;
581
572
  }
582
- const exists = this.metadata.find(prop.pivotTable);
583
- if (exists) {
584
- prop.pivotEntity = exists.className;
585
- return exists;
586
- }
587
573
  let tableName = prop.pivotTable;
588
574
  let schemaName;
589
575
  if (prop.pivotTable.includes('.')) {
590
576
  [schemaName, tableName] = prop.pivotTable.split('.');
591
577
  }
592
578
  schemaName ??= meta.schema;
593
- const targetType = prop.targetMeta.className;
594
- const data = new EntityMetadata({
579
+ const targetMeta = prop.targetMeta;
580
+ const targetType = targetMeta.className;
581
+ const pivotMeta2 = new EntityMetadata({
595
582
  name: prop.pivotTable,
596
583
  className: prop.pivotTable,
597
584
  collection: tableName,
598
585
  schema: schemaName,
599
586
  pivotTable: true,
600
587
  });
601
- prop.pivotEntity = data.className;
588
+ prop.pivotEntity = pivotMeta2.class;
602
589
  if (prop.fixedOrder) {
603
- const primaryProp = this.defineFixedOrderProperty(prop, targetType);
604
- data.properties[primaryProp.name] = primaryProp;
590
+ const primaryProp = this.defineFixedOrderProperty(prop, targetMeta);
591
+ pivotMeta2.properties[primaryProp.name] = primaryProp;
605
592
  }
606
593
  else {
607
- data.compositePK = true;
594
+ pivotMeta2.compositePK = true;
608
595
  }
609
596
  // handle self-referenced m:n with same default field names
610
597
  if (meta.className === targetType && prop.joinColumns.every((joinColumn, idx) => joinColumn === prop.inverseJoinColumns[idx])) {
611
- prop.joinColumns = prop.referencedColumnNames.map(name => this.namingStrategy.joinKeyColumnName(meta.className + '_1', name, meta.compositePK));
612
- prop.inverseJoinColumns = prop.referencedColumnNames.map(name => this.namingStrategy.joinKeyColumnName(meta.className + '_2', name, meta.compositePK));
598
+ prop.joinColumns = prop.referencedColumnNames.map(name => this.namingStrategy.joinKeyColumnName(meta.tableName + '_1', name, meta.compositePK));
599
+ prop.inverseJoinColumns = prop.referencedColumnNames.map(name => this.namingStrategy.joinKeyColumnName(meta.tableName + '_2', name, meta.compositePK));
613
600
  if (prop.inversedBy) {
614
- const prop2 = this.metadata.get(targetType).properties[prop.inversedBy];
601
+ const prop2 = targetMeta.properties[prop.inversedBy];
615
602
  prop2.inverseJoinColumns = prop.joinColumns;
616
603
  prop2.joinColumns = prop.inverseJoinColumns;
617
604
  }
618
605
  }
619
- data.properties[meta.name + '_owner'] = this.definePivotProperty(prop, meta.name + '_owner', meta.className, targetType + '_inverse', true, meta.className === targetType);
620
- data.properties[targetType + '_inverse'] = this.definePivotProperty(prop, targetType + '_inverse', targetType, meta.name + '_owner', false, meta.className === targetType);
621
- return this.metadata.set(data.className, data);
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);
622
609
  }
623
- defineFixedOrderProperty(prop, targetType) {
610
+ defineFixedOrderProperty(prop, targetMeta) {
624
611
  const pk = prop.fixedOrderColumn || this.namingStrategy.referenceColumnName();
625
612
  const primaryProp = {
626
613
  name: pk,
@@ -634,7 +621,7 @@ export class MetadataDiscovery {
634
621
  this.initColumnType(primaryProp);
635
622
  prop.fixedOrderColumn = pk;
636
623
  if (prop.inversedBy) {
637
- const prop2 = this.metadata.get(targetType).properties[prop.inversedBy];
624
+ const prop2 = targetMeta.properties[prop.inversedBy];
638
625
  prop2.fixedOrder = true;
639
626
  prop2.fixedOrderColumn = pk;
640
627
  }
@@ -643,7 +630,8 @@ export class MetadataDiscovery {
643
630
  definePivotProperty(prop, name, type, inverse, owner, selfReferencing) {
644
631
  const ret = {
645
632
  name,
646
- type,
633
+ type: Utils.className(type),
634
+ target: type,
647
635
  kind: ReferenceKind.MANY_TO_ONE,
648
636
  cascade: [Cascade.ALL],
649
637
  fixedOrder: prop.fixedOrder,
@@ -653,6 +641,7 @@ export class MetadataDiscovery {
653
641
  autoincrement: false,
654
642
  updateRule: prop.updateRule,
655
643
  deleteRule: prop.deleteRule,
644
+ createForeignKeyConstraint: prop.createForeignKeyConstraint,
656
645
  };
657
646
  if (selfReferencing && !this.platform.supportsMultipleCascadePaths()) {
658
647
  ret.updateRule ??= 'no action';
@@ -700,7 +689,7 @@ export class MetadataDiscovery {
700
689
  Object.values(meta.properties)
701
690
  .filter(prop => prop.kind !== ReferenceKind.SCALAR && !prop.owner && prop.mappedBy)
702
691
  .forEach(prop => {
703
- const meta2 = this.metadata.get(prop.type);
692
+ const meta2 = prop.targetMeta;
704
693
  const prop2 = meta2.properties[prop.mappedBy];
705
694
  if (prop2 && !prop2.inversedBy) {
706
695
  prop2.inversedBy = prop.name;
@@ -708,7 +697,7 @@ export class MetadataDiscovery {
708
697
  });
709
698
  }
710
699
  defineBaseEntityProperties(meta) {
711
- const base = meta.extends && this.metadata.get(Utils.className(meta.extends));
700
+ const base = meta.extends && this.metadata.get(meta.extends);
712
701
  if (!base || base === meta) { // make sure we do not fall into infinite loop
713
702
  return 0;
714
703
  }
@@ -739,12 +728,9 @@ export class MetadataDiscovery {
739
728
  Utils.keys(base.hooks).forEach(type => {
740
729
  meta.hooks[type] = Utils.unique([...base.hooks[type], ...(meta.hooks[type] || [])]);
741
730
  });
742
- if (meta.constructorParams.length === 0 && base.constructorParams.length > 0) {
731
+ if ((meta.constructorParams?.length ?? 0) === 0 && (base.constructorParams?.length ?? 0) > 0) {
743
732
  meta.constructorParams = [...base.constructorParams];
744
733
  }
745
- if (meta.toJsonParams.length === 0 && base.toJsonParams.length > 0) {
746
- meta.toJsonParams = [...base.toJsonParams];
747
- }
748
734
  return order;
749
735
  }
750
736
  initPolyEmbeddables(embeddedProp, discovered, visited = new Set()) {
@@ -820,22 +806,30 @@ export class MetadataDiscovery {
820
806
  }
821
807
  return prop.embedded ? isParentObject(meta.properties[prop.embedded[0]]) : false;
822
808
  };
809
+ const isParentArray = (prop) => {
810
+ if (prop.array) {
811
+ return true;
812
+ }
813
+ return prop.embedded ? isParentArray(meta.properties[prop.embedded[0]]) : false;
814
+ };
823
815
  const rootProperty = getRootProperty(embeddedProp);
824
816
  const parentProperty = meta.properties[embeddedProp.embedded?.[0] ?? ''];
825
817
  const object = isParentObject(embeddedProp);
818
+ const array = isParentArray(embeddedProp);
826
819
  this.initFieldName(embeddedProp, rootProperty !== embeddedProp && object);
827
820
  // the prefix of the parent cannot be a boolean; it already passed here
828
821
  const prefix = this.getPrefix(embeddedProp, parentProperty);
829
822
  const glue = object ? '~' : '_';
830
823
  for (const prop of Object.values(embeddable.properties)) {
831
824
  const name = (embeddedProp.embeddedPath?.join(glue) ?? embeddedProp.fieldNames[0] + glue) + prop.name;
832
- meta.properties[name] = Utils.copy(prop, false);
825
+ meta.properties[name] = Utils.copy(prop);
833
826
  meta.properties[name].name = name;
834
827
  meta.properties[name].embedded = [embeddedProp.name, prop.name];
835
828
  meta.propertyOrder.set(name, (order += 0.01));
836
829
  embeddedProp.embeddedProps[prop.name] = meta.properties[name];
837
830
  meta.properties[name].persist ??= embeddedProp.persist;
838
- if (embeddedProp.nullable) {
831
+ const refInArray = array && [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && prop.owner;
832
+ if (embeddedProp.nullable || refInArray) {
839
833
  meta.properties[name].nullable = true;
840
834
  }
841
835
  if (meta.properties[name].fieldNames) {
@@ -873,6 +867,7 @@ export class MetadataDiscovery {
873
867
  meta.properties[name].persist = false; // only virtual as we store the whole object
874
868
  meta.properties[name].userDefined = false; // mark this as a generated/internal property, so we can distinguish from user-defined non-persist properties
875
869
  meta.properties[name].object = true;
870
+ this.initCustomType(meta, meta.properties[name], false, true);
876
871
  }
877
872
  this.initEmbeddables(meta, meta.properties[name], visited);
878
873
  }
@@ -895,7 +890,7 @@ export class MetadataDiscovery {
895
890
  }
896
891
  initSingleTableInheritance(meta, metadata) {
897
892
  if (meta.root !== meta && !meta.__processed) {
898
- meta.root = metadata.find(m => m.className === meta.root.className);
893
+ meta.root = metadata.find(m => m.class === meta.root.class);
899
894
  meta.root.__processed = true;
900
895
  }
901
896
  else {
@@ -904,17 +899,23 @@ export class MetadataDiscovery {
904
899
  if (!meta.root.discriminatorColumn) {
905
900
  return;
906
901
  }
907
- 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 {
908
909
  meta.root.discriminatorMap = {};
909
910
  const children = metadata
910
- .filter(m => m.root.className === meta.root.className && !m.abstract)
911
+ .filter(m => m.root.class === meta.root.class && !m.abstract)
911
912
  .sort((a, b) => a.className.localeCompare(b.className));
912
913
  for (const m of children) {
913
914
  const name = m.discriminatorValue ?? this.namingStrategy.classToTableName(m.className);
914
- meta.root.discriminatorMap[name] = m.className;
915
+ meta.root.discriminatorMap[name] = m.class;
915
916
  }
916
917
  }
917
- 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];
918
919
  if (!meta.root.properties[meta.root.discriminatorColumn]) {
919
920
  this.createDiscriminatorProperty(meta.root);
920
921
  }
@@ -941,10 +942,10 @@ export class MetadataDiscovery {
941
942
  newProp.items = Utils.unique([...meta.root.properties[prop.name].items, ...prop.items]);
942
943
  }
943
944
  newProp.nullable = true;
944
- newProp.inherited = true;
945
+ newProp.inherited = !meta.root.properties[prop.name];
945
946
  meta.root.addProperty(newProp);
946
947
  });
947
- meta.collection = meta.root.collection;
948
+ meta.tableName = meta.root.tableName;
948
949
  meta.root.indexes = Utils.unique([...meta.root.indexes, ...meta.indexes]);
949
950
  meta.root.uniques = Utils.unique([...meta.root.uniques, ...meta.uniques]);
950
951
  meta.root.checks = Utils.unique([...meta.root.checks, ...meta.checks]);
@@ -966,7 +967,7 @@ export class MetadataDiscovery {
966
967
  }
967
968
  }
968
969
  initCheckConstraints(meta) {
969
- const map = this.createColumnMappingObject(meta);
970
+ const map = meta.createColumnMappingObject();
970
971
  for (const check of meta.checks) {
971
972
  const columns = check.property ? meta.properties[check.property].fieldNames : [];
972
973
  check.name ??= this.namingStrategy.indexName(meta.tableName, columns, 'check');
@@ -976,7 +977,7 @@ export class MetadataDiscovery {
976
977
  }
977
978
  if (this.platform.usesEnumCheckConstraints() && !meta.embeddable) {
978
979
  for (const prop of meta.props) {
979
- if (prop.enum && !prop.nativeEnumName && prop.items?.every(item => Utils.isString(item))) {
980
+ if (prop.enum && !prop.nativeEnumName && prop.items?.every(item => typeof item === 'string')) {
980
981
  this.initFieldName(prop);
981
982
  meta.checks.push({
982
983
  name: this.namingStrategy.indexName(meta.tableName, prop.fieldNames, 'check'),
@@ -1001,38 +1002,28 @@ export class MetadataDiscovery {
1001
1002
  }
1002
1003
  return;
1003
1004
  }
1004
- const map = this.createColumnMappingObject(meta);
1005
+ const map = meta.createColumnMappingObject();
1005
1006
  if (prop.generated instanceof Function) {
1006
1007
  prop.generated = prop.generated(map);
1007
1008
  }
1008
1009
  }
1009
- createColumnMappingObject(meta) {
1010
- return Object.values(meta.properties).reduce((o, prop) => {
1011
- if (prop.fieldNames) {
1012
- o[prop.name] = prop.fieldNames[0];
1013
- }
1014
- return o;
1015
- }, {});
1016
- }
1017
- getDefaultVersionValue(prop) {
1010
+ getDefaultVersionValue(meta, prop) {
1018
1011
  if (typeof prop.defaultRaw !== 'undefined') {
1019
1012
  return prop.defaultRaw;
1020
1013
  }
1021
- /* v8 ignore next 3 */
1014
+ /* v8 ignore next */
1022
1015
  if (prop.default != null) {
1023
1016
  return '' + this.platform.quoteVersionValue(prop.default, prop);
1024
1017
  }
1025
- if (prop.type.toLowerCase() === 'date') {
1018
+ this.initCustomType(meta, prop, true);
1019
+ const type = prop.customType?.runtimeType ?? prop.runtimeType ?? prop.type;
1020
+ if (type === 'Date') {
1026
1021
  prop.length ??= this.platform.getDefaultVersionLength();
1027
1022
  return this.platform.getCurrentTimestampSQL(prop.length);
1028
1023
  }
1029
1024
  return '1';
1030
1025
  }
1031
1026
  inferDefaultValue(meta, prop) {
1032
- /* v8 ignore next 3 */
1033
- if (!meta.class) {
1034
- return;
1035
- }
1036
1027
  try {
1037
1028
  // try to create two entity instances to detect the value is stable
1038
1029
  const now = Date.now();
@@ -1060,12 +1051,12 @@ export class MetadataDiscovery {
1060
1051
  return;
1061
1052
  }
1062
1053
  let val = prop.default;
1063
- const raw = RawQueryFragment.getKnownFragment(val);
1054
+ const raw = Raw.getKnownFragment(val);
1064
1055
  if (raw) {
1065
1056
  prop.defaultRaw = this.platform.formatQuery(raw.sql, raw.params);
1066
1057
  return;
1067
1058
  }
1068
- if (prop.customType instanceof ArrayType && Array.isArray(prop.default)) {
1059
+ if (Array.isArray(prop.default) && prop.customType) {
1069
1060
  val = prop.customType.convertToDatabaseValue(prop.default, this.platform);
1070
1061
  }
1071
1062
  prop.defaultRaw = typeof val === 'string' ? `'${val}'` : '' + val;
@@ -1093,13 +1084,13 @@ export class MetadataDiscovery {
1093
1084
  if (prop.version) {
1094
1085
  this.initDefaultValue(prop);
1095
1086
  meta.versionProperty = prop.name;
1096
- prop.defaultRaw = this.getDefaultVersionValue(prop);
1087
+ prop.defaultRaw = this.getDefaultVersionValue(meta, prop);
1097
1088
  }
1098
1089
  if (prop.concurrencyCheck && !prop.primary) {
1099
1090
  meta.concurrencyCheckKeys.add(prop.name);
1100
1091
  }
1101
1092
  }
1102
- initCustomType(meta, prop) {
1093
+ initCustomType(meta, prop, simple = false, objectEmbeddable = false) {
1103
1094
  // `prop.type` might be actually instance of custom type class
1104
1095
  if (Type.isMappedType(prop.type) && !prop.customType) {
1105
1096
  prop.customType = prop.type;
@@ -1107,47 +1098,70 @@ export class MetadataDiscovery {
1107
1098
  }
1108
1099
  // `prop.type` might also be custom type class (not instance), so `typeof MyType` will give us `function`, not `object`
1109
1100
  if (typeof prop.type === 'function' && Type.isMappedType(prop.type.prototype) && !prop.customType) {
1110
- prop.customType = new prop.type();
1111
- prop.type = prop.customType.constructor.name;
1101
+ // if the type is an ORM defined mapped type without `ensureComparable: true`,
1102
+ // we use just the type name, to have more performant hydration code
1103
+ const type = Utils.keys(t).find(type => {
1104
+ return !Type.getType(t[type]).ensureComparable(meta, prop) && prop.type === t[type];
1105
+ });
1106
+ if (type) {
1107
+ prop.type = type === 'datetime' ? 'Date' : type;
1108
+ }
1109
+ else {
1110
+ prop.customType = new prop.type();
1111
+ prop.type = prop.customType.constructor.name;
1112
+ }
1113
+ }
1114
+ if (simple) {
1115
+ return;
1112
1116
  }
1113
1117
  if (!prop.customType && ['json', 'jsonb'].includes(prop.type?.toLowerCase())) {
1114
- prop.customType = new JsonType();
1118
+ prop.customType = new t.json();
1115
1119
  }
1116
1120
  if (prop.kind === ReferenceKind.SCALAR && !prop.customType && prop.columnTypes && ['json', 'jsonb'].includes(prop.columnTypes[0])) {
1117
- prop.customType = new JsonType();
1121
+ prop.customType = new t.json();
1122
+ }
1123
+ if (prop.kind === ReferenceKind.EMBEDDED && !prop.customType && (prop.object || prop.array)) {
1124
+ prop.customType = new t.json();
1118
1125
  }
1119
1126
  if (!prop.customType && prop.array && prop.items) {
1120
- prop.customType = new EnumArrayType(`${meta.className}.${prop.name}`, prop.items);
1127
+ prop.customType = new t.enumArray(`${meta.className}.${prop.name}`, prop.items);
1128
+ }
1129
+ const isArray = prop.type?.toLowerCase() === 'array' || prop.type?.toString().endsWith('[]');
1130
+ if (objectEmbeddable && !prop.customType && isArray) {
1131
+ prop.customType = new t.json();
1121
1132
  }
1122
1133
  // for number arrays we make sure to convert the items to numbers
1123
1134
  if (!prop.customType && prop.type === 'number[]') {
1124
- prop.customType = new ArrayType(i => +i);
1135
+ prop.customType = new t.array(i => +i);
1125
1136
  }
1126
1137
  // `string[]` can be returned via ts-morph, while reflect metadata will give us just `array`
1127
- if (!prop.customType && (prop.type?.toLowerCase() === 'array' || prop.type?.toString().endsWith('[]'))) {
1128
- prop.customType = new ArrayType();
1138
+ if (!prop.customType && isArray) {
1139
+ prop.customType = new t.array();
1129
1140
  }
1130
1141
  if (!prop.customType && prop.type?.toLowerCase() === 'buffer') {
1131
- prop.customType = new BlobType();
1142
+ prop.customType = new t.blob();
1132
1143
  }
1133
1144
  if (!prop.customType && prop.type?.toLowerCase() === 'uint8array') {
1134
- prop.customType = new Uint8ArrayType();
1145
+ prop.customType = new t.uint8array();
1135
1146
  }
1136
1147
  const mappedType = this.getMappedType(prop);
1137
1148
  if (prop.fieldNames?.length === 1 && !prop.customType) {
1138
- [BigIntType, DoubleType, DecimalType, IntervalType, DateType]
1149
+ [t.bigint, t.double, t.decimal, t.interval, t.date]
1139
1150
  .filter(type => mappedType instanceof type)
1140
- .forEach(type => prop.customType = new type());
1151
+ .forEach((type) => prop.customType = new type());
1141
1152
  }
1142
1153
  if (prop.customType && !prop.columnTypes) {
1143
1154
  const mappedType = this.getMappedType({ columnTypes: [prop.customType.getColumnType(prop, this.platform)] });
1144
- if (prop.customType.compareAsType() === 'any' && ![JsonType].some(t => prop.customType instanceof t)) {
1155
+ if (prop.customType.compareAsType() === 'any' && ![t.json].some(t => prop.customType instanceof t)) {
1145
1156
  prop.runtimeType ??= mappedType.runtimeType;
1146
1157
  }
1147
1158
  else {
1148
1159
  prop.runtimeType ??= prop.customType.runtimeType;
1149
1160
  }
1150
1161
  }
1162
+ else if (prop.runtimeType === 'object') {
1163
+ prop.runtimeType = mappedType.runtimeType;
1164
+ }
1151
1165
  else {
1152
1166
  prop.runtimeType ??= mappedType.runtimeType;
1153
1167
  }
@@ -1158,16 +1172,16 @@ export class MetadataDiscovery {
1158
1172
  prop.columnTypes ??= [prop.customType.getColumnType(prop, this.platform)];
1159
1173
  prop.hasConvertToJSValueSQL = !!prop.customType.convertToJSValueSQL && prop.customType.convertToJSValueSQL('', this.platform) !== '';
1160
1174
  prop.hasConvertToDatabaseValueSQL = !!prop.customType.convertToDatabaseValueSQL && prop.customType.convertToDatabaseValueSQL('', this.platform) !== '';
1161
- if (prop.customType instanceof BigIntType && ['string', 'bigint', 'number'].includes(prop.runtimeType.toLowerCase())) {
1175
+ if (prop.customType instanceof t.bigint && ['string', 'bigint', 'number'].includes(prop.runtimeType.toLowerCase())) {
1162
1176
  prop.customType.mode = prop.runtimeType.toLowerCase();
1163
1177
  }
1164
1178
  }
1165
- if (Type.isMappedType(prop.customType) && prop.kind === ReferenceKind.SCALAR && !prop.type?.toString().endsWith('[]')) {
1179
+ if (Type.isMappedType(prop.customType) && prop.kind === ReferenceKind.SCALAR && !isArray) {
1166
1180
  prop.type = prop.customType.name;
1167
1181
  }
1168
- 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) {
1169
1183
  prop.customTypes = [];
1170
- for (const pk of this.metadata.get(prop.type).getPrimaryProps()) {
1184
+ for (const pk of prop.targetMeta.getPrimaryProps()) {
1171
1185
  if (pk.customType) {
1172
1186
  prop.customTypes.push(pk.customType);
1173
1187
  prop.hasConvertToJSValueSQL ||= !!pk.customType.convertToJSValueSQL && pk.customType.convertToJSValueSQL('', this.platform) !== '';
@@ -1179,7 +1193,7 @@ export class MetadataDiscovery {
1179
1193
  }
1180
1194
  }
1181
1195
  }
1182
- if (prop.kind === ReferenceKind.SCALAR && !(mappedType instanceof UnknownType)) {
1196
+ if (prop.kind === ReferenceKind.SCALAR && !(mappedType instanceof t.unknown)) {
1183
1197
  if (!prop.columnTypes && prop.nativeEnumName && meta.schema !== this.platform.getDefaultSchemaName() && meta.schema && !prop.nativeEnumName.includes('.')) {
1184
1198
  prop.columnTypes = [`${meta.schema}.${prop.nativeEnumName}`];
1185
1199
  }
@@ -1197,7 +1211,8 @@ export class MetadataDiscovery {
1197
1211
  if (prop.kind === ReferenceKind.SCALAR) {
1198
1212
  return;
1199
1213
  }
1200
- 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);
1201
1216
  prop.referencedPKs = meta2.primaryKeys;
1202
1217
  prop.targetMeta = meta2;
1203
1218
  if (!prop.formula && prop.persist === false && [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && !prop.embedded) {
@@ -1206,7 +1221,7 @@ export class MetadataDiscovery {
1206
1221
  }
1207
1222
  initColumnType(prop) {
1208
1223
  this.initUnsigned(prop);
1209
- this.metadata.find(prop.type)?.getPrimaryProps().map(pk => {
1224
+ prop.targetMeta?.getPrimaryProps().map(pk => {
1210
1225
  prop.length ??= pk.length;
1211
1226
  prop.precision ??= pk.precision;
1212
1227
  prop.scale ??= pk.scale;
@@ -1222,8 +1237,7 @@ export class MetadataDiscovery {
1222
1237
  if (prop.kind === ReferenceKind.SCALAR) {
1223
1238
  const mappedType = this.getMappedType(prop);
1224
1239
  const SCALAR_TYPES = ['string', 'number', 'boolean', 'bigint', 'Date', 'Buffer', 'RegExp', 'any', 'unknown'];
1225
- if (mappedType instanceof UnknownType
1226
- && !prop.columnTypes
1240
+ if (mappedType instanceof t.unknown
1227
1241
  // it could be a runtime type from reflect-metadata
1228
1242
  && !SCALAR_TYPES.includes(prop.type)
1229
1243
  // or it might be inferred via ts-morph to some generic type alias
@@ -1236,11 +1250,12 @@ export class MetadataDiscovery {
1236
1250
  }
1237
1251
  return;
1238
1252
  }
1239
- if (prop.kind === ReferenceKind.EMBEDDED && prop.object && !prop.columnTypes) {
1253
+ /* v8 ignore next */
1254
+ if (prop.kind === ReferenceKind.EMBEDDED && prop.object) {
1240
1255
  prop.columnTypes = [this.platform.getJsonDeclarationSQL()];
1241
1256
  return;
1242
1257
  }
1243
- const targetMeta = this.metadata.get(prop.type);
1258
+ const targetMeta = prop.targetMeta;
1244
1259
  prop.columnTypes = [];
1245
1260
  for (const pk of targetMeta.getPrimaryProps()) {
1246
1261
  this.initCustomType(targetMeta, pk);
@@ -1266,7 +1281,7 @@ export class MetadataDiscovery {
1266
1281
  t = 'enum';
1267
1282
  }
1268
1283
  else if (prop.enum) {
1269
- t = prop.items?.every(item => Utils.isString(item)) ? 'enum' : 'tinyint';
1284
+ t = prop.items?.every(item => typeof item === 'string') ? 'enum' : 'tinyint';
1270
1285
  }
1271
1286
  if (t === 'Date') {
1272
1287
  t = 'datetime';
@@ -1290,7 +1305,7 @@ export class MetadataDiscovery {
1290
1305
  return;
1291
1306
  }
1292
1307
  if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind)) {
1293
- const meta2 = this.metadata.get(prop.type);
1308
+ const meta2 = prop.targetMeta;
1294
1309
  prop.unsigned = meta2.getPrimaryProps().some(pk => {
1295
1310
  this.initUnsigned(pk);
1296
1311
  return pk.unsigned;
@@ -1305,30 +1320,6 @@ export class MetadataDiscovery {
1305
1320
  prop.index ??= true;
1306
1321
  }
1307
1322
  }
1308
- async getEntityClassOrSchema(path, name) {
1309
- const exports = await Utils.dynamicImport(path);
1310
- const targets = Object.values(exports)
1311
- .filter(item => item instanceof EntitySchema || (item instanceof Function && MetadataStorage.isKnownEntity(item.name)));
1312
- // ignore class implementations that are linked from an EntitySchema
1313
- for (const item of targets) {
1314
- if (item instanceof EntitySchema) {
1315
- targets.forEach((item2, idx) => {
1316
- if (item.meta.class === item2) {
1317
- targets.splice(idx, 1);
1318
- }
1319
- });
1320
- }
1321
- }
1322
- if (targets.length > 0) {
1323
- return targets;
1324
- }
1325
- const target = exports.default ?? exports[name];
1326
- /* v8 ignore next 3 */
1327
- if (!target) {
1328
- throw MetadataError.entityNotFound(name, path.replace(this.config.get('baseDir'), '.'));
1329
- }
1330
- return [target];
1331
- }
1332
1323
  shouldForceConstructorUsage(meta) {
1333
1324
  const forceConstructor = this.config.get('forceEntityConstructor');
1334
1325
  if (Array.isArray(forceConstructor)) {