@mikro-orm/core 7.0.0-dev.7 → 7.0.0-dev.71

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 (161) hide show
  1. package/EntityManager.d.ts +85 -42
  2. package/EntityManager.js +282 -194
  3. package/MikroORM.d.ts +11 -29
  4. package/MikroORM.js +33 -127
  5. package/README.md +3 -2
  6. package/cache/FileCacheAdapter.js +1 -2
  7. package/connections/Connection.d.ts +11 -7
  8. package/connections/Connection.js +16 -14
  9. package/drivers/DatabaseDriver.d.ts +11 -5
  10. package/drivers/DatabaseDriver.js +13 -4
  11. package/drivers/IDatabaseDriver.d.ts +27 -5
  12. package/entity/BaseEntity.d.ts +0 -1
  13. package/entity/BaseEntity.js +0 -3
  14. package/entity/Collection.d.ts +98 -30
  15. package/entity/Collection.js +432 -93
  16. package/entity/EntityAssigner.d.ts +1 -1
  17. package/entity/EntityAssigner.js +9 -1
  18. package/entity/EntityFactory.d.ts +7 -0
  19. package/entity/EntityFactory.js +63 -40
  20. package/entity/EntityHelper.js +26 -9
  21. package/entity/EntityLoader.d.ts +5 -4
  22. package/entity/EntityLoader.js +69 -36
  23. package/entity/EntityRepository.d.ts +1 -1
  24. package/entity/EntityValidator.js +4 -4
  25. package/entity/Reference.d.ts +9 -7
  26. package/entity/Reference.js +32 -5
  27. package/entity/WrappedEntity.d.ts +0 -2
  28. package/entity/WrappedEntity.js +1 -5
  29. package/entity/defineEntity.d.ts +549 -0
  30. package/entity/defineEntity.js +529 -0
  31. package/entity/index.d.ts +2 -1
  32. package/entity/index.js +2 -1
  33. package/entity/utils.d.ts +7 -0
  34. package/entity/utils.js +15 -3
  35. package/enums.d.ts +20 -5
  36. package/enums.js +13 -0
  37. package/errors.d.ts +6 -1
  38. package/errors.js +14 -4
  39. package/events/EventSubscriber.d.ts +3 -1
  40. package/hydration/ObjectHydrator.d.ts +4 -4
  41. package/hydration/ObjectHydrator.js +35 -24
  42. package/index.d.ts +2 -2
  43. package/index.js +1 -2
  44. package/logging/DefaultLogger.d.ts +1 -1
  45. package/logging/SimpleLogger.d.ts +1 -1
  46. package/metadata/EntitySchema.d.ts +9 -13
  47. package/metadata/EntitySchema.js +44 -26
  48. package/metadata/MetadataDiscovery.d.ts +6 -7
  49. package/metadata/MetadataDiscovery.js +161 -162
  50. package/metadata/MetadataProvider.d.ts +2 -2
  51. package/metadata/MetadataProvider.js +15 -0
  52. package/metadata/MetadataStorage.d.ts +0 -4
  53. package/metadata/MetadataStorage.js +6 -10
  54. package/metadata/MetadataValidator.d.ts +0 -7
  55. package/metadata/MetadataValidator.js +4 -13
  56. package/metadata/discover-entities.d.ts +5 -0
  57. package/metadata/discover-entities.js +39 -0
  58. package/metadata/index.d.ts +1 -1
  59. package/metadata/index.js +1 -1
  60. package/metadata/types.d.ts +480 -0
  61. package/metadata/types.js +1 -0
  62. package/naming-strategy/AbstractNamingStrategy.d.ts +5 -1
  63. package/naming-strategy/AbstractNamingStrategy.js +7 -1
  64. package/naming-strategy/NamingStrategy.d.ts +11 -1
  65. package/package.json +11 -10
  66. package/platforms/Platform.d.ts +6 -10
  67. package/platforms/Platform.js +6 -22
  68. package/serialization/EntitySerializer.d.ts +2 -0
  69. package/serialization/EntitySerializer.js +29 -11
  70. package/serialization/EntityTransformer.js +22 -12
  71. package/serialization/SerializationContext.js +14 -11
  72. package/types/ArrayType.d.ts +1 -1
  73. package/types/ArrayType.js +1 -2
  74. package/types/BigIntType.d.ts +8 -6
  75. package/types/BlobType.d.ts +0 -1
  76. package/types/BlobType.js +0 -3
  77. package/types/BooleanType.d.ts +2 -1
  78. package/types/BooleanType.js +3 -0
  79. package/types/DecimalType.d.ts +6 -4
  80. package/types/DecimalType.js +1 -1
  81. package/types/DoubleType.js +1 -1
  82. package/types/JsonType.d.ts +1 -1
  83. package/types/JsonType.js +7 -2
  84. package/types/Type.d.ts +2 -1
  85. package/types/Type.js +1 -1
  86. package/types/Uint8ArrayType.d.ts +0 -1
  87. package/types/Uint8ArrayType.js +0 -3
  88. package/types/index.d.ts +1 -1
  89. package/typings.d.ts +112 -77
  90. package/typings.js +32 -32
  91. package/unit-of-work/ChangeSetComputer.js +8 -3
  92. package/unit-of-work/ChangeSetPersister.d.ts +4 -2
  93. package/unit-of-work/ChangeSetPersister.js +37 -16
  94. package/unit-of-work/UnitOfWork.d.ts +8 -1
  95. package/unit-of-work/UnitOfWork.js +111 -54
  96. package/utils/AbstractSchemaGenerator.d.ts +5 -5
  97. package/utils/AbstractSchemaGenerator.js +10 -8
  98. package/utils/Configuration.d.ts +200 -191
  99. package/utils/Configuration.js +141 -152
  100. package/utils/ConfigurationLoader.d.ts +3 -44
  101. package/utils/ConfigurationLoader.js +26 -239
  102. package/utils/Cursor.d.ts +3 -3
  103. package/utils/Cursor.js +3 -0
  104. package/utils/DataloaderUtils.d.ts +15 -5
  105. package/utils/DataloaderUtils.js +53 -7
  106. package/utils/EntityComparator.d.ts +8 -4
  107. package/utils/EntityComparator.js +107 -60
  108. package/utils/QueryHelper.d.ts +9 -1
  109. package/utils/QueryHelper.js +69 -8
  110. package/utils/RawQueryFragment.d.ts +36 -4
  111. package/utils/RawQueryFragment.js +34 -13
  112. package/utils/TransactionManager.d.ts +65 -0
  113. package/utils/TransactionManager.js +223 -0
  114. package/utils/Utils.d.ts +17 -84
  115. package/utils/Utils.js +132 -252
  116. package/utils/index.d.ts +1 -0
  117. package/utils/index.js +1 -0
  118. package/utils/upsert-utils.d.ts +7 -2
  119. package/utils/upsert-utils.js +52 -1
  120. package/decorators/Check.d.ts +0 -3
  121. package/decorators/Check.js +0 -13
  122. package/decorators/CreateRequestContext.d.ts +0 -3
  123. package/decorators/CreateRequestContext.js +0 -32
  124. package/decorators/Embeddable.d.ts +0 -8
  125. package/decorators/Embeddable.js +0 -11
  126. package/decorators/Embedded.d.ts +0 -18
  127. package/decorators/Embedded.js +0 -18
  128. package/decorators/Entity.d.ts +0 -18
  129. package/decorators/Entity.js +0 -12
  130. package/decorators/Enum.d.ts +0 -9
  131. package/decorators/Enum.js +0 -16
  132. package/decorators/Filter.d.ts +0 -2
  133. package/decorators/Filter.js +0 -8
  134. package/decorators/Formula.d.ts +0 -4
  135. package/decorators/Formula.js +0 -15
  136. package/decorators/Indexed.d.ts +0 -19
  137. package/decorators/Indexed.js +0 -20
  138. package/decorators/ManyToMany.d.ts +0 -40
  139. package/decorators/ManyToMany.js +0 -14
  140. package/decorators/ManyToOne.d.ts +0 -30
  141. package/decorators/ManyToOne.js +0 -14
  142. package/decorators/OneToMany.d.ts +0 -28
  143. package/decorators/OneToMany.js +0 -17
  144. package/decorators/OneToOne.d.ts +0 -24
  145. package/decorators/OneToOne.js +0 -7
  146. package/decorators/PrimaryKey.d.ts +0 -8
  147. package/decorators/PrimaryKey.js +0 -20
  148. package/decorators/Property.d.ts +0 -250
  149. package/decorators/Property.js +0 -32
  150. package/decorators/Transactional.d.ts +0 -13
  151. package/decorators/Transactional.js +0 -28
  152. package/decorators/hooks.d.ts +0 -16
  153. package/decorators/hooks.js +0 -47
  154. package/decorators/index.d.ts +0 -17
  155. package/decorators/index.js +0 -17
  156. package/entity/ArrayCollection.d.ts +0 -116
  157. package/entity/ArrayCollection.js +0 -402
  158. package/metadata/ReflectMetadataProvider.d.ts +0 -8
  159. package/metadata/ReflectMetadataProvider.js +0 -44
  160. package/utils/resolveContextProvider.d.ts +0 -10
  161. package/utils/resolveContextProvider.js +0 -28
@@ -1,5 +1,4 @@
1
- import { basename, extname } from 'node:path';
2
- import globby from 'globby';
1
+ import { extname } from 'node:path';
3
2
  import { EntityMetadata, } from '../typings.js';
4
3
  import { Utils } from '../utils/Utils.js';
5
4
  import { MetadataValidator } from './MetadataValidator.js';
@@ -7,7 +6,7 @@ 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, 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
11
  import { raw, RawQueryFragment } from '../utils/RawQueryFragment.js';
13
12
  export class MetadataDiscovery {
@@ -32,6 +31,7 @@ export class MetadataDiscovery {
32
31
  this.schemaHelper = this.platform.getSchemaHelper();
33
32
  }
34
33
  async discover(preferTs = true) {
34
+ this.discovered.length = 0;
35
35
  const startTime = Date.now();
36
36
  this.logger.log('discovery', `ORM entity discovery started, using ${colors.cyan(this.metadataProvider.constructor.name)}`);
37
37
  await this.findEntities(preferTs);
@@ -47,10 +47,12 @@ 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
53
  this.logger.log('discovery', `ORM entity discovery started, using ${colors.cyan(this.metadataProvider.constructor.name)} in sync mode`);
53
- this.findEntities(preferTs, true);
54
+ const refs = this.config.get('entities');
55
+ this.discoverReferences(refs);
54
56
  for (const meta of this.discovered) {
55
57
  /* v8 ignore next */
56
58
  void this.config.get('discovery').onMetadata?.(meta, this.platform);
@@ -63,6 +65,9 @@ export class MetadataDiscovery {
63
65
  void this.config.get('discovery').afterDiscovered?.(storage, this.platform);
64
66
  return storage;
65
67
  }
68
+ validateDiscovered(metadata) {
69
+ return this.validator.validateDiscovered(metadata, this.config.get('discovery'));
70
+ }
66
71
  mapDiscoveredEntities() {
67
72
  const discovered = new MetadataStorage();
68
73
  this.discovered
@@ -74,11 +79,41 @@ export class MetadataDiscovery {
74
79
  });
75
80
  return discovered;
76
81
  }
82
+ initAccessors(meta) {
83
+ for (const prop of Object.values(meta.properties)) {
84
+ if (!prop.accessor || meta.properties[prop.accessor]) {
85
+ continue;
86
+ }
87
+ const desc = Object.getOwnPropertyDescriptor(meta.prototype, prop.name);
88
+ if (desc?.get || desc?.set) {
89
+ this.initFieldName(prop);
90
+ const accessor = prop.name;
91
+ prop.name = typeof prop.accessor === 'string' ? prop.accessor : prop.name;
92
+ if (prop.accessor === true) {
93
+ prop.getter = prop.setter = true;
94
+ }
95
+ else {
96
+ prop.getter = prop.setter = false;
97
+ }
98
+ prop.accessor = accessor;
99
+ prop.serializedName ??= accessor;
100
+ Utils.renameKey(meta.properties, accessor, prop.name);
101
+ }
102
+ else {
103
+ const name = prop.name;
104
+ prop.name = prop.accessor;
105
+ this.initFieldName(prop);
106
+ prop.serializedName ??= prop.accessor;
107
+ prop.name = name;
108
+ }
109
+ }
110
+ }
77
111
  processDiscoveredEntities(discovered) {
78
112
  for (const meta of discovered) {
79
113
  let i = 1;
80
114
  Object.values(meta.properties).forEach(prop => meta.propertyOrder.set(prop.name, i++));
81
115
  Object.values(meta.properties).forEach(prop => this.initPolyEmbeddables(prop, discovered));
116
+ this.initAccessors(meta);
82
117
  }
83
118
  // ignore base entities (not annotated with @Entity)
84
119
  const filtered = discovered.filter(meta => meta.root.name);
@@ -101,10 +136,6 @@ export class MetadataDiscovery {
101
136
  this.initDefaultValue(prop);
102
137
  this.inferTypeFromDefault(prop);
103
138
  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
139
  }
109
140
  }
110
141
  filtered.forEach(meta => Object.values(meta.properties).forEach(prop => this.initIndexes(meta, prop)));
@@ -125,27 +156,20 @@ export class MetadataDiscovery {
125
156
  return meta;
126
157
  });
127
158
  }
128
- findEntities(preferTs, sync = false) {
129
- this.discovered.length = 0;
130
- const options = this.config.get('discovery');
131
- const key = (preferTs && this.config.get('preferTs', Utils.detectTypeScriptSupport()) && this.config.get('entitiesTs').length > 0) ? 'entitiesTs' : 'entities';
132
- const paths = this.config.get(key).filter(item => Utils.isString(item));
133
- const refs = this.config.get(key).filter(item => !Utils.isString(item));
134
- if (paths.length > 0) {
135
- if (sync || options.requireEntitiesArray) {
136
- throw new Error(`[requireEntitiesArray] Explicit list of entities is required, please use the 'entities' option.`);
159
+ async findEntities(preferTs) {
160
+ const { entities, entitiesTs, baseDir } = this.config.getAll();
161
+ const targets = (preferTs && entitiesTs.length > 0) ? entitiesTs : entities;
162
+ const processed = [];
163
+ for (const entity of targets) {
164
+ if (typeof entity === 'string') {
165
+ const { discoverEntities } = await import('@mikro-orm/core/file-discovery' + '');
166
+ processed.push(...await discoverEntities(entity, { baseDir }));
167
+ }
168
+ else {
169
+ processed.push(entity);
137
170
  }
138
- return this.discoverDirectories(paths).then(() => {
139
- this.discoverReferences(refs);
140
- this.discoverMissingTargets();
141
- this.validator.validateDiscovered(this.discovered, options);
142
- return this.discovered;
143
- });
144
171
  }
145
- this.discoverReferences(refs);
146
- this.discoverMissingTargets();
147
- this.validator.validateDiscovered(this.discovered, options);
148
- return this.discovered;
172
+ return this.discoverReferences(processed);
149
173
  }
150
174
  discoverMissingTargets() {
151
175
  const unwrap = (type) => type
@@ -173,50 +197,20 @@ export class MetadataDiscovery {
173
197
  }
174
198
  tryDiscoverTargets(targets) {
175
199
  for (const target of targets) {
176
- if (typeof target === 'function' && target.name && !this.metadata.has(target.name)) {
177
- this.discoverReferences([target]);
200
+ const isDiscoverable = typeof target === 'function' || target instanceof EntitySchema;
201
+ if (isDiscoverable && target.name && !this.metadata.has(target.name)) {
202
+ this.discoverReferences([target], false);
178
203
  this.discoverMissingTargets();
179
204
  }
180
205
  }
181
206
  }
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) {
207
+ discoverReferences(refs, validate = true) {
217
208
  const found = [];
218
209
  for (const entity of refs) {
219
- const schema = this.getSchema(this.prepare(entity));
210
+ if (typeof entity === 'string') {
211
+ throw new Error('Folder based discovery requires the async `MikroORM.init()` method.');
212
+ }
213
+ const schema = this.getSchema(entity);
220
214
  const meta = schema.init().meta;
221
215
  this.metadata.set(meta.className, meta);
222
216
  found.push(schema);
@@ -225,7 +219,10 @@ export class MetadataDiscovery {
225
219
  for (const meta of this.metadata) {
226
220
  let parent = meta.extends;
227
221
  if (parent instanceof EntitySchema && !this.metadata.has(parent.meta.className)) {
228
- this.discoverReferences([parent]);
222
+ this.discoverReferences([parent], false);
223
+ }
224
+ if (typeof parent === 'function' && parent.name && !this.metadata.has(parent.name)) {
225
+ this.discoverReferences([parent], false);
229
226
  }
230
227
  /* v8 ignore next 3 */
231
228
  if (!meta.class) {
@@ -233,12 +230,16 @@ export class MetadataDiscovery {
233
230
  }
234
231
  parent = Object.getPrototypeOf(meta.class);
235
232
  if (parent.name !== '' && !this.metadata.has(parent.name)) {
236
- this.discoverReferences([parent]);
233
+ this.discoverReferences([parent], false);
237
234
  }
238
235
  }
239
236
  for (const schema of found) {
240
237
  this.discoverEntity(schema);
241
238
  }
239
+ this.discoverMissingTargets();
240
+ if (validate) {
241
+ this.validateDiscovered(this.discovered);
242
+ }
242
243
  return this.discovered.filter(meta => found.find(m => m.name === meta.className));
243
244
  }
244
245
  reset(className) {
@@ -248,23 +249,13 @@ export class MetadataDiscovery {
248
249
  this.discovered.splice(exists, 1);
249
250
  }
250
251
  }
251
- prepare(entity) {
252
- /* v8 ignore next 3 */
253
- if ('schema' in entity && entity.schema instanceof EntitySchema) {
254
- return entity.schema;
255
- }
252
+ getSchema(entity) {
256
253
  if (EntitySchema.REGISTRY.has(entity)) {
257
- return EntitySchema.REGISTRY.get(entity);
254
+ entity = EntitySchema.REGISTRY.get(entity);
258
255
  }
259
- return entity;
260
- }
261
- getSchema(entity, filepath) {
262
256
  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;
257
+ const meta = Utils.copy(entity.meta, false);
258
+ return EntitySchema.fromMetadata(meta);
268
259
  }
269
260
  const path = entity[MetadataStorage.PATH_SYMBOL];
270
261
  if (path) {
@@ -279,11 +270,23 @@ export class MetadataDiscovery {
279
270
  schema.setClass(entity);
280
271
  return schema;
281
272
  }
282
- discoverEntity(schema, path) {
283
- this.logger.log('discovery', `- processing entity ${colors.cyan(schema.meta.className)}${colors.grey(path ? ` (${path})` : '')}`);
273
+ getRootEntity(meta) {
274
+ const base = meta.extends && this.metadata.find(Utils.className(meta.extends));
275
+ if (!base || base === meta) { // make sure we do not fall into infinite loop
276
+ return meta;
277
+ }
278
+ const root = this.getRootEntity(base);
279
+ if (root.discriminatorColumn) {
280
+ return root;
281
+ }
282
+ return meta;
283
+ }
284
+ discoverEntity(schema) {
284
285
  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'));
286
+ const path = meta.path;
287
+ this.logger.log('discovery', `- processing entity ${colors.cyan(meta.className)}${colors.grey(path ? ` (${path})` : '')}`);
288
+ const root = this.getRootEntity(meta);
289
+ schema.meta.path = Utils.relativePath(meta.path, this.config.get('baseDir'));
287
290
  const cache = this.metadataProvider.useCache() && meta.path && this.cache.get(meta.className + extname(meta.path));
288
291
  if (cache) {
289
292
  this.logger.log('discovery', `- using cached metadata for entity ${colors.cyan(meta.className)}`);
@@ -297,7 +300,7 @@ export class MetadataDiscovery {
297
300
  this.inferDefaultValue(meta, prop);
298
301
  }
299
302
  // 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);
303
+ this.metadataProvider.loadEntityMetadata(meta);
301
304
  if (!meta.collection && meta.name) {
302
305
  const entityName = root.discriminatorColumn ? root.name : meta.name;
303
306
  meta.collection = this.namingStrategy.classToTableName(entityName);
@@ -336,11 +339,8 @@ export class MetadataDiscovery {
336
339
  }
337
340
  }
338
341
  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
342
  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));
343
+ return Utils.defaultValue(prop, 'nullable', prop.optional || !prop.owner);
344
344
  }
345
345
  return Utils.defaultValue(prop, 'nullable', prop.optional);
346
346
  }
@@ -497,10 +497,9 @@ export class MetadataDiscovery {
497
497
  }
498
498
  this.initOwnColumns(meta);
499
499
  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;
500
+ meta.serializedPrimaryKey ??= meta.props.find(prop => prop.serializedPrimaryKey)?.name;
501
+ if (meta.serializedPrimaryKey && meta.serializedPrimaryKey !== meta.primaryKeys[0]) {
502
+ meta.properties[meta.serializedPrimaryKey].persist ??= false;
504
503
  }
505
504
  if (this.platform.usesPivotTable()) {
506
505
  return Object.values(meta.properties)
@@ -618,7 +617,7 @@ export class MetadataDiscovery {
618
617
  }
619
618
  data.properties[meta.name + '_owner'] = this.definePivotProperty(prop, meta.name + '_owner', meta.className, targetType + '_inverse', true, meta.className === targetType);
620
619
  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);
620
+ return this.metadata.set(data.className, EntitySchema.fromMetadata(data).init().meta);
622
621
  }
623
622
  defineFixedOrderProperty(prop, targetType) {
624
623
  const pk = prop.fixedOrderColumn || this.namingStrategy.referenceColumnName();
@@ -653,6 +652,7 @@ export class MetadataDiscovery {
653
652
  autoincrement: false,
654
653
  updateRule: prop.updateRule,
655
654
  deleteRule: prop.deleteRule,
655
+ createForeignKeyConstraint: prop.createForeignKeyConstraint,
656
656
  };
657
657
  if (selfReferencing && !this.platform.supportsMultipleCascadePaths()) {
658
658
  ret.updateRule ??= 'no action';
@@ -739,12 +739,9 @@ export class MetadataDiscovery {
739
739
  Utils.keys(base.hooks).forEach(type => {
740
740
  meta.hooks[type] = Utils.unique([...base.hooks[type], ...(meta.hooks[type] || [])]);
741
741
  });
742
- if (meta.constructorParams.length === 0 && base.constructorParams.length > 0) {
742
+ if ((meta.constructorParams?.length ?? 0) === 0 && (base.constructorParams?.length ?? 0) > 0) {
743
743
  meta.constructorParams = [...base.constructorParams];
744
744
  }
745
- if (meta.toJsonParams.length === 0 && base.toJsonParams.length > 0) {
746
- meta.toJsonParams = [...base.toJsonParams];
747
- }
748
745
  return order;
749
746
  }
750
747
  initPolyEmbeddables(embeddedProp, discovered, visited = new Set()) {
@@ -765,6 +762,7 @@ export class MetadataDiscovery {
765
762
  delete prop.default;
766
763
  if (properties[prop.name] && properties[prop.name].type !== prop.type) {
767
764
  properties[prop.name].type = `${properties[prop.name].type} | ${prop.type}`;
765
+ properties[prop.name].runtimeType = 'any';
768
766
  return properties[prop.name];
769
767
  }
770
768
  return properties[prop.name] = prop;
@@ -819,9 +817,16 @@ export class MetadataDiscovery {
819
817
  }
820
818
  return prop.embedded ? isParentObject(meta.properties[prop.embedded[0]]) : false;
821
819
  };
820
+ const isParentArray = (prop) => {
821
+ if (prop.array) {
822
+ return true;
823
+ }
824
+ return prop.embedded ? isParentArray(meta.properties[prop.embedded[0]]) : false;
825
+ };
822
826
  const rootProperty = getRootProperty(embeddedProp);
823
827
  const parentProperty = meta.properties[embeddedProp.embedded?.[0] ?? ''];
824
828
  const object = isParentObject(embeddedProp);
829
+ const array = isParentArray(embeddedProp);
825
830
  this.initFieldName(embeddedProp, rootProperty !== embeddedProp && object);
826
831
  // the prefix of the parent cannot be a boolean; it already passed here
827
832
  const prefix = this.getPrefix(embeddedProp, parentProperty);
@@ -834,7 +839,8 @@ export class MetadataDiscovery {
834
839
  meta.propertyOrder.set(name, (order += 0.01));
835
840
  embeddedProp.embeddedProps[prop.name] = meta.properties[name];
836
841
  meta.properties[name].persist ??= embeddedProp.persist;
837
- if (embeddedProp.nullable) {
842
+ const refInArray = array && [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) && prop.owner;
843
+ if (embeddedProp.nullable || refInArray) {
838
844
  meta.properties[name].nullable = true;
839
845
  }
840
846
  if (meta.properties[name].fieldNames) {
@@ -872,6 +878,7 @@ export class MetadataDiscovery {
872
878
  meta.properties[name].persist = false; // only virtual as we store the whole object
873
879
  meta.properties[name].userDefined = false; // mark this as a generated/internal property, so we can distinguish from user-defined non-persist properties
874
880
  meta.properties[name].object = true;
881
+ this.initCustomType(meta, meta.properties[name], false, true);
875
882
  }
876
883
  this.initEmbeddables(meta, meta.properties[name], visited);
877
884
  }
@@ -924,7 +931,7 @@ export class MetadataDiscovery {
924
931
  }
925
932
  let i = 1;
926
933
  Object.values(meta.properties).forEach(prop => {
927
- const newProp = Utils.copy(prop, false);
934
+ const newProp = { ...prop };
928
935
  if (meta.root.properties[prop.name] && meta.root.properties[prop.name].type !== prop.type) {
929
936
  const name = newProp.name;
930
937
  this.initFieldName(newProp, newProp.object);
@@ -940,7 +947,7 @@ export class MetadataDiscovery {
940
947
  newProp.items = Utils.unique([...meta.root.properties[prop.name].items, ...prop.items]);
941
948
  }
942
949
  newProp.nullable = true;
943
- newProp.inherited = true;
950
+ newProp.inherited = !meta.root.properties[prop.name];
944
951
  meta.root.addProperty(newProp);
945
952
  });
946
953
  meta.collection = meta.root.collection;
@@ -965,7 +972,7 @@ export class MetadataDiscovery {
965
972
  }
966
973
  }
967
974
  initCheckConstraints(meta) {
968
- const map = this.createColumnMappingObject(meta);
975
+ const map = meta.createColumnMappingObject();
969
976
  for (const check of meta.checks) {
970
977
  const columns = check.property ? meta.properties[check.property].fieldNames : [];
971
978
  check.name ??= this.namingStrategy.indexName(meta.tableName, columns, 'check');
@@ -975,7 +982,7 @@ export class MetadataDiscovery {
975
982
  }
976
983
  if (this.platform.usesEnumCheckConstraints() && !meta.embeddable) {
977
984
  for (const prop of meta.props) {
978
- 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')) {
979
986
  this.initFieldName(prop);
980
987
  meta.checks.push({
981
988
  name: this.namingStrategy.indexName(meta.tableName, prop.fieldNames, 'check'),
@@ -1000,20 +1007,12 @@ export class MetadataDiscovery {
1000
1007
  }
1001
1008
  return;
1002
1009
  }
1003
- const map = this.createColumnMappingObject(meta);
1010
+ const map = meta.createColumnMappingObject();
1004
1011
  if (prop.generated instanceof Function) {
1005
1012
  prop.generated = prop.generated(map);
1006
1013
  }
1007
1014
  }
1008
- createColumnMappingObject(meta) {
1009
- return Object.values(meta.properties).reduce((o, prop) => {
1010
- if (prop.fieldNames) {
1011
- o[prop.name] = prop.fieldNames[0];
1012
- }
1013
- return o;
1014
- }, {});
1015
- }
1016
- getDefaultVersionValue(prop) {
1015
+ getDefaultVersionValue(meta, prop) {
1017
1016
  if (typeof prop.defaultRaw !== 'undefined') {
1018
1017
  return prop.defaultRaw;
1019
1018
  }
@@ -1021,14 +1020,15 @@ export class MetadataDiscovery {
1021
1020
  if (prop.default != null) {
1022
1021
  return '' + this.platform.quoteVersionValue(prop.default, prop);
1023
1022
  }
1024
- 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') {
1025
1026
  prop.length ??= this.platform.getDefaultVersionLength();
1026
1027
  return this.platform.getCurrentTimestampSQL(prop.length);
1027
1028
  }
1028
1029
  return '1';
1029
1030
  }
1030
1031
  inferDefaultValue(meta, prop) {
1031
- /* v8 ignore next 3 */
1032
1032
  if (!meta.class) {
1033
1033
  return;
1034
1034
  }
@@ -1064,7 +1064,7 @@ export class MetadataDiscovery {
1064
1064
  prop.defaultRaw = this.platform.formatQuery(raw.sql, raw.params);
1065
1065
  return;
1066
1066
  }
1067
- if (prop.customType instanceof ArrayType && Array.isArray(prop.default)) {
1067
+ if (Array.isArray(prop.default) && prop.customType) {
1068
1068
  val = prop.customType.convertToDatabaseValue(prop.default, this.platform);
1069
1069
  }
1070
1070
  prop.defaultRaw = typeof val === 'string' ? `'${val}'` : '' + val;
@@ -1092,13 +1092,13 @@ export class MetadataDiscovery {
1092
1092
  if (prop.version) {
1093
1093
  this.initDefaultValue(prop);
1094
1094
  meta.versionProperty = prop.name;
1095
- prop.defaultRaw = this.getDefaultVersionValue(prop);
1095
+ prop.defaultRaw = this.getDefaultVersionValue(meta, prop);
1096
1096
  }
1097
1097
  if (prop.concurrencyCheck && !prop.primary) {
1098
1098
  meta.concurrencyCheckKeys.add(prop.name);
1099
1099
  }
1100
1100
  }
1101
- initCustomType(meta, prop) {
1101
+ initCustomType(meta, prop, simple = false, objectEmbeddable = false) {
1102
1102
  // `prop.type` might be actually instance of custom type class
1103
1103
  if (Type.isMappedType(prop.type) && !prop.customType) {
1104
1104
  prop.customType = prop.type;
@@ -1106,47 +1106,70 @@ export class MetadataDiscovery {
1106
1106
  }
1107
1107
  // `prop.type` might also be custom type class (not instance), so `typeof MyType` will give us `function`, not `object`
1108
1108
  if (typeof prop.type === 'function' && Type.isMappedType(prop.type.prototype) && !prop.customType) {
1109
- prop.customType = new prop.type();
1110
- prop.type = prop.customType.constructor.name;
1109
+ // if the type is an ORM defined mapped type without `ensureComparable: true`,
1110
+ // we use just the type name, to have more performant hydration code
1111
+ const type = Utils.keys(t).find(type => {
1112
+ return !Type.getType(t[type]).ensureComparable(meta, prop) && prop.type === t[type];
1113
+ });
1114
+ if (type) {
1115
+ prop.type = type === 'datetime' ? 'Date' : type;
1116
+ }
1117
+ else {
1118
+ prop.customType = new prop.type();
1119
+ prop.type = prop.customType.constructor.name;
1120
+ }
1121
+ }
1122
+ if (simple) {
1123
+ return;
1111
1124
  }
1112
1125
  if (!prop.customType && ['json', 'jsonb'].includes(prop.type?.toLowerCase())) {
1113
- prop.customType = new JsonType();
1126
+ prop.customType = new t.json();
1114
1127
  }
1115
1128
  if (prop.kind === ReferenceKind.SCALAR && !prop.customType && prop.columnTypes && ['json', 'jsonb'].includes(prop.columnTypes[0])) {
1116
- prop.customType = new JsonType();
1129
+ prop.customType = new t.json();
1130
+ }
1131
+ if (prop.kind === ReferenceKind.EMBEDDED && !prop.customType && (prop.object || prop.array)) {
1132
+ prop.customType = new t.json();
1117
1133
  }
1118
1134
  if (!prop.customType && prop.array && prop.items) {
1119
- prop.customType = new EnumArrayType(`${meta.className}.${prop.name}`, prop.items);
1135
+ prop.customType = new t.enumArray(`${meta.className}.${prop.name}`, prop.items);
1136
+ }
1137
+ const isArray = prop.type?.toLowerCase() === 'array' || prop.type?.toString().endsWith('[]');
1138
+ if (objectEmbeddable && !prop.customType && isArray) {
1139
+ prop.customType = new t.json();
1120
1140
  }
1121
1141
  // for number arrays we make sure to convert the items to numbers
1122
1142
  if (!prop.customType && prop.type === 'number[]') {
1123
- prop.customType = new ArrayType(i => +i);
1143
+ prop.customType = new t.array(i => +i);
1124
1144
  }
1125
1145
  // `string[]` can be returned via ts-morph, while reflect metadata will give us just `array`
1126
- if (!prop.customType && (prop.type?.toLowerCase() === 'array' || prop.type?.toString().endsWith('[]'))) {
1127
- prop.customType = new ArrayType();
1146
+ if (!prop.customType && isArray) {
1147
+ prop.customType = new t.array();
1128
1148
  }
1129
1149
  if (!prop.customType && prop.type?.toLowerCase() === 'buffer') {
1130
- prop.customType = new BlobType();
1150
+ prop.customType = new t.blob();
1131
1151
  }
1132
1152
  if (!prop.customType && prop.type?.toLowerCase() === 'uint8array') {
1133
- prop.customType = new Uint8ArrayType();
1153
+ prop.customType = new t.uint8array();
1134
1154
  }
1135
1155
  const mappedType = this.getMappedType(prop);
1136
1156
  if (prop.fieldNames?.length === 1 && !prop.customType) {
1137
- [BigIntType, DoubleType, DecimalType, IntervalType]
1157
+ [t.bigint, t.double, t.decimal, t.interval, t.date]
1138
1158
  .filter(type => mappedType instanceof type)
1139
- .forEach(type => prop.customType = new type());
1159
+ .forEach((type) => prop.customType = new type());
1140
1160
  }
1141
1161
  if (prop.customType && !prop.columnTypes) {
1142
1162
  const mappedType = this.getMappedType({ columnTypes: [prop.customType.getColumnType(prop, this.platform)] });
1143
- if (prop.customType.compareAsType() === 'any' && ![JsonType].some(t => prop.customType instanceof t)) {
1163
+ if (prop.customType.compareAsType() === 'any' && ![t.json].some(t => prop.customType instanceof t)) {
1144
1164
  prop.runtimeType ??= mappedType.runtimeType;
1145
1165
  }
1146
1166
  else {
1147
1167
  prop.runtimeType ??= prop.customType.runtimeType;
1148
1168
  }
1149
1169
  }
1170
+ else if (prop.runtimeType === 'object') {
1171
+ prop.runtimeType = mappedType.runtimeType;
1172
+ }
1150
1173
  else {
1151
1174
  prop.runtimeType ??= mappedType.runtimeType;
1152
1175
  }
@@ -1157,11 +1180,11 @@ export class MetadataDiscovery {
1157
1180
  prop.columnTypes ??= [prop.customType.getColumnType(prop, this.platform)];
1158
1181
  prop.hasConvertToJSValueSQL = !!prop.customType.convertToJSValueSQL && prop.customType.convertToJSValueSQL('', this.platform) !== '';
1159
1182
  prop.hasConvertToDatabaseValueSQL = !!prop.customType.convertToDatabaseValueSQL && prop.customType.convertToDatabaseValueSQL('', this.platform) !== '';
1160
- if (prop.customType instanceof BigIntType && ['string', 'bigint', 'number'].includes(prop.runtimeType.toLowerCase())) {
1183
+ if (prop.customType instanceof t.bigint && ['string', 'bigint', 'number'].includes(prop.runtimeType.toLowerCase())) {
1161
1184
  prop.customType.mode = prop.runtimeType.toLowerCase();
1162
1185
  }
1163
1186
  }
1164
- if (Type.isMappedType(prop.customType) && prop.kind === ReferenceKind.SCALAR && !prop.type?.toString().endsWith('[]')) {
1187
+ if (Type.isMappedType(prop.customType) && prop.kind === ReferenceKind.SCALAR && !isArray) {
1165
1188
  prop.type = prop.customType.name;
1166
1189
  }
1167
1190
  if (!prop.customType && [ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(prop.kind) && this.metadata.get(prop.type).compositePK) {
@@ -1178,7 +1201,7 @@ export class MetadataDiscovery {
1178
1201
  }
1179
1202
  }
1180
1203
  }
1181
- if (prop.kind === ReferenceKind.SCALAR && !(mappedType instanceof UnknownType)) {
1204
+ if (prop.kind === ReferenceKind.SCALAR && !(mappedType instanceof t.unknown)) {
1182
1205
  if (!prop.columnTypes && prop.nativeEnumName && meta.schema !== this.platform.getDefaultSchemaName() && meta.schema && !prop.nativeEnumName.includes('.')) {
1183
1206
  prop.columnTypes = [`${meta.schema}.${prop.nativeEnumName}`];
1184
1207
  }
@@ -1221,7 +1244,7 @@ export class MetadataDiscovery {
1221
1244
  if (prop.kind === ReferenceKind.SCALAR) {
1222
1245
  const mappedType = this.getMappedType(prop);
1223
1246
  const SCALAR_TYPES = ['string', 'number', 'boolean', 'bigint', 'Date', 'Buffer', 'RegExp', 'any', 'unknown'];
1224
- if (mappedType instanceof UnknownType
1247
+ if (mappedType instanceof t.unknown
1225
1248
  && !prop.columnTypes
1226
1249
  // it could be a runtime type from reflect-metadata
1227
1250
  && !SCALAR_TYPES.includes(prop.type)
@@ -1265,7 +1288,7 @@ export class MetadataDiscovery {
1265
1288
  t = 'enum';
1266
1289
  }
1267
1290
  else if (prop.enum) {
1268
- t = prop.items?.every(item => Utils.isString(item)) ? 'enum' : 'tinyint';
1291
+ t = prop.items?.every(item => typeof item === 'string') ? 'enum' : 'tinyint';
1269
1292
  }
1270
1293
  if (t === 'Date') {
1271
1294
  t = 'datetime';
@@ -1304,30 +1327,6 @@ export class MetadataDiscovery {
1304
1327
  prop.index ??= true;
1305
1328
  }
1306
1329
  }
1307
- async getEntityClassOrSchema(path, name) {
1308
- const exports = await Utils.dynamicImport(path);
1309
- const targets = Object.values(exports)
1310
- .filter(item => item instanceof EntitySchema || (item instanceof Function && MetadataStorage.isKnownEntity(item.name)));
1311
- // ignore class implementations that are linked from an EntitySchema
1312
- for (const item of targets) {
1313
- if (item instanceof EntitySchema) {
1314
- targets.forEach((item2, idx) => {
1315
- if (item.meta.class === item2) {
1316
- targets.splice(idx, 1);
1317
- }
1318
- });
1319
- }
1320
- }
1321
- if (targets.length > 0) {
1322
- return targets;
1323
- }
1324
- const target = exports.default ?? exports[name];
1325
- /* v8 ignore next 3 */
1326
- if (!target) {
1327
- throw MetadataError.entityNotFound(name, path.replace(this.config.get('baseDir'), '.'));
1328
- }
1329
- return [target];
1330
- }
1331
1330
  shouldForceConstructorUsage(meta) {
1332
1331
  const forceConstructor = this.config.get('forceEntityConstructor');
1333
1332
  if (Array.isArray(forceConstructor)) {
@@ -4,10 +4,10 @@ export interface IConfiguration {
4
4
  get(key: string, defaultValue?: any): any;
5
5
  getLogger(): Logger;
6
6
  }
7
- export declare abstract class MetadataProvider {
7
+ export declare class MetadataProvider {
8
8
  protected readonly config: IConfiguration;
9
9
  constructor(config: IConfiguration);
10
- abstract loadEntityMetadata(meta: EntityMetadata, name: string): void;
10
+ loadEntityMetadata(meta: EntityMetadata): void;
11
11
  loadFromCache(meta: EntityMetadata, cache: EntityMetadata): void;
12
12
  useCache(): boolean;
13
13
  }