@mikro-orm/core 7.0.7 → 7.0.8-dev.1

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 (206) hide show
  1. package/EntityManager.d.ts +583 -884
  2. package/EntityManager.js +1899 -1926
  3. package/MikroORM.d.ts +74 -103
  4. package/MikroORM.js +179 -178
  5. package/README.md +1 -1
  6. package/cache/CacheAdapter.d.ts +36 -36
  7. package/cache/FileCacheAdapter.d.ts +24 -30
  8. package/cache/FileCacheAdapter.js +78 -80
  9. package/cache/GeneratedCacheAdapter.d.ts +20 -18
  10. package/cache/GeneratedCacheAdapter.js +30 -30
  11. package/cache/MemoryCacheAdapter.d.ts +20 -18
  12. package/cache/MemoryCacheAdapter.js +36 -35
  13. package/cache/NullCacheAdapter.d.ts +16 -16
  14. package/cache/NullCacheAdapter.js +24 -24
  15. package/connections/Connection.d.ts +84 -95
  16. package/connections/Connection.js +168 -165
  17. package/drivers/DatabaseDriver.d.ts +80 -186
  18. package/drivers/DatabaseDriver.js +443 -450
  19. package/drivers/IDatabaseDriver.d.ts +301 -440
  20. package/entity/BaseEntity.d.ts +83 -120
  21. package/entity/BaseEntity.js +43 -43
  22. package/entity/Collection.d.ts +180 -213
  23. package/entity/Collection.js +724 -730
  24. package/entity/EntityAssigner.d.ts +77 -88
  25. package/entity/EntityAssigner.js +230 -231
  26. package/entity/EntityFactory.d.ts +55 -67
  27. package/entity/EntityFactory.js +414 -455
  28. package/entity/EntityHelper.d.ts +23 -35
  29. package/entity/EntityHelper.js +277 -289
  30. package/entity/EntityIdentifier.d.ts +4 -4
  31. package/entity/EntityIdentifier.js +10 -10
  32. package/entity/EntityLoader.d.ts +72 -98
  33. package/entity/EntityLoader.js +730 -760
  34. package/entity/EntityRepository.d.ts +201 -316
  35. package/entity/EntityRepository.js +213 -213
  36. package/entity/PolymorphicRef.d.ts +5 -5
  37. package/entity/PolymorphicRef.js +10 -10
  38. package/entity/Reference.d.ts +83 -127
  39. package/entity/Reference.js +277 -281
  40. package/entity/WrappedEntity.d.ts +72 -115
  41. package/entity/WrappedEntity.js +166 -168
  42. package/entity/defineEntity.d.ts +658 -1347
  43. package/entity/defineEntity.js +518 -527
  44. package/entity/utils.d.ts +3 -13
  45. package/entity/utils.js +73 -71
  46. package/entity/validators.js +43 -43
  47. package/entity/wrap.js +8 -8
  48. package/enums.d.ts +253 -258
  49. package/enums.js +252 -251
  50. package/errors.d.ts +72 -114
  51. package/errors.js +253 -350
  52. package/events/EventManager.d.ts +14 -26
  53. package/events/EventManager.js +77 -79
  54. package/events/EventSubscriber.d.ts +29 -29
  55. package/events/TransactionEventBroadcaster.d.ts +8 -15
  56. package/events/TransactionEventBroadcaster.js +14 -14
  57. package/exceptions.d.ts +40 -23
  58. package/exceptions.js +52 -35
  59. package/hydration/Hydrator.d.ts +17 -42
  60. package/hydration/Hydrator.js +43 -43
  61. package/hydration/ObjectHydrator.d.ts +17 -50
  62. package/hydration/ObjectHydrator.js +418 -483
  63. package/index.d.ts +2 -116
  64. package/index.js +1 -10
  65. package/logging/DefaultLogger.d.ts +32 -34
  66. package/logging/DefaultLogger.js +86 -86
  67. package/logging/Logger.d.ts +41 -41
  68. package/logging/SimpleLogger.d.ts +11 -13
  69. package/logging/SimpleLogger.js +22 -22
  70. package/logging/colors.d.ts +6 -6
  71. package/logging/colors.js +10 -11
  72. package/logging/inspect.js +7 -7
  73. package/metadata/EntitySchema.d.ts +130 -214
  74. package/metadata/EntitySchema.js +412 -411
  75. package/metadata/MetadataDiscovery.d.ts +114 -114
  76. package/metadata/MetadataDiscovery.js +1868 -1944
  77. package/metadata/MetadataProvider.d.ts +26 -29
  78. package/metadata/MetadataProvider.js +97 -95
  79. package/metadata/MetadataStorage.d.ts +32 -38
  80. package/metadata/MetadataStorage.js +118 -118
  81. package/metadata/MetadataValidator.d.ts +39 -39
  82. package/metadata/MetadataValidator.js +338 -381
  83. package/metadata/discover-entities.d.ts +2 -5
  84. package/metadata/discover-entities.js +37 -35
  85. package/metadata/types.d.ts +531 -615
  86. package/naming-strategy/AbstractNamingStrategy.d.ts +39 -54
  87. package/naming-strategy/AbstractNamingStrategy.js +85 -90
  88. package/naming-strategy/EntityCaseNamingStrategy.d.ts +6 -6
  89. package/naming-strategy/EntityCaseNamingStrategy.js +22 -22
  90. package/naming-strategy/MongoNamingStrategy.d.ts +6 -6
  91. package/naming-strategy/MongoNamingStrategy.js +18 -18
  92. package/naming-strategy/NamingStrategy.d.ts +99 -109
  93. package/naming-strategy/UnderscoreNamingStrategy.d.ts +7 -7
  94. package/naming-strategy/UnderscoreNamingStrategy.js +21 -21
  95. package/not-supported.js +4 -7
  96. package/package.json +1 -1
  97. package/platforms/ExceptionConverter.d.ts +1 -1
  98. package/platforms/ExceptionConverter.js +4 -4
  99. package/platforms/Platform.d.ts +303 -312
  100. package/platforms/Platform.js +644 -667
  101. package/serialization/EntitySerializer.d.ts +26 -49
  102. package/serialization/EntitySerializer.js +218 -224
  103. package/serialization/EntityTransformer.d.ts +6 -10
  104. package/serialization/EntityTransformer.js +217 -219
  105. package/serialization/SerializationContext.d.ts +23 -27
  106. package/serialization/SerializationContext.js +105 -105
  107. package/types/ArrayType.d.ts +8 -8
  108. package/types/ArrayType.js +33 -33
  109. package/types/BigIntType.d.ts +10 -17
  110. package/types/BigIntType.js +37 -37
  111. package/types/BlobType.d.ts +3 -3
  112. package/types/BlobType.js +13 -13
  113. package/types/BooleanType.d.ts +4 -4
  114. package/types/BooleanType.js +12 -12
  115. package/types/CharacterType.d.ts +2 -2
  116. package/types/CharacterType.js +6 -6
  117. package/types/DateTimeType.d.ts +5 -5
  118. package/types/DateTimeType.js +15 -15
  119. package/types/DateType.d.ts +5 -5
  120. package/types/DateType.js +15 -15
  121. package/types/DecimalType.d.ts +7 -7
  122. package/types/DecimalType.js +26 -26
  123. package/types/DoubleType.d.ts +3 -3
  124. package/types/DoubleType.js +12 -12
  125. package/types/EnumArrayType.d.ts +5 -5
  126. package/types/EnumArrayType.js +24 -24
  127. package/types/EnumType.d.ts +3 -3
  128. package/types/EnumType.js +11 -11
  129. package/types/FloatType.d.ts +3 -3
  130. package/types/FloatType.js +9 -9
  131. package/types/IntegerType.d.ts +3 -3
  132. package/types/IntegerType.js +9 -9
  133. package/types/IntervalType.d.ts +4 -4
  134. package/types/IntervalType.js +12 -12
  135. package/types/JsonType.d.ts +8 -8
  136. package/types/JsonType.js +32 -32
  137. package/types/MediumIntType.d.ts +1 -1
  138. package/types/MediumIntType.js +3 -3
  139. package/types/SmallIntType.d.ts +3 -3
  140. package/types/SmallIntType.js +9 -9
  141. package/types/StringType.d.ts +4 -4
  142. package/types/StringType.js +12 -12
  143. package/types/TextType.d.ts +3 -3
  144. package/types/TextType.js +9 -9
  145. package/types/TimeType.d.ts +5 -5
  146. package/types/TimeType.js +17 -17
  147. package/types/TinyIntType.d.ts +3 -3
  148. package/types/TinyIntType.js +10 -10
  149. package/types/Type.d.ts +79 -83
  150. package/types/Type.js +82 -82
  151. package/types/Uint8ArrayType.d.ts +4 -4
  152. package/types/Uint8ArrayType.js +21 -21
  153. package/types/UnknownType.d.ts +4 -4
  154. package/types/UnknownType.js +12 -12
  155. package/types/UuidType.d.ts +5 -5
  156. package/types/UuidType.js +19 -19
  157. package/types/index.d.ts +49 -75
  158. package/types/index.js +26 -52
  159. package/typings.d.ts +741 -1254
  160. package/typings.js +233 -244
  161. package/unit-of-work/ChangeSet.d.ts +26 -26
  162. package/unit-of-work/ChangeSet.js +56 -56
  163. package/unit-of-work/ChangeSetComputer.d.ts +12 -12
  164. package/unit-of-work/ChangeSetComputer.js +179 -187
  165. package/unit-of-work/ChangeSetPersister.d.ts +44 -63
  166. package/unit-of-work/ChangeSetPersister.js +423 -446
  167. package/unit-of-work/CommitOrderCalculator.d.ts +40 -40
  168. package/unit-of-work/CommitOrderCalculator.js +88 -89
  169. package/unit-of-work/IdentityMap.d.ts +31 -31
  170. package/unit-of-work/IdentityMap.js +105 -105
  171. package/unit-of-work/UnitOfWork.d.ts +141 -181
  172. package/unit-of-work/UnitOfWork.js +1183 -1200
  173. package/utils/AbstractMigrator.d.ts +91 -111
  174. package/utils/AbstractMigrator.js +275 -275
  175. package/utils/AbstractSchemaGenerator.d.ts +34 -43
  176. package/utils/AbstractSchemaGenerator.js +122 -121
  177. package/utils/AsyncContext.d.ts +3 -3
  178. package/utils/AsyncContext.js +35 -34
  179. package/utils/Configuration.d.ts +808 -852
  180. package/utils/Configuration.js +344 -359
  181. package/utils/Cursor.d.ts +22 -40
  182. package/utils/Cursor.js +127 -135
  183. package/utils/DataloaderUtils.d.ts +43 -58
  184. package/utils/DataloaderUtils.js +198 -203
  185. package/utils/EntityComparator.d.ts +81 -98
  186. package/utils/EntityComparator.js +735 -829
  187. package/utils/NullHighlighter.d.ts +1 -1
  188. package/utils/NullHighlighter.js +3 -3
  189. package/utils/QueryHelper.d.ts +51 -79
  190. package/utils/QueryHelper.js +361 -372
  191. package/utils/RawQueryFragment.d.ts +34 -50
  192. package/utils/RawQueryFragment.js +105 -107
  193. package/utils/RequestContext.d.ts +32 -32
  194. package/utils/RequestContext.js +53 -52
  195. package/utils/TransactionContext.d.ts +16 -16
  196. package/utils/TransactionContext.js +27 -27
  197. package/utils/TransactionManager.d.ts +58 -58
  198. package/utils/TransactionManager.js +197 -199
  199. package/utils/Utils.d.ts +145 -204
  200. package/utils/Utils.js +815 -815
  201. package/utils/clone.js +114 -105
  202. package/utils/env-vars.js +88 -90
  203. package/utils/fs-utils.d.ts +15 -15
  204. package/utils/fs-utils.js +181 -180
  205. package/utils/upsert-utils.d.ts +5 -20
  206. package/utils/upsert-utils.js +116 -114
@@ -1,4 +1,4 @@
1
- import { EntityMetadata } from '../typings.js';
1
+ import { EntityMetadata, } from '../typings.js';
2
2
  import { BaseEntity } from '../entity/BaseEntity.js';
3
3
  import { Cascade, ReferenceKind } from '../enums.js';
4
4
  import { Type } from '../types/Type.js';
@@ -6,414 +6,415 @@ import { Utils } from '../utils/Utils.js';
6
6
  import { EnumArrayType } from '../types/EnumArrayType.js';
7
7
  /** Class-less entity definition that provides a programmatic API for defining entities without decorators. */
8
8
  export class EntitySchema {
9
- /**
10
- * When schema links the entity class via `class` option, this registry allows the lookup from opposite side,
11
- * so we can use the class in `entities` option just like the EntitySchema instance.
12
- *
13
- * Stored on `globalThis` via `Symbol.for` to survive the CJS/ESM dual-package hazard
14
- * (e.g. when `tsx` loads the same package in both module systems).
15
- */
16
- static get REGISTRY() {
17
- const key = Symbol.for('@mikro-orm/core/EntitySchema.REGISTRY');
18
- return (globalThis[key] ??= new Map());
19
- }
20
- _meta;
21
- internal = false;
22
- initialized = false;
23
- constructor(meta) {
24
- // Skip for internal schemas (fromMetadata) — the name was already resolved,
25
- // re-deriving it from class.name would break defineEntity + setClass with a different name (GH #7391).
26
- if (!meta.internal) {
27
- meta.name = meta.class ? meta.class.name : meta.name;
28
- }
29
- if (meta.name) {
30
- meta.abstract ??= false;
31
- }
32
- this._meta = new EntityMetadata({
33
- className: meta.name,
34
- ...meta,
35
- });
36
- this._meta.root ??= this._meta;
37
- if (meta.class && !meta.internal) {
38
- EntitySchema.REGISTRY.set(meta.class, this);
39
- }
40
- }
41
- /**
42
- * Checks if the given value is an EntitySchema instance, using duck-typing
43
- * as a fallback when `instanceof` fails due to CJS/ESM dual-package hazard
44
- * (e.g. when using `tsx` or `@swc-node/register` with `"type": "commonjs"` projects).
45
- */
46
- static is(item) {
47
- if (item instanceof EntitySchema) {
48
- return true;
49
- }
50
- return item != null && typeof item === 'object' && item.constructor?.name === 'EntitySchema' && 'meta' in item;
51
- }
52
- /** Creates an EntitySchema from existing EntityMetadata (used internally). */
53
- static fromMetadata(meta) {
54
- const schema = new EntitySchema({ ...meta, internal: true });
55
- schema.internal = true;
56
- return schema;
57
- }
58
- /** Adds a scalar property to the entity schema. */
59
- addProperty(name, type, options = {}) {
60
- this.renameCompositeOptions(name, options);
61
- const prop = {
62
- name,
63
- kind: ReferenceKind.SCALAR,
64
- ...options,
65
- ...this.normalizeType(options, type),
66
- };
67
- if (type && Type.isMappedType(type.prototype)) {
68
- prop.type = type;
69
- }
70
- if (typeof prop.formula === 'string') {
71
- const formula = prop.formula;
72
- prop.formula = () => formula;
73
- }
74
- if (prop.formula) {
75
- prop.persist ??= false;
76
- }
77
- if (prop.check) {
78
- this._meta.checks.push({ property: prop.name, expression: prop.check });
79
- delete prop.check;
80
- }
81
- this._meta.properties[name] = prop;
82
- }
83
- /** Adds an enum property to the entity schema. */
84
- addEnum(name, type, options = {}) {
85
- if (options.items instanceof Function) {
86
- options.items = Utils.extractEnumValues(options.items());
87
- }
88
- // enum arrays are simple numeric/string arrays, the constraint is enforced in the custom type only
89
- if (options.array && !options.type) {
90
- options.type = new EnumArrayType(`${this._meta.className}.${name}`, options.items);
91
- options.enum = false;
92
- }
93
- const prop = { enum: true, ...options };
94
- if (prop.array) {
95
- prop.enum = false;
96
- }
97
- // force string labels on native enums
98
- if (prop.nativeEnumName && Array.isArray(prop.items)) {
99
- prop.items = prop.items.map(val => '' + val);
100
- }
101
- this.addProperty(name, this.internal ? type : type || 'enum', prop);
102
- }
103
- /** Adds a version property for optimistic locking. */
104
- addVersion(name, type, options = {}) {
105
- this.addProperty(name, type, { version: true, ...options });
106
- }
107
- /** Adds a primary key property to the entity schema. */
108
- addPrimaryKey(name, type, options = {}) {
109
- this.addProperty(name, type, { primary: true, ...options });
110
- }
111
- /** Adds a serialized primary key property (e.g. for MongoDB ObjectId). */
112
- addSerializedPrimaryKey(name, type, options = {}) {
113
- this._meta.serializedPrimaryKey = name;
114
- this.addProperty(name, type, { serializedPrimaryKey: true, ...options });
115
- }
116
- /** Adds an embedded property to the entity schema. */
117
- addEmbedded(name, options) {
118
- this.renameCompositeOptions(name, options);
119
- Utils.defaultValue(options, 'prefix', true);
120
- if (options.array) {
121
- options.object = true; // force object mode for arrays
122
- }
123
- this._meta.properties[name] = {
124
- name,
125
- kind: ReferenceKind.EMBEDDED,
126
- ...this.normalizeType(options),
127
- ...options,
128
- };
129
- }
130
- /** Adds a many-to-one relation to the entity schema. */
131
- addManyToOne(name, type, options) {
132
- const prop = this.createProperty(ReferenceKind.MANY_TO_ONE, options);
133
- prop.owner = true;
134
- if (prop.joinColumns && !prop.fieldNames) {
135
- prop.fieldNames = prop.joinColumns;
136
- }
137
- if (prop.fieldNames && !prop.joinColumns) {
138
- prop.joinColumns = prop.fieldNames;
139
- }
140
- // By default, the foreign key constraint is created on the relation
141
- Utils.defaultValue(prop, 'createForeignKeyConstraint', true);
142
- this.addProperty(name, type, prop);
143
- }
144
- /** Adds a many-to-many relation to the entity schema. */
145
- addManyToMany(name, type, options) {
146
- options.fixedOrder = options.fixedOrder || !!options.fixedOrderColumn;
147
- if (!options.owner && !options.mappedBy) {
148
- options.owner = true;
149
- }
150
- if (options.owner) {
151
- Utils.renameKey(options, 'mappedBy', 'inversedBy');
152
- // By default, the foreign key constraint is created on the relation
153
- Utils.defaultValue(options, 'createForeignKeyConstraint', true);
154
- }
155
- const prop = this.createProperty(ReferenceKind.MANY_TO_MANY, options);
156
- this.addProperty(name, type, prop);
157
- }
158
- /** Adds a one-to-many relation to the entity schema. */
159
- addOneToMany(name, type, options) {
160
- const prop = this.createProperty(ReferenceKind.ONE_TO_MANY, options);
161
- this.addProperty(name, type, prop);
162
- }
163
- /** Adds a one-to-one relation to the entity schema. */
164
- addOneToOne(name, type, options) {
165
- const prop = this.createProperty(ReferenceKind.ONE_TO_ONE, options);
166
- Utils.defaultValue(prop, 'owner', !!prop.inversedBy || !prop.mappedBy);
167
- Utils.defaultValue(prop, 'unique', prop.owner);
168
- if (prop.owner) {
169
- if (options.mappedBy) {
170
- Utils.renameKey(prop, 'mappedBy', 'inversedBy');
171
- }
172
- // By default, the foreign key constraint is created on the relation
173
- Utils.defaultValue(prop, 'createForeignKeyConstraint', true);
174
- }
175
- if (prop.joinColumns && !prop.fieldNames) {
176
- prop.fieldNames = prop.joinColumns;
177
- }
178
- if (prop.fieldNames && !prop.joinColumns) {
179
- prop.joinColumns = prop.fieldNames;
180
- }
181
- this.addProperty(name, type, prop);
182
- }
183
- /** Adds an index definition to the entity schema. */
184
- addIndex(options) {
185
- this._meta.indexes.push(options);
186
- }
187
- /** Adds a unique constraint definition to the entity schema. */
188
- addUnique(options) {
189
- this._meta.uniques.push(options);
190
- }
191
- /** Sets a custom repository class for this entity. */
192
- setCustomRepository(repository) {
193
- this._meta.repository = repository;
194
- }
195
- /** Sets the base entity that this schema extends. */
196
- setExtends(base) {
197
- this._meta.extends = base;
198
- }
199
- /** Sets or replaces the entity class associated with this schema. */
200
- setClass(cls) {
201
- const oldClass = this._meta.class;
202
- const sameClass = this._meta.class === cls;
203
- this._meta.class = cls;
204
- this._meta.prototype = cls.prototype;
205
- this._meta.className = this._meta.name ?? cls.name;
206
- if (!sameClass || !this._meta.constructorParams) {
207
- this._meta.constructorParams = Utils.getConstructorParams(cls);
208
- }
209
- if (!this.internal) {
210
- // Remove old class from registry if it's being replaced with a different class
211
- if (oldClass && oldClass !== cls && EntitySchema.REGISTRY.get(oldClass) === this) {
212
- EntitySchema.REGISTRY.delete(oldClass);
213
- }
214
- EntitySchema.REGISTRY.set(cls, this);
215
- }
216
- const base = Object.getPrototypeOf(cls);
217
- // Only set extends if the parent is NOT the auto-generated class for this same entity.
218
- // When the user extends the auto-generated class (from defineEntity without a class option)
219
- // and registers their custom class via setClass, we don't want to discover the
220
- // auto-generated class as a separate parent entity.
221
- if (base !== BaseEntity && base.name !== this._meta.className) {
222
- this._meta.extends ??= base.name ? base : undefined;
223
- }
224
- }
225
- /** Returns the underlying EntityMetadata. */
226
- get meta() {
227
- return this._meta;
228
- }
229
- /** Returns the entity class name. */
230
- get name() {
231
- return this._meta.className;
232
- }
233
- /** Returns the database table name. */
234
- get tableName() {
235
- return this._meta.tableName;
236
- }
237
- get class() {
238
- return this._meta.class;
239
- }
240
- get properties() {
241
- return this._meta.properties;
242
- }
243
- new(...params) {
244
- return new this._meta.class(...params);
245
- }
246
- /**
247
- * @internal
248
- */
249
- init() {
250
- if (this.initialized) {
251
- return this;
252
- }
253
- this.setClass(this._meta.class);
254
- // Abstract TPT entities keep their name because they have their own table
255
- const isTPT = this._meta.inheritance === 'tpt' || this.isPartOfTPTHierarchy();
256
- if (this._meta.abstract && !this._meta.discriminatorColumn && !isTPT) {
257
- delete this._meta.name;
258
- }
259
- const tableName = this._meta.collection ?? this._meta.tableName;
260
- if (tableName?.includes('.') && !this._meta.schema) {
261
- this._meta.schema = tableName.substring(0, tableName.indexOf('.'));
262
- this._meta.tableName = tableName.substring(tableName.indexOf('.') + 1);
263
- }
264
- this.initProperties();
265
- this.initPrimaryKeys();
266
- this._meta.props = Object.values(this._meta.properties);
267
- this._meta.relations = this._meta.props.filter(
268
- prop =>
269
- typeof prop.kind !== 'undefined' && prop.kind !== ReferenceKind.SCALAR && prop.kind !== ReferenceKind.EMBEDDED,
270
- );
271
- this.initialized = true;
272
- return this;
273
- }
274
- /**
275
- * Check if this entity is part of a TPT hierarchy by walking up the extends chain.
276
- * This handles mid-level abstract entities (e.g., Animal -> Mammal -> Dog where Mammal is abstract).
277
- */
278
- isPartOfTPTHierarchy() {
279
- let parent = this._meta.extends;
280
- while (parent) {
281
- const parentSchema = EntitySchema.is(parent) ? parent : EntitySchema.REGISTRY.get(parent);
282
- if (!parentSchema) {
283
- break;
284
- }
285
- if (parentSchema._meta.inheritance === 'tpt') {
286
- return true;
287
- }
288
- parent = parentSchema._meta.extends;
289
- }
290
- return false;
291
- }
292
- initProperties() {
293
- Utils.entries(this._meta.properties).forEach(([name, options]) => {
294
- if (Type.isMappedType(options.type)) {
295
- options.type ??= options.type.constructor.name;
296
- }
297
- switch (options.kind) {
298
- case ReferenceKind.ONE_TO_ONE:
299
- this.addOneToOne(name, options.type, options);
300
- break;
301
- case ReferenceKind.ONE_TO_MANY:
302
- this.addOneToMany(name, options.type, options);
303
- break;
304
- case ReferenceKind.MANY_TO_ONE:
305
- this.addManyToOne(name, options.type, options);
306
- break;
307
- case ReferenceKind.MANY_TO_MANY:
308
- this.addManyToMany(name, options.type, options);
309
- break;
310
- case ReferenceKind.EMBEDDED:
311
- this.addEmbedded(name, options);
312
- break;
313
- default:
314
- if (options.enum) {
315
- this.addEnum(name, options.type, options);
316
- } else if (options.primary) {
317
- this.addPrimaryKey(name, options.type, options);
318
- } else if (options.serializedPrimaryKey) {
319
- this.addSerializedPrimaryKey(name, options.type, options);
320
- } else if (options.version) {
321
- this.addVersion(name, options.type, options);
322
- } else {
323
- this.addProperty(name, options.type, options);
324
- }
325
- }
326
- });
327
- }
328
- initPrimaryKeys() {
329
- const pks = Object.values(this._meta.properties).filter(prop => prop.primary);
330
- if (pks.length > 0) {
331
- this._meta.primaryKeys = pks.map(prop => prop.name);
332
- this._meta.compositePK = pks.length > 1;
333
- this._meta.simplePK = !this._meta.compositePK && pks[0].kind === ReferenceKind.SCALAR && !pks[0].customType;
334
- }
335
- if (pks.length === 1 && ['number', 'bigint'].includes(pks[0].type)) {
336
- pks[0].autoincrement ??= true;
337
- }
338
- const serializedPrimaryKey = Object.values(this._meta.properties).find(prop => prop.serializedPrimaryKey);
339
- if (serializedPrimaryKey) {
340
- this._meta.serializedPrimaryKey = serializedPrimaryKey.name;
341
- }
342
- }
343
- normalizeType(options, type) {
344
- if ('entity' in options) {
345
- /* v8 ignore next */
346
- if (typeof options.entity === 'string') {
347
- throw new Error(
348
- `Relation target needs to be an entity class or EntitySchema instance, string '${options.entity}' given instead for ${this._meta.className}.${options.name}.`,
349
- );
350
- } else if (options.entity) {
351
- const tmp = options.entity();
352
- type = options.type = Array.isArray(tmp)
353
- ? tmp
354
- .map(t => Utils.className(t))
355
- .sort()
356
- .join(' | ')
357
- : Utils.className(tmp);
358
- const target = EntitySchema.is(tmp) ? tmp.meta.class : tmp;
359
- return { type, target };
360
- }
361
- }
362
- if (type instanceof Function) {
363
- type = type.name;
364
- }
365
- if (['String', 'Number', 'Boolean', 'Array'].includes(type)) {
366
- type = type.toLowerCase();
367
- }
368
- return { type };
369
- }
370
- createProperty(kind, options) {
371
- return {
372
- kind,
373
- cascade: [Cascade.PERSIST],
374
- ...options,
375
- };
376
- }
377
- rename(data, from, to) {
378
- if (from in data && !(to in data)) {
379
- // @ts-ignore
380
- data[to] = [data[from]];
381
- // @ts-ignore
382
- delete data[from];
383
- }
384
- }
385
- renameCompositeOptions(name, options = {}) {
386
- if (name !== options.name && !options.fieldNames) {
387
- Utils.renameKey(options, 'name', 'fieldName');
388
- } else if (options.name && (options.fieldNames?.length ?? 0) > 1) {
389
- delete options.name;
390
- }
391
- this.rename(options, 'fieldName', 'fieldNames');
392
- this.rename(options, 'joinColumn', 'joinColumns');
393
- this.rename(options, 'inverseJoinColumn', 'inverseJoinColumns');
394
- this.rename(options, 'referenceColumnName', 'referencedColumnNames');
395
- this.rename(options, 'columnType', 'columnTypes');
396
- }
397
- /**
398
- * Adds a lifecycle hook handler to the entity schema.
399
- * This method allows registering hooks after the entity is defined,
400
- * which can be useful for avoiding circular type references.
401
- *
402
- * @example
403
- * ```ts
404
- * export const Article = defineEntity({
405
- * name: 'Article',
406
- * properties: { ... },
407
- * });
408
- *
409
- * Article.addHook('beforeCreate', async args => {
410
- * args.entity.slug = args.entity.title.toLowerCase();
411
- * });
412
- * ```
413
- */
414
- addHook(event, handler) {
415
- this._meta.hooks[event] ??= [];
416
- this._meta.hooks[event].push(handler);
417
- return this;
418
- }
9
+ /**
10
+ * When schema links the entity class via `class` option, this registry allows the lookup from opposite side,
11
+ * so we can use the class in `entities` option just like the EntitySchema instance.
12
+ *
13
+ * Stored on `globalThis` via `Symbol.for` to survive the CJS/ESM dual-package hazard
14
+ * (e.g. when `tsx` loads the same package in both module systems).
15
+ */
16
+ static get REGISTRY() {
17
+ const key = Symbol.for('@mikro-orm/core/EntitySchema.REGISTRY');
18
+ return (globalThis[key] ??= new Map());
19
+ }
20
+ _meta;
21
+ internal = false;
22
+ initialized = false;
23
+ constructor(meta) {
24
+ // Skip for internal schemas (fromMetadata) — the name was already resolved,
25
+ // re-deriving it from class.name would break defineEntity + setClass with a different name (GH #7391).
26
+ if (!meta.internal) {
27
+ meta.name = meta.class ? meta.class.name : meta.name;
28
+ }
29
+ if (meta.name) {
30
+ meta.abstract ??= false;
31
+ }
32
+ this._meta = new EntityMetadata({
33
+ className: meta.name,
34
+ ...meta,
35
+ });
36
+ this._meta.root ??= this._meta;
37
+ if (meta.class && !meta.internal) {
38
+ EntitySchema.REGISTRY.set(meta.class, this);
39
+ }
40
+ }
41
+ /**
42
+ * Checks if the given value is an EntitySchema instance, using duck-typing
43
+ * as a fallback when `instanceof` fails due to CJS/ESM dual-package hazard
44
+ * (e.g. when using `tsx` or `@swc-node/register` with `"type": "commonjs"` projects).
45
+ */
46
+ static is(item) {
47
+ if (item instanceof EntitySchema) {
48
+ return true;
49
+ }
50
+ return item != null && typeof item === 'object' && item.constructor?.name === 'EntitySchema' && 'meta' in item;
51
+ }
52
+ /** Creates an EntitySchema from existing EntityMetadata (used internally). */
53
+ static fromMetadata(meta) {
54
+ const schema = new EntitySchema({ ...meta, internal: true });
55
+ schema.internal = true;
56
+ return schema;
57
+ }
58
+ /** Adds a scalar property to the entity schema. */
59
+ addProperty(name, type, options = {}) {
60
+ this.renameCompositeOptions(name, options);
61
+ const prop = {
62
+ name,
63
+ kind: ReferenceKind.SCALAR,
64
+ ...options,
65
+ ...this.normalizeType(options, type),
66
+ };
67
+ if (type && Type.isMappedType(type.prototype)) {
68
+ prop.type = type;
69
+ }
70
+ if (typeof prop.formula === 'string') {
71
+ const formula = prop.formula;
72
+ prop.formula = () => formula;
73
+ }
74
+ if (prop.formula) {
75
+ prop.persist ??= false;
76
+ }
77
+ if (prop.check) {
78
+ this._meta.checks.push({ property: prop.name, expression: prop.check });
79
+ delete prop.check;
80
+ }
81
+ this._meta.properties[name] = prop;
82
+ }
83
+ /** Adds an enum property to the entity schema. */
84
+ addEnum(name, type, options = {}) {
85
+ if (options.items instanceof Function) {
86
+ options.items = Utils.extractEnumValues(options.items());
87
+ }
88
+ // enum arrays are simple numeric/string arrays, the constraint is enforced in the custom type only
89
+ if (options.array && !options.type) {
90
+ options.type = new EnumArrayType(`${this._meta.className}.${name}`, options.items);
91
+ options.enum = false;
92
+ }
93
+ const prop = { enum: true, ...options };
94
+ if (prop.array) {
95
+ prop.enum = false;
96
+ }
97
+ // force string labels on native enums
98
+ if (prop.nativeEnumName && Array.isArray(prop.items)) {
99
+ prop.items = prop.items.map(val => '' + val);
100
+ }
101
+ this.addProperty(name, this.internal ? type : type || 'enum', prop);
102
+ }
103
+ /** Adds a version property for optimistic locking. */
104
+ addVersion(name, type, options = {}) {
105
+ this.addProperty(name, type, { version: true, ...options });
106
+ }
107
+ /** Adds a primary key property to the entity schema. */
108
+ addPrimaryKey(name, type, options = {}) {
109
+ this.addProperty(name, type, { primary: true, ...options });
110
+ }
111
+ /** Adds a serialized primary key property (e.g. for MongoDB ObjectId). */
112
+ addSerializedPrimaryKey(name, type, options = {}) {
113
+ this._meta.serializedPrimaryKey = name;
114
+ this.addProperty(name, type, { serializedPrimaryKey: true, ...options });
115
+ }
116
+ /** Adds an embedded property to the entity schema. */
117
+ addEmbedded(name, options) {
118
+ this.renameCompositeOptions(name, options);
119
+ Utils.defaultValue(options, 'prefix', true);
120
+ if (options.array) {
121
+ options.object = true; // force object mode for arrays
122
+ }
123
+ this._meta.properties[name] = {
124
+ name,
125
+ kind: ReferenceKind.EMBEDDED,
126
+ ...this.normalizeType(options),
127
+ ...options,
128
+ };
129
+ }
130
+ /** Adds a many-to-one relation to the entity schema. */
131
+ addManyToOne(name, type, options) {
132
+ const prop = this.createProperty(ReferenceKind.MANY_TO_ONE, options);
133
+ prop.owner = true;
134
+ if (prop.joinColumns && !prop.fieldNames) {
135
+ prop.fieldNames = prop.joinColumns;
136
+ }
137
+ if (prop.fieldNames && !prop.joinColumns) {
138
+ prop.joinColumns = prop.fieldNames;
139
+ }
140
+ // By default, the foreign key constraint is created on the relation
141
+ Utils.defaultValue(prop, 'createForeignKeyConstraint', true);
142
+ this.addProperty(name, type, prop);
143
+ }
144
+ /** Adds a many-to-many relation to the entity schema. */
145
+ addManyToMany(name, type, options) {
146
+ options.fixedOrder = options.fixedOrder || !!options.fixedOrderColumn;
147
+ if (!options.owner && !options.mappedBy) {
148
+ options.owner = true;
149
+ }
150
+ if (options.owner) {
151
+ Utils.renameKey(options, 'mappedBy', 'inversedBy');
152
+ // By default, the foreign key constraint is created on the relation
153
+ Utils.defaultValue(options, 'createForeignKeyConstraint', true);
154
+ }
155
+ const prop = this.createProperty(ReferenceKind.MANY_TO_MANY, options);
156
+ this.addProperty(name, type, prop);
157
+ }
158
+ /** Adds a one-to-many relation to the entity schema. */
159
+ addOneToMany(name, type, options) {
160
+ const prop = this.createProperty(ReferenceKind.ONE_TO_MANY, options);
161
+ this.addProperty(name, type, prop);
162
+ }
163
+ /** Adds a one-to-one relation to the entity schema. */
164
+ addOneToOne(name, type, options) {
165
+ const prop = this.createProperty(ReferenceKind.ONE_TO_ONE, options);
166
+ Utils.defaultValue(prop, 'owner', !!prop.inversedBy || !prop.mappedBy);
167
+ Utils.defaultValue(prop, 'unique', prop.owner);
168
+ if (prop.owner) {
169
+ if (options.mappedBy) {
170
+ Utils.renameKey(prop, 'mappedBy', 'inversedBy');
171
+ }
172
+ // By default, the foreign key constraint is created on the relation
173
+ Utils.defaultValue(prop, 'createForeignKeyConstraint', true);
174
+ }
175
+ if (prop.joinColumns && !prop.fieldNames) {
176
+ prop.fieldNames = prop.joinColumns;
177
+ }
178
+ if (prop.fieldNames && !prop.joinColumns) {
179
+ prop.joinColumns = prop.fieldNames;
180
+ }
181
+ this.addProperty(name, type, prop);
182
+ }
183
+ /** Adds an index definition to the entity schema. */
184
+ addIndex(options) {
185
+ this._meta.indexes.push(options);
186
+ }
187
+ /** Adds a unique constraint definition to the entity schema. */
188
+ addUnique(options) {
189
+ this._meta.uniques.push(options);
190
+ }
191
+ /** Sets a custom repository class for this entity. */
192
+ setCustomRepository(repository) {
193
+ this._meta.repository = repository;
194
+ }
195
+ /** Sets the base entity that this schema extends. */
196
+ setExtends(base) {
197
+ this._meta.extends = base;
198
+ }
199
+ /** Sets or replaces the entity class associated with this schema. */
200
+ setClass(cls) {
201
+ const oldClass = this._meta.class;
202
+ const sameClass = this._meta.class === cls;
203
+ this._meta.class = cls;
204
+ this._meta.prototype = cls.prototype;
205
+ this._meta.className = this._meta.name ?? cls.name;
206
+ if (!sameClass || !this._meta.constructorParams) {
207
+ this._meta.constructorParams = Utils.getConstructorParams(cls);
208
+ }
209
+ if (!this.internal) {
210
+ // Remove old class from registry if it's being replaced with a different class
211
+ if (oldClass && oldClass !== cls && EntitySchema.REGISTRY.get(oldClass) === this) {
212
+ EntitySchema.REGISTRY.delete(oldClass);
213
+ }
214
+ EntitySchema.REGISTRY.set(cls, this);
215
+ }
216
+ const base = Object.getPrototypeOf(cls);
217
+ // Only set extends if the parent is NOT the auto-generated class for this same entity.
218
+ // When the user extends the auto-generated class (from defineEntity without a class option)
219
+ // and registers their custom class via setClass, we don't want to discover the
220
+ // auto-generated class as a separate parent entity.
221
+ if (base !== BaseEntity && base.name !== this._meta.className) {
222
+ this._meta.extends ??= base.name ? base : undefined;
223
+ }
224
+ }
225
+ /** Returns the underlying EntityMetadata. */
226
+ get meta() {
227
+ return this._meta;
228
+ }
229
+ /** Returns the entity class name. */
230
+ get name() {
231
+ return this._meta.className;
232
+ }
233
+ /** Returns the database table name. */
234
+ get tableName() {
235
+ return this._meta.tableName;
236
+ }
237
+ get class() {
238
+ return this._meta.class;
239
+ }
240
+ get properties() {
241
+ return this._meta.properties;
242
+ }
243
+ new(...params) {
244
+ return new this._meta.class(...params);
245
+ }
246
+ /**
247
+ * @internal
248
+ */
249
+ init() {
250
+ if (this.initialized) {
251
+ return this;
252
+ }
253
+ this.setClass(this._meta.class);
254
+ // Abstract TPT entities keep their name because they have their own table
255
+ const isTPT = this._meta.inheritance === 'tpt' || this.isPartOfTPTHierarchy();
256
+ if (this._meta.abstract && !this._meta.discriminatorColumn && !isTPT) {
257
+ delete this._meta.name;
258
+ }
259
+ const tableName = this._meta.collection ?? this._meta.tableName;
260
+ if (tableName?.includes('.') && !this._meta.schema) {
261
+ this._meta.schema = tableName.substring(0, tableName.indexOf('.'));
262
+ this._meta.tableName = tableName.substring(tableName.indexOf('.') + 1);
263
+ }
264
+ this.initProperties();
265
+ this.initPrimaryKeys();
266
+ this._meta.props = Object.values(this._meta.properties);
267
+ this._meta.relations = this._meta.props.filter(prop => typeof prop.kind !== 'undefined' && prop.kind !== ReferenceKind.SCALAR && prop.kind !== ReferenceKind.EMBEDDED);
268
+ this.initialized = true;
269
+ return this;
270
+ }
271
+ /**
272
+ * Check if this entity is part of a TPT hierarchy by walking up the extends chain.
273
+ * This handles mid-level abstract entities (e.g., Animal -> Mammal -> Dog where Mammal is abstract).
274
+ */
275
+ isPartOfTPTHierarchy() {
276
+ let parent = this._meta.extends;
277
+ while (parent) {
278
+ const parentSchema = EntitySchema.is(parent) ? parent : EntitySchema.REGISTRY.get(parent);
279
+ if (!parentSchema) {
280
+ break;
281
+ }
282
+ if (parentSchema._meta.inheritance === 'tpt') {
283
+ return true;
284
+ }
285
+ parent = parentSchema._meta.extends;
286
+ }
287
+ return false;
288
+ }
289
+ initProperties() {
290
+ Utils.entries(this._meta.properties).forEach(([name, options]) => {
291
+ if (Type.isMappedType(options.type)) {
292
+ options.type ??= options.type.constructor.name;
293
+ }
294
+ switch (options.kind) {
295
+ case ReferenceKind.ONE_TO_ONE:
296
+ this.addOneToOne(name, options.type, options);
297
+ break;
298
+ case ReferenceKind.ONE_TO_MANY:
299
+ this.addOneToMany(name, options.type, options);
300
+ break;
301
+ case ReferenceKind.MANY_TO_ONE:
302
+ this.addManyToOne(name, options.type, options);
303
+ break;
304
+ case ReferenceKind.MANY_TO_MANY:
305
+ this.addManyToMany(name, options.type, options);
306
+ break;
307
+ case ReferenceKind.EMBEDDED:
308
+ this.addEmbedded(name, options);
309
+ break;
310
+ default:
311
+ if (options.enum) {
312
+ this.addEnum(name, options.type, options);
313
+ }
314
+ else if (options.primary) {
315
+ this.addPrimaryKey(name, options.type, options);
316
+ }
317
+ else if (options.serializedPrimaryKey) {
318
+ this.addSerializedPrimaryKey(name, options.type, options);
319
+ }
320
+ else if (options.version) {
321
+ this.addVersion(name, options.type, options);
322
+ }
323
+ else {
324
+ this.addProperty(name, options.type, options);
325
+ }
326
+ }
327
+ });
328
+ }
329
+ initPrimaryKeys() {
330
+ const pks = Object.values(this._meta.properties).filter(prop => prop.primary);
331
+ if (pks.length > 0) {
332
+ this._meta.primaryKeys = pks.map(prop => prop.name);
333
+ this._meta.compositePK = pks.length > 1;
334
+ this._meta.simplePK = !this._meta.compositePK && pks[0].kind === ReferenceKind.SCALAR && !pks[0].customType;
335
+ }
336
+ if (pks.length === 1 && ['number', 'bigint'].includes(pks[0].type)) {
337
+ pks[0].autoincrement ??= true;
338
+ }
339
+ const serializedPrimaryKey = Object.values(this._meta.properties).find(prop => prop.serializedPrimaryKey);
340
+ if (serializedPrimaryKey) {
341
+ this._meta.serializedPrimaryKey = serializedPrimaryKey.name;
342
+ }
343
+ }
344
+ normalizeType(options, type) {
345
+ if ('entity' in options) {
346
+ /* v8 ignore next */
347
+ if (typeof options.entity === 'string') {
348
+ throw new Error(`Relation target needs to be an entity class or EntitySchema instance, string '${options.entity}' given instead for ${this._meta.className}.${options.name}.`);
349
+ }
350
+ else if (options.entity) {
351
+ const tmp = options.entity();
352
+ type = options.type = Array.isArray(tmp)
353
+ ? tmp
354
+ .map(t => Utils.className(t))
355
+ .sort()
356
+ .join(' | ')
357
+ : Utils.className(tmp);
358
+ const target = EntitySchema.is(tmp) ? tmp.meta.class : tmp;
359
+ return { type, target };
360
+ }
361
+ }
362
+ if (type instanceof Function) {
363
+ type = type.name;
364
+ }
365
+ if (['String', 'Number', 'Boolean', 'Array'].includes(type)) {
366
+ type = type.toLowerCase();
367
+ }
368
+ return { type };
369
+ }
370
+ createProperty(kind, options) {
371
+ return {
372
+ kind,
373
+ cascade: [Cascade.PERSIST],
374
+ ...options,
375
+ };
376
+ }
377
+ rename(data, from, to) {
378
+ if (from in data && !(to in data)) {
379
+ // @ts-ignore
380
+ data[to] = [data[from]];
381
+ // @ts-ignore
382
+ delete data[from];
383
+ }
384
+ }
385
+ renameCompositeOptions(name, options = {}) {
386
+ if (name !== options.name && !options.fieldNames) {
387
+ Utils.renameKey(options, 'name', 'fieldName');
388
+ }
389
+ else if (options.name && (options.fieldNames?.length ?? 0) > 1) {
390
+ delete options.name;
391
+ }
392
+ this.rename(options, 'fieldName', 'fieldNames');
393
+ this.rename(options, 'joinColumn', 'joinColumns');
394
+ this.rename(options, 'inverseJoinColumn', 'inverseJoinColumns');
395
+ this.rename(options, 'referenceColumnName', 'referencedColumnNames');
396
+ this.rename(options, 'columnType', 'columnTypes');
397
+ }
398
+ /**
399
+ * Adds a lifecycle hook handler to the entity schema.
400
+ * This method allows registering hooks after the entity is defined,
401
+ * which can be useful for avoiding circular type references.
402
+ *
403
+ * @example
404
+ * ```ts
405
+ * export const Article = defineEntity({
406
+ * name: 'Article',
407
+ * properties: { ... },
408
+ * });
409
+ *
410
+ * Article.addHook('beforeCreate', async args => {
411
+ * args.entity.slug = args.entity.title.toLowerCase();
412
+ * });
413
+ * ```
414
+ */
415
+ addHook(event, handler) {
416
+ this._meta.hooks[event] ??= [];
417
+ this._meta.hooks[event].push(handler);
418
+ return this;
419
+ }
419
420
  }