@mikro-orm/core 7.0.0-dev.14 → 7.0.0-dev.140

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