@mikro-orm/core 7.0.9-dev.9 → 7.0.9

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 +884 -583
  2. package/EntityManager.js +1926 -1899
  3. package/MikroORM.d.ts +103 -74
  4. package/MikroORM.js +177 -179
  5. package/README.md +1 -1
  6. package/cache/CacheAdapter.d.ts +36 -36
  7. package/cache/FileCacheAdapter.d.ts +30 -24
  8. package/cache/FileCacheAdapter.js +80 -78
  9. package/cache/GeneratedCacheAdapter.d.ts +18 -20
  10. package/cache/GeneratedCacheAdapter.js +30 -30
  11. package/cache/MemoryCacheAdapter.d.ts +18 -20
  12. package/cache/MemoryCacheAdapter.js +35 -36
  13. package/cache/NullCacheAdapter.d.ts +16 -16
  14. package/cache/NullCacheAdapter.js +24 -24
  15. package/connections/Connection.d.ts +95 -84
  16. package/connections/Connection.js +165 -168
  17. package/drivers/DatabaseDriver.d.ts +187 -81
  18. package/drivers/DatabaseDriver.js +450 -444
  19. package/drivers/IDatabaseDriver.d.ts +440 -301
  20. package/entity/BaseEntity.d.ts +120 -83
  21. package/entity/BaseEntity.js +43 -43
  22. package/entity/Collection.d.ts +215 -181
  23. package/entity/Collection.js +730 -724
  24. package/entity/EntityAssigner.d.ts +88 -77
  25. package/entity/EntityAssigner.js +231 -230
  26. package/entity/EntityFactory.d.ts +67 -55
  27. package/entity/EntityFactory.js +457 -414
  28. package/entity/EntityHelper.d.ts +35 -23
  29. package/entity/EntityHelper.js +291 -279
  30. package/entity/EntityIdentifier.d.ts +4 -4
  31. package/entity/EntityIdentifier.js +10 -10
  32. package/entity/EntityLoader.d.ts +98 -72
  33. package/entity/EntityLoader.js +792 -761
  34. package/entity/EntityRepository.d.ts +316 -201
  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 +127 -83
  39. package/entity/Reference.js +281 -277
  40. package/entity/WrappedEntity.d.ts +115 -72
  41. package/entity/WrappedEntity.js +168 -166
  42. package/entity/defineEntity.d.ts +1359 -654
  43. package/entity/defineEntity.js +527 -518
  44. package/entity/utils.d.ts +13 -3
  45. package/entity/utils.js +71 -73
  46. package/entity/validators.js +43 -43
  47. package/entity/wrap.js +8 -8
  48. package/enums.d.ts +258 -253
  49. package/enums.js +251 -252
  50. package/errors.d.ts +114 -72
  51. package/errors.js +350 -253
  52. package/events/EventManager.d.ts +26 -14
  53. package/events/EventManager.js +79 -77
  54. package/events/EventSubscriber.d.ts +29 -29
  55. package/events/TransactionEventBroadcaster.d.ts +15 -8
  56. package/events/TransactionEventBroadcaster.js +14 -14
  57. package/exceptions.d.ts +23 -40
  58. package/exceptions.js +35 -52
  59. package/hydration/Hydrator.d.ts +42 -17
  60. package/hydration/Hydrator.js +43 -43
  61. package/hydration/ObjectHydrator.d.ts +50 -17
  62. package/hydration/ObjectHydrator.js +483 -418
  63. package/index.d.ts +116 -2
  64. package/index.js +10 -1
  65. package/logging/DefaultLogger.d.ts +34 -32
  66. package/logging/DefaultLogger.js +86 -86
  67. package/logging/Logger.d.ts +41 -41
  68. package/logging/SimpleLogger.d.ts +13 -11
  69. package/logging/SimpleLogger.js +22 -22
  70. package/logging/colors.d.ts +6 -6
  71. package/logging/colors.js +11 -10
  72. package/logging/inspect.js +7 -7
  73. package/metadata/EntitySchema.d.ts +214 -130
  74. package/metadata/EntitySchema.js +411 -412
  75. package/metadata/MetadataDiscovery.d.ts +114 -114
  76. package/metadata/MetadataDiscovery.js +1957 -1879
  77. package/metadata/MetadataProvider.d.ts +29 -26
  78. package/metadata/MetadataProvider.js +95 -97
  79. package/metadata/MetadataStorage.d.ts +38 -32
  80. package/metadata/MetadataStorage.js +118 -118
  81. package/metadata/MetadataValidator.d.ts +39 -39
  82. package/metadata/MetadataValidator.js +381 -338
  83. package/metadata/discover-entities.d.ts +5 -2
  84. package/metadata/discover-entities.js +35 -37
  85. package/metadata/types.d.ts +615 -531
  86. package/naming-strategy/AbstractNamingStrategy.d.ts +54 -39
  87. package/naming-strategy/AbstractNamingStrategy.js +90 -85
  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 +109 -99
  93. package/naming-strategy/UnderscoreNamingStrategy.d.ts +7 -7
  94. package/naming-strategy/UnderscoreNamingStrategy.js +21 -21
  95. package/not-supported.js +7 -4
  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 +312 -303
  100. package/platforms/Platform.js +695 -642
  101. package/serialization/EntitySerializer.d.ts +49 -26
  102. package/serialization/EntitySerializer.js +224 -218
  103. package/serialization/EntityTransformer.d.ts +10 -6
  104. package/serialization/EntityTransformer.js +219 -217
  105. package/serialization/SerializationContext.d.ts +27 -23
  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 +17 -10
  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 +83 -79
  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 +75 -49
  158. package/types/index.js +52 -26
  159. package/typings.d.ts +1254 -741
  160. package/typings.js +244 -233
  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 +187 -179
  165. package/unit-of-work/ChangeSetPersister.d.ts +69 -50
  166. package/unit-of-work/ChangeSetPersister.js +465 -442
  167. package/unit-of-work/CommitOrderCalculator.d.ts +40 -40
  168. package/unit-of-work/CommitOrderCalculator.js +89 -88
  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 +181 -141
  172. package/unit-of-work/UnitOfWork.js +1236 -1222
  173. package/utils/AbstractMigrator.d.ts +111 -91
  174. package/utils/AbstractMigrator.js +275 -275
  175. package/utils/AbstractSchemaGenerator.d.ts +43 -34
  176. package/utils/AbstractSchemaGenerator.js +121 -122
  177. package/utils/AsyncContext.d.ts +3 -3
  178. package/utils/AsyncContext.js +34 -35
  179. package/utils/Configuration.d.ts +852 -808
  180. package/utils/Configuration.js +359 -344
  181. package/utils/Cursor.d.ts +40 -22
  182. package/utils/Cursor.js +135 -127
  183. package/utils/DataloaderUtils.d.ts +58 -43
  184. package/utils/DataloaderUtils.js +203 -198
  185. package/utils/EntityComparator.d.ts +99 -82
  186. package/utils/EntityComparator.js +829 -737
  187. package/utils/NullHighlighter.d.ts +1 -1
  188. package/utils/NullHighlighter.js +3 -3
  189. package/utils/QueryHelper.d.ts +79 -51
  190. package/utils/QueryHelper.js +372 -361
  191. package/utils/RawQueryFragment.d.ts +50 -34
  192. package/utils/RawQueryFragment.js +107 -105
  193. package/utils/RequestContext.d.ts +32 -32
  194. package/utils/RequestContext.js +52 -53
  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 +199 -197
  199. package/utils/Utils.d.ts +204 -145
  200. package/utils/Utils.js +815 -815
  201. package/utils/clone.js +105 -114
  202. package/utils/env-vars.js +90 -88
  203. package/utils/fs-utils.d.ts +15 -15
  204. package/utils/fs-utils.js +180 -181
  205. package/utils/upsert-utils.d.ts +20 -5
  206. package/utils/upsert-utils.js +114 -116
@@ -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,415 +6,414 @@ 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(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
- }
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
+ }
420
419
  }