@mikro-orm/core 7.0.0-dev.15 → 7.0.0-dev.150

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 (209) hide show
  1. package/EntityManager.d.ts +81 -55
  2. package/EntityManager.js +292 -262
  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 +94 -29
  20. package/entity/Collection.js +434 -97
  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 +5 -5
  28. package/entity/EntityLoader.js +80 -70
  29. package/entity/EntityRepository.d.ts +6 -2
  30. package/entity/EntityRepository.js +8 -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 +21 -5
  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 +18 -22
  64. package/metadata/EntitySchema.js +50 -34
  65. package/metadata/MetadataDiscovery.d.ts +6 -10
  66. package/metadata/MetadataDiscovery.js +315 -304
  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 +18 -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 +158 -113
  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 +70 -34
  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 +64 -30
  143. package/utils/EntityComparator.d.ts +13 -9
  144. package/utils/EntityComparator.js +84 -42
  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 +13 -120
  154. package/utils/Utils.js +99 -375
  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 -12
  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 -32
  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 -26
  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/exports.d.ts +0 -24
  205. package/exports.js +0 -23
  206. package/metadata/ReflectMetadataProvider.d.ts +0 -8
  207. package/metadata/ReflectMetadataProvider.js +0 -44
  208. package/utils/resolveContextProvider.d.ts +0 -10
  209. 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
- import { Utils } from '../utils/Utils.js';
2
+ import { compareArrays, 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,123 +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);
235
+ }
236
+ if (typeof parent === 'function' && parent.name && !this.metadata.has(parent)) {
237
+ this.discoverReferences([parent], false);
229
238
  }
230
- /* v8 ignore next 3 */
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
269
  const meta = Utils.copy(entity.meta, false);
268
270
  return EntitySchema.fromMetadata(meta);
269
271
  }
270
272
  const path = entity[MetadataStorage.PATH_SYMBOL];
271
273
  if (path) {
272
274
  const meta = Utils.copy(MetadataStorage.getMetadata(entity.name, path), false);
273
- meta.path = Utils.relativePath(path, this.config.get('baseDir'));
274
- this.metadata.set(entity.name, meta);
275
+ meta.path = path;
276
+ this.metadata.set(entity, meta);
275
277
  }
276
- const exists = this.metadata.has(entity.name);
277
- const meta = this.metadata.get(entity.name, true);
278
+ const exists = this.metadata.has(entity);
279
+ const meta = this.metadata.get(entity, true);
278
280
  meta.abstract ??= !(exists && meta.name);
279
281
  const schema = EntitySchema.fromMetadata(meta);
280
282
  schema.setClass(entity);
281
283
  return schema;
282
284
  }
283
- discoverEntity(schema, path) {
284
- 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) {
285
297
  const meta = schema.meta;
286
- const root = Utils.getRootEntity(this.metadata, meta);
287
- schema.meta.path = Utils.relativePath(path || meta.path, this.config.get('baseDir'));
288
- 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);
289
303
  if (cache) {
290
304
  this.logger.log('discovery', `- using cached metadata for entity ${colors.cyan(meta.className)}`);
291
- this.metadataProvider.loadFromCache(meta, cache);
292
- meta.root = root;
293
305
  this.discovered.push(meta);
294
306
  return;
295
307
  }
@@ -298,50 +310,18 @@ export class MetadataDiscovery {
298
310
  this.inferDefaultValue(meta, prop);
299
311
  }
300
312
  // if the definition is using EntitySchema we still want it to go through the metadata provider to validate no types are missing
301
- this.metadataProvider.loadEntityMetadata(meta, meta.className);
302
- if (!meta.collection && meta.name) {
313
+ this.metadataProvider.loadEntityMetadata(meta);
314
+ if (!meta.tableName && meta.name) {
303
315
  const entityName = root.discriminatorColumn ? root.name : meta.name;
304
- meta.collection = this.namingStrategy.classToTableName(entityName);
316
+ meta.tableName = this.namingStrategy.classToTableName(entityName);
305
317
  }
306
- delete meta.root; // to allow caching (as root can contain cycles)
307
- this.saveToCache(meta);
318
+ this.metadataProvider.saveToCache(meta);
308
319
  meta.root = root;
309
320
  this.discovered.push(meta);
310
321
  }
311
- saveToCache(meta) {
312
- if (!this.metadataProvider.useCache()) {
313
- return;
314
- }
315
- const copy = Utils.copy(meta, false);
316
- for (const prop of copy.props) {
317
- if (Type.isMappedType(prop.type)) {
318
- Reflect.deleteProperty(prop, 'type');
319
- Reflect.deleteProperty(prop, 'customType');
320
- }
321
- if (prop.default) {
322
- const raw = RawQueryFragment.getKnownFragment(prop.default);
323
- if (raw) {
324
- prop.defaultRaw ??= this.platform.formatQuery(raw.sql, raw.params);
325
- Reflect.deleteProperty(prop, 'default');
326
- }
327
- }
328
- Reflect.deleteProperty(prop, 'targetMeta');
329
- }
330
- [
331
- 'prototype', 'props', 'referencingProperties', 'propertyOrder', 'relations',
332
- 'concurrencyCheckKeys', 'checks',
333
- ].forEach(key => delete copy[key]);
334
- // base entity without properties might not have path, but nothing to cache there
335
- if (meta.path) {
336
- this.cache.set(meta.className + extname(meta.path), copy, meta.path);
337
- }
338
- }
339
322
  initNullability(prop) {
340
- if (prop.kind === ReferenceKind.MANY_TO_ONE) {
341
- return Utils.defaultValue(prop, 'nullable', prop.optional || prop.cascade.includes(Cascade.REMOVE) || prop.cascade.includes(Cascade.ALL));
342
- }
343
323
  if (prop.kind === ReferenceKind.ONE_TO_ONE) {
344
- 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);
345
325
  }
346
326
  return Utils.defaultValue(prop, 'nullable', prop.optional);
347
327
  }
@@ -376,7 +356,7 @@ export class MetadataDiscovery {
376
356
  if (prop.joinColumns.length !== prop.columnTypes.length) {
377
357
  prop.columnTypes = prop.joinColumns.flatMap(field => {
378
358
  const matched = meta.props.find(p => p.fieldNames?.includes(field));
379
- /* v8 ignore next 3 */
359
+ /* v8 ignore next */
380
360
  if (!matched) {
381
361
  throw MetadataError.fromWrongForeignKey(meta, prop, 'columnTypes');
382
362
  }
@@ -403,7 +383,7 @@ export class MetadataDiscovery {
403
383
  }
404
384
  }
405
385
  initManyToOneFieldName(prop, name) {
406
- const meta2 = this.metadata.get(prop.type);
386
+ const meta2 = prop.targetMeta;
407
387
  const ret = [];
408
388
  for (const primaryKey of meta2.primaryKeys) {
409
389
  this.initFieldName(meta2.properties[primaryKey]);
@@ -414,11 +394,11 @@ export class MetadataDiscovery {
414
394
  return ret;
415
395
  }
416
396
  initManyToManyFieldName(prop, name) {
417
- const meta2 = this.metadata.get(prop.type);
397
+ const meta2 = prop.targetMeta;
418
398
  return meta2.primaryKeys.map(() => this.namingStrategy.propertyToColumnName(name));
419
399
  }
420
400
  initManyToManyFields(meta, prop) {
421
- const meta2 = this.metadata.get(prop.type);
401
+ const meta2 = prop.targetMeta;
422
402
  Utils.defaultValue(prop, 'fixedOrder', !!prop.fixedOrderColumn);
423
403
  const pivotMeta = this.metadata.find(prop.pivotEntity);
424
404
  const props = Object.values(pivotMeta?.properties ?? {});
@@ -439,26 +419,26 @@ export class MetadataDiscovery {
439
419
  prop.inverseJoinColumns ??= second.fieldNames;
440
420
  }
441
421
  if (!prop.pivotTable && prop.owner && this.platform.usesPivotTable()) {
442
- 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);
443
423
  }
444
424
  if (prop.mappedBy) {
445
425
  const prop2 = meta2.properties[prop.mappedBy];
446
426
  this.initManyToManyFields(meta2, prop2);
447
427
  prop.pivotTable = prop2.pivotTable;
448
- prop.pivotEntity = prop2.pivotEntity ?? prop2.pivotTable;
428
+ prop.pivotEntity = prop2.pivotEntity;
449
429
  prop.fixedOrder = prop2.fixedOrder;
450
430
  prop.fixedOrderColumn = prop2.fixedOrderColumn;
451
431
  prop.joinColumns = prop2.inverseJoinColumns;
452
432
  prop.inverseJoinColumns = prop2.joinColumns;
453
433
  }
454
434
  prop.referencedColumnNames ??= Utils.flatten(meta.primaryKeys.map(primaryKey => meta.properties[primaryKey].fieldNames));
455
- 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));
456
436
  prop.inverseJoinColumns ??= this.initManyToOneFieldName(prop, meta2.root.className);
457
437
  }
458
438
  initManyToOneFields(prop) {
459
- const meta2 = this.metadata.get(prop.type);
439
+ const meta2 = prop.targetMeta;
460
440
  const fieldNames = Utils.flatten(meta2.primaryKeys.map(primaryKey => meta2.properties[primaryKey].fieldNames));
461
- Utils.defaultValue(prop, 'referencedTableName', meta2.collection);
441
+ Utils.defaultValue(prop, 'referencedTableName', meta2.tableName);
462
442
  if (!prop.joinColumns) {
463
443
  prop.joinColumns = fieldNames.map(fieldName => this.namingStrategy.joinKeyColumnName(prop.name, fieldName, fieldNames.length > 1));
464
444
  }
@@ -467,7 +447,7 @@ export class MetadataDiscovery {
467
447
  }
468
448
  }
469
449
  initOneToManyFields(prop) {
470
- const meta2 = this.metadata.get(prop.type);
450
+ const meta2 = prop.targetMeta;
471
451
  if (!prop.joinColumns) {
472
452
  prop.joinColumns = [this.namingStrategy.joinColumnName(prop.name)];
473
453
  }
@@ -485,7 +465,7 @@ export class MetadataDiscovery {
485
465
  pks[0].deleteRule ??= 'cascade';
486
466
  }
487
467
  meta.forceConstructor ??= this.shouldForceConstructorUsage(meta);
488
- this.validator.validateEntityDefinition(this.metadata, meta.className, this.config.get('discovery'));
468
+ this.validator.validateEntityDefinition(this.metadata, meta.class, this.config.get('discovery'));
489
469
  for (const prop of Object.values(meta.properties)) {
490
470
  this.initNullability(prop);
491
471
  this.applyNamingStrategy(meta, prop);
@@ -498,15 +478,21 @@ export class MetadataDiscovery {
498
478
  }
499
479
  this.initOwnColumns(meta);
500
480
  meta.simplePK = pks.length === 1 && pks[0].kind === ReferenceKind.SCALAR && !pks[0].customType && pks[0].runtimeType !== 'Date';
501
- meta.serializedPrimaryKey = this.platform.getSerializedPrimaryKeyField(meta.primaryKeys[0]);
502
- const serializedPKProp = meta.properties[meta.serializedPrimaryKey];
503
- if (serializedPKProp && meta.serializedPrimaryKey !== meta.primaryKeys[0]) {
504
- 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;
505
484
  }
506
485
  if (this.platform.usesPivotTable()) {
507
486
  return Object.values(meta.properties)
508
487
  .filter(prop => prop.kind === ReferenceKind.MANY_TO_MANY && prop.owner && prop.pivotTable)
509
- .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
+ });
510
496
  }
511
497
  return [];
512
498
  }
@@ -523,8 +509,11 @@ export class MetadataDiscovery {
523
509
  ['mappedBy', 'inversedBy', 'pivotEntity'].forEach(type => {
524
510
  const value = prop[type];
525
511
  if (value instanceof Function) {
526
- const meta2 = this.metadata.get(prop.type);
512
+ const meta2 = prop.targetMeta ?? this.metadata.get(prop.target);
527
513
  prop[type] = value(meta2.properties)?.name;
514
+ if (type === 'pivotEntity' && value) {
515
+ prop[type] = value(meta2.properties);
516
+ }
528
517
  if (prop[type] == null) {
529
518
  throw MetadataError.fromWrongReference(meta, prop, type);
530
519
  }
@@ -540,9 +529,9 @@ export class MetadataDiscovery {
540
529
  }
541
530
  else if (fks.length >= 2) {
542
531
  [first, second] = fks;
543
- /* v8 ignore next 3 */
544
532
  }
545
533
  else {
534
+ /* v8 ignore next */
546
535
  return [];
547
536
  }
548
537
  // wrong FK order, first FK needs to point to the owning side
@@ -556,7 +545,9 @@ export class MetadataDiscovery {
556
545
  return [first, second];
557
546
  }
558
547
  definePivotTableEntity(meta, prop) {
559
- 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);
560
551
  // ensure inverse side exists so we can join it when populating via pivot tables
561
552
  if (!prop.inversedBy && prop.targetMeta) {
562
553
  const inverseName = `${meta.className}_${prop.name}__inverse`;
@@ -565,6 +556,8 @@ export class MetadataDiscovery {
565
556
  name: inverseName,
566
557
  kind: ReferenceKind.MANY_TO_MANY,
567
558
  type: meta.className,
559
+ target: meta.class,
560
+ targetMeta: meta,
568
561
  mappedBy: prop.name,
569
562
  pivotEntity: prop.pivotEntity,
570
563
  pivotTable: prop.pivotTable,
@@ -573,55 +566,51 @@ export class MetadataDiscovery {
573
566
  };
574
567
  this.applyNamingStrategy(prop.targetMeta, inverseProp);
575
568
  this.initCustomType(prop.targetMeta, inverseProp);
576
- this.initRelation(inverseProp);
577
569
  prop.targetMeta.properties[inverseName] = inverseProp;
578
570
  }
579
571
  if (pivotMeta) {
572
+ prop.pivotEntity = pivotMeta.class;
580
573
  this.ensureCorrectFKOrderInPivotEntity(pivotMeta, prop);
581
574
  return pivotMeta;
582
575
  }
583
- const exists = this.metadata.find(prop.pivotTable);
584
- if (exists) {
585
- prop.pivotEntity = exists.className;
586
- return exists;
587
- }
588
576
  let tableName = prop.pivotTable;
589
577
  let schemaName;
590
578
  if (prop.pivotTable.includes('.')) {
591
579
  [schemaName, tableName] = prop.pivotTable.split('.');
592
580
  }
593
581
  schemaName ??= meta.schema;
594
- const targetType = prop.targetMeta.className;
595
- const data = new EntityMetadata({
582
+ const targetMeta = prop.targetMeta;
583
+ const targetType = targetMeta.className;
584
+ const pivotMeta2 = new EntityMetadata({
596
585
  name: prop.pivotTable,
597
586
  className: prop.pivotTable,
598
587
  collection: tableName,
599
588
  schema: schemaName,
600
589
  pivotTable: true,
601
590
  });
602
- prop.pivotEntity = data.className;
591
+ prop.pivotEntity = pivotMeta2.class;
603
592
  if (prop.fixedOrder) {
604
- const primaryProp = this.defineFixedOrderProperty(prop, targetType);
605
- data.properties[primaryProp.name] = primaryProp;
593
+ const primaryProp = this.defineFixedOrderProperty(prop, targetMeta);
594
+ pivotMeta2.properties[primaryProp.name] = primaryProp;
606
595
  }
607
596
  else {
608
- data.compositePK = true;
597
+ pivotMeta2.compositePK = true;
609
598
  }
610
599
  // handle self-referenced m:n with same default field names
611
600
  if (meta.className === targetType && prop.joinColumns.every((joinColumn, idx) => joinColumn === prop.inverseJoinColumns[idx])) {
612
- prop.joinColumns = prop.referencedColumnNames.map(name => this.namingStrategy.joinKeyColumnName(meta.className + '_1', name, meta.compositePK));
613
- 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));
614
603
  if (prop.inversedBy) {
615
- const prop2 = this.metadata.get(targetType).properties[prop.inversedBy];
604
+ const prop2 = targetMeta.properties[prop.inversedBy];
616
605
  prop2.inverseJoinColumns = prop.joinColumns;
617
606
  prop2.joinColumns = prop.inverseJoinColumns;
618
607
  }
619
608
  }
620
- data.properties[meta.name + '_owner'] = this.definePivotProperty(prop, meta.name + '_owner', meta.className, targetType + '_inverse', true, meta.className === targetType);
621
- data.properties[targetType + '_inverse'] = this.definePivotProperty(prop, targetType + '_inverse', targetType, meta.name + '_owner', false, meta.className === targetType);
622
- 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);
623
612
  }
624
- defineFixedOrderProperty(prop, targetType) {
613
+ defineFixedOrderProperty(prop, targetMeta) {
625
614
  const pk = prop.fixedOrderColumn || this.namingStrategy.referenceColumnName();
626
615
  const primaryProp = {
627
616
  name: pk,
@@ -635,7 +624,7 @@ export class MetadataDiscovery {
635
624
  this.initColumnType(primaryProp);
636
625
  prop.fixedOrderColumn = pk;
637
626
  if (prop.inversedBy) {
638
- const prop2 = this.metadata.get(targetType).properties[prop.inversedBy];
627
+ const prop2 = targetMeta.properties[prop.inversedBy];
639
628
  prop2.fixedOrder = true;
640
629
  prop2.fixedOrderColumn = pk;
641
630
  }
@@ -644,7 +633,8 @@ export class MetadataDiscovery {
644
633
  definePivotProperty(prop, name, type, inverse, owner, selfReferencing) {
645
634
  const ret = {
646
635
  name,
647
- type,
636
+ type: Utils.className(type),
637
+ target: type,
648
638
  kind: ReferenceKind.MANY_TO_ONE,
649
639
  cascade: [Cascade.ALL],
650
640
  fixedOrder: prop.fixedOrder,
@@ -654,6 +644,7 @@ export class MetadataDiscovery {
654
644
  autoincrement: false,
655
645
  updateRule: prop.updateRule,
656
646
  deleteRule: prop.deleteRule,
647
+ createForeignKeyConstraint: prop.createForeignKeyConstraint,
657
648
  };
658
649
  if (selfReferencing && !this.platform.supportsMultipleCascadePaths()) {
659
650
  ret.updateRule ??= 'no action';
@@ -701,7 +692,7 @@ export class MetadataDiscovery {
701
692
  Object.values(meta.properties)
702
693
  .filter(prop => prop.kind !== ReferenceKind.SCALAR && !prop.owner && prop.mappedBy)
703
694
  .forEach(prop => {
704
- const meta2 = this.metadata.get(prop.type);
695
+ const meta2 = prop.targetMeta;
705
696
  const prop2 = meta2.properties[prop.mappedBy];
706
697
  if (prop2 && !prop2.inversedBy) {
707
698
  prop2.inversedBy = prop.name;
@@ -709,7 +700,7 @@ export class MetadataDiscovery {
709
700
  });
710
701
  }
711
702
  defineBaseEntityProperties(meta) {
712
- const base = meta.extends && this.metadata.get(Utils.className(meta.extends));
703
+ const base = meta.extends && this.metadata.get(meta.extends);
713
704
  if (!base || base === meta) { // make sure we do not fall into infinite loop
714
705
  return 0;
715
706
  }
@@ -740,12 +731,9 @@ export class MetadataDiscovery {
740
731
  Utils.keys(base.hooks).forEach(type => {
741
732
  meta.hooks[type] = Utils.unique([...base.hooks[type], ...(meta.hooks[type] || [])]);
742
733
  });
743
- if (meta.constructorParams.length === 0 && base.constructorParams.length > 0) {
734
+ if ((meta.constructorParams?.length ?? 0) === 0 && (base.constructorParams?.length ?? 0) > 0) {
744
735
  meta.constructorParams = [...base.constructorParams];
745
736
  }
746
- if (meta.toJsonParams.length === 0 && base.toJsonParams.length > 0) {
747
- meta.toJsonParams = [...base.toJsonParams];
748
- }
749
737
  return order;
750
738
  }
751
739
  initPolyEmbeddables(embeddedProp, discovered, visited = new Set()) {
@@ -821,22 +809,30 @@ export class MetadataDiscovery {
821
809
  }
822
810
  return prop.embedded ? isParentObject(meta.properties[prop.embedded[0]]) : false;
823
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
+ };
824
818
  const rootProperty = getRootProperty(embeddedProp);
825
819
  const parentProperty = meta.properties[embeddedProp.embedded?.[0] ?? ''];
826
820
  const object = isParentObject(embeddedProp);
821
+ const array = isParentArray(embeddedProp);
827
822
  this.initFieldName(embeddedProp, rootProperty !== embeddedProp && object);
828
823
  // the prefix of the parent cannot be a boolean; it already passed here
829
824
  const prefix = this.getPrefix(embeddedProp, parentProperty);
830
825
  const glue = object ? '~' : '_';
831
826
  for (const prop of Object.values(embeddable.properties)) {
832
827
  const name = (embeddedProp.embeddedPath?.join(glue) ?? embeddedProp.fieldNames[0] + glue) + prop.name;
833
- meta.properties[name] = Utils.copy(prop, false);
828
+ meta.properties[name] = Utils.copy(prop);
834
829
  meta.properties[name].name = name;
835
830
  meta.properties[name].embedded = [embeddedProp.name, prop.name];
836
831
  meta.propertyOrder.set(name, (order += 0.01));
837
832
  embeddedProp.embeddedProps[prop.name] = meta.properties[name];
838
833
  meta.properties[name].persist ??= embeddedProp.persist;
839
- 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) {
840
836
  meta.properties[name].nullable = true;
841
837
  }
842
838
  if (meta.properties[name].fieldNames) {
@@ -866,14 +862,17 @@ export class MetadataDiscovery {
866
862
  path = [embeddedProp.fieldNames[0]];
867
863
  }
868
864
  this.initFieldName(prop, true);
865
+ this.initRelation(prop);
869
866
  path.push(prop.fieldNames[0]);
870
867
  meta.properties[name].fieldNames = prop.fieldNames;
871
868
  meta.properties[name].embeddedPath = path;
872
- 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));
873
871
  meta.properties[name].fieldNameRaw = fieldName.sql; // for querying in SQL drivers
874
872
  meta.properties[name].persist = false; // only virtual as we store the whole object
875
873
  meta.properties[name].userDefined = false; // mark this as a generated/internal property, so we can distinguish from user-defined non-persist properties
876
874
  meta.properties[name].object = true;
875
+ this.initCustomType(meta, meta.properties[name], false, true);
877
876
  }
878
877
  this.initEmbeddables(meta, meta.properties[name], visited);
879
878
  }
@@ -896,7 +895,7 @@ export class MetadataDiscovery {
896
895
  }
897
896
  initSingleTableInheritance(meta, metadata) {
898
897
  if (meta.root !== meta && !meta.__processed) {
899
- meta.root = metadata.find(m => m.className === meta.root.className);
898
+ meta.root = metadata.find(m => m.class === meta.root.class);
900
899
  meta.root.__processed = true;
901
900
  }
902
901
  else {
@@ -905,17 +904,23 @@ export class MetadataDiscovery {
905
904
  if (!meta.root.discriminatorColumn) {
906
905
  return;
907
906
  }
908
- 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 {
909
914
  meta.root.discriminatorMap = {};
910
915
  const children = metadata
911
- .filter(m => m.root.className === meta.root.className && !m.abstract)
916
+ .filter(m => m.root.class === meta.root.class && !m.abstract)
912
917
  .sort((a, b) => a.className.localeCompare(b.className));
913
918
  for (const m of children) {
914
919
  const name = m.discriminatorValue ?? this.namingStrategy.classToTableName(m.className);
915
- meta.root.discriminatorMap[name] = m.className;
920
+ meta.root.discriminatorMap[name] = m.class;
916
921
  }
917
922
  }
918
- 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];
919
924
  if (!meta.root.properties[meta.root.discriminatorColumn]) {
920
925
  this.createDiscriminatorProperty(meta.root);
921
926
  }
@@ -927,25 +932,44 @@ export class MetadataDiscovery {
927
932
  let i = 1;
928
933
  Object.values(meta.properties).forEach(prop => {
929
934
  const newProp = { ...prop };
930
- if (meta.root.properties[prop.name] && meta.root.properties[prop.name].type !== prop.type) {
935
+ const rootProp = meta.root.properties[prop.name];
936
+ if (rootProp && (rootProp.type !== prop.type || (rootProp.fieldNames && prop.fieldNames && !compareArrays(rootProp.fieldNames, prop.fieldNames)))) {
931
937
  const name = newProp.name;
932
938
  this.initFieldName(newProp, newProp.object);
939
+ newProp.renamedFrom = name;
933
940
  newProp.name = name + '_' + (i++);
934
941
  meta.root.addProperty(newProp);
942
+ // Track all field variants and map discriminator values to field names
943
+ if (!rootProp.stiFieldNames) {
944
+ this.initFieldName(prop, prop.object);
945
+ this.initFieldName(rootProp, rootProp.object);
946
+ rootProp.stiFieldNames = [...rootProp.fieldNames];
947
+ rootProp.stiFieldNameMap = {};
948
+ // Find which discriminator owns the original fieldNames
949
+ for (const [discValue, childClass] of Object.entries(meta.root.discriminatorMap)) {
950
+ const childMeta = this.metadata.find(childClass);
951
+ if (childMeta?.properties[prop.name]?.fieldNames && compareArrays(childMeta.properties[prop.name].fieldNames, rootProp.fieldNames)) {
952
+ rootProp.stiFieldNameMap[discValue] = rootProp.fieldNames[0];
953
+ break;
954
+ }
955
+ }
956
+ }
957
+ rootProp.stiFieldNameMap[meta.discriminatorValue] = prop.fieldNames[0];
958
+ rootProp.stiFieldNames.push(...prop.fieldNames);
935
959
  newProp.nullable = true;
936
960
  newProp.name = name;
937
961
  newProp.hydrate = false;
938
962
  newProp.inherited = true;
939
963
  return;
940
964
  }
941
- if (prop.enum && prop.items && meta.root.properties[prop.name]?.items) {
942
- newProp.items = Utils.unique([...meta.root.properties[prop.name].items, ...prop.items]);
965
+ if (prop.enum && prop.items && rootProp?.items) {
966
+ newProp.items = Utils.unique([...rootProp.items, ...prop.items]);
943
967
  }
944
968
  newProp.nullable = true;
945
- newProp.inherited = true;
969
+ newProp.inherited = !rootProp;
946
970
  meta.root.addProperty(newProp);
947
971
  });
948
- meta.collection = meta.root.collection;
972
+ meta.tableName = meta.root.tableName;
949
973
  meta.root.indexes = Utils.unique([...meta.root.indexes, ...meta.indexes]);
950
974
  meta.root.uniques = Utils.unique([...meta.root.uniques, ...meta.uniques]);
951
975
  meta.root.checks = Utils.unique([...meta.root.checks, ...meta.checks]);
@@ -967,7 +991,7 @@ export class MetadataDiscovery {
967
991
  }
968
992
  }
969
993
  initCheckConstraints(meta) {
970
- const map = this.createColumnMappingObject(meta);
994
+ const map = meta.createColumnMappingObject();
971
995
  for (const check of meta.checks) {
972
996
  const columns = check.property ? meta.properties[check.property].fieldNames : [];
973
997
  check.name ??= this.namingStrategy.indexName(meta.tableName, columns, 'check');
@@ -977,7 +1001,7 @@ export class MetadataDiscovery {
977
1001
  }
978
1002
  if (this.platform.usesEnumCheckConstraints() && !meta.embeddable) {
979
1003
  for (const prop of meta.props) {
980
- if (prop.enum && !prop.nativeEnumName && prop.items?.every(item => Utils.isString(item))) {
1004
+ if (prop.enum && !prop.nativeEnumName && prop.items?.every(item => typeof item === 'string')) {
981
1005
  this.initFieldName(prop);
982
1006
  meta.checks.push({
983
1007
  name: this.namingStrategy.indexName(meta.tableName, prop.fieldNames, 'check'),
@@ -1002,38 +1026,28 @@ export class MetadataDiscovery {
1002
1026
  }
1003
1027
  return;
1004
1028
  }
1005
- const map = this.createColumnMappingObject(meta);
1029
+ const map = meta.createColumnMappingObject();
1006
1030
  if (prop.generated instanceof Function) {
1007
1031
  prop.generated = prop.generated(map);
1008
1032
  }
1009
1033
  }
1010
- createColumnMappingObject(meta) {
1011
- return Object.values(meta.properties).reduce((o, prop) => {
1012
- if (prop.fieldNames) {
1013
- o[prop.name] = prop.fieldNames[0];
1014
- }
1015
- return o;
1016
- }, {});
1017
- }
1018
- getDefaultVersionValue(prop) {
1034
+ getDefaultVersionValue(meta, prop) {
1019
1035
  if (typeof prop.defaultRaw !== 'undefined') {
1020
1036
  return prop.defaultRaw;
1021
1037
  }
1022
- /* v8 ignore next 3 */
1038
+ /* v8 ignore next */
1023
1039
  if (prop.default != null) {
1024
1040
  return '' + this.platform.quoteVersionValue(prop.default, prop);
1025
1041
  }
1026
- if (prop.type.toLowerCase() === 'date') {
1042
+ this.initCustomType(meta, prop, true);
1043
+ const type = prop.customType?.runtimeType ?? prop.runtimeType ?? prop.type;
1044
+ if (type === 'Date') {
1027
1045
  prop.length ??= this.platform.getDefaultVersionLength();
1028
1046
  return this.platform.getCurrentTimestampSQL(prop.length);
1029
1047
  }
1030
1048
  return '1';
1031
1049
  }
1032
1050
  inferDefaultValue(meta, prop) {
1033
- /* v8 ignore next 3 */
1034
- if (!meta.class) {
1035
- return;
1036
- }
1037
1051
  try {
1038
1052
  // try to create two entity instances to detect the value is stable
1039
1053
  const now = Date.now();
@@ -1061,12 +1075,12 @@ export class MetadataDiscovery {
1061
1075
  return;
1062
1076
  }
1063
1077
  let val = prop.default;
1064
- const raw = RawQueryFragment.getKnownFragment(val);
1078
+ const raw = Raw.getKnownFragment(val);
1065
1079
  if (raw) {
1066
1080
  prop.defaultRaw = this.platform.formatQuery(raw.sql, raw.params);
1067
1081
  return;
1068
1082
  }
1069
- if (prop.customType instanceof ArrayType && Array.isArray(prop.default)) {
1083
+ if (Array.isArray(prop.default) && prop.customType) {
1070
1084
  val = prop.customType.convertToDatabaseValue(prop.default, this.platform);
1071
1085
  }
1072
1086
  prop.defaultRaw = typeof val === 'string' ? `'${val}'` : '' + val;
@@ -1094,13 +1108,13 @@ export class MetadataDiscovery {
1094
1108
  if (prop.version) {
1095
1109
  this.initDefaultValue(prop);
1096
1110
  meta.versionProperty = prop.name;
1097
- prop.defaultRaw = this.getDefaultVersionValue(prop);
1111
+ prop.defaultRaw = this.getDefaultVersionValue(meta, prop);
1098
1112
  }
1099
1113
  if (prop.concurrencyCheck && !prop.primary) {
1100
1114
  meta.concurrencyCheckKeys.add(prop.name);
1101
1115
  }
1102
1116
  }
1103
- initCustomType(meta, prop) {
1117
+ initCustomType(meta, prop, simple = false, objectEmbeddable = false) {
1104
1118
  // `prop.type` might be actually instance of custom type class
1105
1119
  if (Type.isMappedType(prop.type) && !prop.customType) {
1106
1120
  prop.customType = prop.type;
@@ -1108,41 +1122,61 @@ export class MetadataDiscovery {
1108
1122
  }
1109
1123
  // `prop.type` might also be custom type class (not instance), so `typeof MyType` will give us `function`, not `object`
1110
1124
  if (typeof prop.type === 'function' && Type.isMappedType(prop.type.prototype) && !prop.customType) {
1111
- prop.customType = new prop.type();
1112
- prop.type = prop.customType.constructor.name;
1125
+ // if the type is an ORM defined mapped type without `ensureComparable: true`,
1126
+ // we use just the type name, to have more performant hydration code
1127
+ const type = Utils.keys(t).find(type => {
1128
+ return !Type.getType(t[type]).ensureComparable(meta, prop) && prop.type === t[type];
1129
+ });
1130
+ if (type) {
1131
+ prop.type = type === 'datetime' ? 'Date' : type;
1132
+ }
1133
+ else {
1134
+ prop.customType = new prop.type();
1135
+ prop.type = prop.customType.constructor.name;
1136
+ }
1137
+ }
1138
+ if (simple) {
1139
+ return;
1113
1140
  }
1114
1141
  if (!prop.customType && ['json', 'jsonb'].includes(prop.type?.toLowerCase())) {
1115
- prop.customType = new JsonType();
1142
+ prop.customType = new t.json();
1116
1143
  }
1117
1144
  if (prop.kind === ReferenceKind.SCALAR && !prop.customType && prop.columnTypes && ['json', 'jsonb'].includes(prop.columnTypes[0])) {
1118
- prop.customType = new JsonType();
1145
+ prop.customType = new t.json();
1146
+ }
1147
+ if (prop.kind === ReferenceKind.EMBEDDED && !prop.customType && (prop.object || prop.array)) {
1148
+ prop.customType = new t.json();
1119
1149
  }
1120
1150
  if (!prop.customType && prop.array && prop.items) {
1121
- prop.customType = new EnumArrayType(`${meta.className}.${prop.name}`, prop.items);
1151
+ prop.customType = new t.enumArray(`${meta.className}.${prop.name}`, prop.items);
1152
+ }
1153
+ const isArray = prop.type?.toLowerCase() === 'array' || prop.type?.toString().endsWith('[]');
1154
+ if (objectEmbeddable && !prop.customType && isArray) {
1155
+ prop.customType = new t.json();
1122
1156
  }
1123
1157
  // for number arrays we make sure to convert the items to numbers
1124
1158
  if (!prop.customType && prop.type === 'number[]') {
1125
- prop.customType = new ArrayType(i => +i);
1159
+ prop.customType = new t.array(i => +i);
1126
1160
  }
1127
1161
  // `string[]` can be returned via ts-morph, while reflect metadata will give us just `array`
1128
- if (!prop.customType && (prop.type?.toLowerCase() === 'array' || prop.type?.toString().endsWith('[]'))) {
1129
- prop.customType = new ArrayType();
1162
+ if (!prop.customType && isArray) {
1163
+ prop.customType = new t.array();
1130
1164
  }
1131
1165
  if (!prop.customType && prop.type?.toLowerCase() === 'buffer') {
1132
- prop.customType = new BlobType();
1166
+ prop.customType = new t.blob();
1133
1167
  }
1134
1168
  if (!prop.customType && prop.type?.toLowerCase() === 'uint8array') {
1135
- prop.customType = new Uint8ArrayType();
1169
+ prop.customType = new t.uint8array();
1136
1170
  }
1137
1171
  const mappedType = this.getMappedType(prop);
1138
1172
  if (prop.fieldNames?.length === 1 && !prop.customType) {
1139
- [BigIntType, DoubleType, DecimalType, IntervalType, DateType]
1173
+ [t.bigint, t.double, t.decimal, t.interval, t.date]
1140
1174
  .filter(type => mappedType instanceof type)
1141
- .forEach(type => prop.customType = new type());
1175
+ .forEach((type) => prop.customType = new type());
1142
1176
  }
1143
1177
  if (prop.customType && !prop.columnTypes) {
1144
1178
  const mappedType = this.getMappedType({ columnTypes: [prop.customType.getColumnType(prop, this.platform)] });
1145
- if (prop.customType.compareAsType() === 'any' && ![JsonType].some(t => prop.customType instanceof t)) {
1179
+ if (prop.customType.compareAsType() === 'any' && ![t.json].some(t => prop.customType instanceof t)) {
1146
1180
  prop.runtimeType ??= mappedType.runtimeType;
1147
1181
  }
1148
1182
  else {
@@ -1162,16 +1196,16 @@ export class MetadataDiscovery {
1162
1196
  prop.columnTypes ??= [prop.customType.getColumnType(prop, this.platform)];
1163
1197
  prop.hasConvertToJSValueSQL = !!prop.customType.convertToJSValueSQL && prop.customType.convertToJSValueSQL('', this.platform) !== '';
1164
1198
  prop.hasConvertToDatabaseValueSQL = !!prop.customType.convertToDatabaseValueSQL && prop.customType.convertToDatabaseValueSQL('', this.platform) !== '';
1165
- if (prop.customType instanceof BigIntType && ['string', 'bigint', 'number'].includes(prop.runtimeType.toLowerCase())) {
1199
+ if (prop.customType instanceof t.bigint && ['string', 'bigint', 'number'].includes(prop.runtimeType.toLowerCase())) {
1166
1200
  prop.customType.mode = prop.runtimeType.toLowerCase();
1167
1201
  }
1168
1202
  }
1169
- if (Type.isMappedType(prop.customType) && prop.kind === ReferenceKind.SCALAR && !prop.type?.toString().endsWith('[]')) {
1203
+ if (Type.isMappedType(prop.customType) && prop.kind === ReferenceKind.SCALAR && !isArray) {
1170
1204
  prop.type = prop.customType.name;
1171
1205
  }
1172
- if (!prop.customType && [ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(prop.kind) && this.metadata.get(prop.type).compositePK) {
1206
+ if (!prop.customType && [ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(prop.kind) && prop.targetMeta.compositePK) {
1173
1207
  prop.customTypes = [];
1174
- for (const pk of this.metadata.get(prop.type).getPrimaryProps()) {
1208
+ for (const pk of prop.targetMeta.getPrimaryProps()) {
1175
1209
  if (pk.customType) {
1176
1210
  prop.customTypes.push(pk.customType);
1177
1211
  prop.hasConvertToJSValueSQL ||= !!pk.customType.convertToJSValueSQL && pk.customType.convertToJSValueSQL('', this.platform) !== '';
@@ -1183,7 +1217,7 @@ export class MetadataDiscovery {
1183
1217
  }
1184
1218
  }
1185
1219
  }
1186
- if (prop.kind === ReferenceKind.SCALAR && !(mappedType instanceof UnknownType)) {
1220
+ if (prop.kind === ReferenceKind.SCALAR && !(mappedType instanceof t.unknown)) {
1187
1221
  if (!prop.columnTypes && prop.nativeEnumName && meta.schema !== this.platform.getDefaultSchemaName() && meta.schema && !prop.nativeEnumName.includes('.')) {
1188
1222
  prop.columnTypes = [`${meta.schema}.${prop.nativeEnumName}`];
1189
1223
  }
@@ -1201,7 +1235,8 @@ export class MetadataDiscovery {
1201
1235
  if (prop.kind === ReferenceKind.SCALAR) {
1202
1236
  return;
1203
1237
  }
1204
- const meta2 = this.discovered.find(m => m.className === prop.type);
1238
+ // 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
1239
+ const meta2 = this.metadata.find(prop.target) ?? this.metadata.getByClassName(prop.type);
1205
1240
  prop.referencedPKs = meta2.primaryKeys;
1206
1241
  prop.targetMeta = meta2;
1207
1242
  if (!prop.formula && prop.persist === false && [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && !prop.embedded) {
@@ -1210,7 +1245,7 @@ export class MetadataDiscovery {
1210
1245
  }
1211
1246
  initColumnType(prop) {
1212
1247
  this.initUnsigned(prop);
1213
- this.metadata.find(prop.type)?.getPrimaryProps().map(pk => {
1248
+ prop.targetMeta?.getPrimaryProps().map(pk => {
1214
1249
  prop.length ??= pk.length;
1215
1250
  prop.precision ??= pk.precision;
1216
1251
  prop.scale ??= pk.scale;
@@ -1226,8 +1261,7 @@ export class MetadataDiscovery {
1226
1261
  if (prop.kind === ReferenceKind.SCALAR) {
1227
1262
  const mappedType = this.getMappedType(prop);
1228
1263
  const SCALAR_TYPES = ['string', 'number', 'boolean', 'bigint', 'Date', 'Buffer', 'RegExp', 'any', 'unknown'];
1229
- if (mappedType instanceof UnknownType
1230
- && !prop.columnTypes
1264
+ if (mappedType instanceof t.unknown
1231
1265
  // it could be a runtime type from reflect-metadata
1232
1266
  && !SCALAR_TYPES.includes(prop.type)
1233
1267
  // or it might be inferred via ts-morph to some generic type alias
@@ -1240,11 +1274,12 @@ export class MetadataDiscovery {
1240
1274
  }
1241
1275
  return;
1242
1276
  }
1243
- if (prop.kind === ReferenceKind.EMBEDDED && prop.object && !prop.columnTypes) {
1277
+ /* v8 ignore next */
1278
+ if (prop.kind === ReferenceKind.EMBEDDED && prop.object) {
1244
1279
  prop.columnTypes = [this.platform.getJsonDeclarationSQL()];
1245
1280
  return;
1246
1281
  }
1247
- const targetMeta = this.metadata.get(prop.type);
1282
+ const targetMeta = prop.targetMeta;
1248
1283
  prop.columnTypes = [];
1249
1284
  for (const pk of targetMeta.getPrimaryProps()) {
1250
1285
  this.initCustomType(targetMeta, pk);
@@ -1270,7 +1305,7 @@ export class MetadataDiscovery {
1270
1305
  t = 'enum';
1271
1306
  }
1272
1307
  else if (prop.enum) {
1273
- t = prop.items?.every(item => Utils.isString(item)) ? 'enum' : 'tinyint';
1308
+ t = prop.items?.every(item => typeof item === 'string') ? 'enum' : 'tinyint';
1274
1309
  }
1275
1310
  if (t === 'Date') {
1276
1311
  t = 'datetime';
@@ -1294,7 +1329,7 @@ export class MetadataDiscovery {
1294
1329
  return;
1295
1330
  }
1296
1331
  if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind)) {
1297
- const meta2 = this.metadata.get(prop.type);
1332
+ const meta2 = prop.targetMeta;
1298
1333
  prop.unsigned = meta2.getPrimaryProps().some(pk => {
1299
1334
  this.initUnsigned(pk);
1300
1335
  return pk.unsigned;
@@ -1309,30 +1344,6 @@ export class MetadataDiscovery {
1309
1344
  prop.index ??= true;
1310
1345
  }
1311
1346
  }
1312
- async getEntityClassOrSchema(path, name) {
1313
- const exports = await Utils.dynamicImport(path);
1314
- const targets = Object.values(exports)
1315
- .filter(item => item instanceof EntitySchema || (item instanceof Function && MetadataStorage.isKnownEntity(item.name)));
1316
- // ignore class implementations that are linked from an EntitySchema
1317
- for (const item of targets) {
1318
- if (item instanceof EntitySchema) {
1319
- targets.forEach((item2, idx) => {
1320
- if (item.meta.class === item2) {
1321
- targets.splice(idx, 1);
1322
- }
1323
- });
1324
- }
1325
- }
1326
- if (targets.length > 0) {
1327
- return targets;
1328
- }
1329
- const target = exports.default ?? exports[name];
1330
- /* v8 ignore next 3 */
1331
- if (!target) {
1332
- throw MetadataError.entityNotFound(name, path.replace(this.config.get('baseDir'), '.'));
1333
- }
1334
- return [target];
1335
- }
1336
1347
  shouldForceConstructorUsage(meta) {
1337
1348
  const forceConstructor = this.config.get('forceEntityConstructor');
1338
1349
  if (Array.isArray(forceConstructor)) {