@mikro-orm/core 7.0.0-dev.33 → 7.0.0-dev.331

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 (218) hide show
  1. package/EntityManager.d.ts +70 -75
  2. package/EntityManager.js +487 -402
  3. package/MikroORM.d.ts +45 -38
  4. package/MikroORM.js +123 -156
  5. package/README.md +7 -4
  6. package/cache/FileCacheAdapter.d.ts +2 -7
  7. package/cache/FileCacheAdapter.js +35 -30
  8. package/cache/GeneratedCacheAdapter.d.ts +1 -2
  9. package/cache/GeneratedCacheAdapter.js +6 -8
  10. package/cache/MemoryCacheAdapter.d.ts +1 -2
  11. package/cache/MemoryCacheAdapter.js +8 -8
  12. package/cache/index.d.ts +1 -2
  13. package/cache/index.js +0 -2
  14. package/connections/Connection.d.ts +12 -5
  15. package/connections/Connection.js +37 -15
  16. package/drivers/DatabaseDriver.d.ts +25 -18
  17. package/drivers/DatabaseDriver.js +144 -45
  18. package/drivers/IDatabaseDriver.d.ts +118 -23
  19. package/entity/BaseEntity.d.ts +63 -4
  20. package/entity/BaseEntity.js +0 -3
  21. package/entity/Collection.d.ts +95 -31
  22. package/entity/Collection.js +487 -139
  23. package/entity/EntityAssigner.js +37 -25
  24. package/entity/EntityFactory.d.ts +8 -9
  25. package/entity/EntityFactory.js +152 -100
  26. package/entity/EntityHelper.d.ts +2 -2
  27. package/entity/EntityHelper.js +69 -27
  28. package/entity/EntityLoader.d.ts +12 -13
  29. package/entity/EntityLoader.js +286 -125
  30. package/entity/EntityRepository.d.ts +28 -8
  31. package/entity/EntityRepository.js +8 -2
  32. package/entity/PolymorphicRef.d.ts +12 -0
  33. package/entity/PolymorphicRef.js +18 -0
  34. package/entity/Reference.d.ts +3 -8
  35. package/entity/Reference.js +62 -29
  36. package/entity/WrappedEntity.d.ts +7 -10
  37. package/entity/WrappedEntity.js +6 -7
  38. package/entity/defineEntity.d.ts +472 -313
  39. package/entity/defineEntity.js +134 -290
  40. package/entity/index.d.ts +2 -2
  41. package/entity/index.js +2 -2
  42. package/entity/utils.d.ts +6 -1
  43. package/entity/utils.js +46 -11
  44. package/entity/validators.d.ts +11 -0
  45. package/entity/validators.js +66 -0
  46. package/enums.d.ts +8 -6
  47. package/enums.js +13 -17
  48. package/errors.d.ts +26 -16
  49. package/errors.js +63 -31
  50. package/events/EventManager.d.ts +3 -5
  51. package/events/EventManager.js +37 -26
  52. package/events/index.d.ts +1 -1
  53. package/events/index.js +0 -1
  54. package/exceptions.js +9 -2
  55. package/hydration/Hydrator.js +1 -2
  56. package/hydration/ObjectHydrator.d.ts +5 -6
  57. package/hydration/ObjectHydrator.js +109 -50
  58. package/index.d.ts +2 -2
  59. package/index.js +1 -2
  60. package/logging/DefaultLogger.d.ts +1 -1
  61. package/logging/DefaultLogger.js +3 -4
  62. package/logging/SimpleLogger.d.ts +1 -1
  63. package/logging/colors.d.ts +1 -1
  64. package/logging/colors.js +4 -6
  65. package/logging/index.d.ts +2 -1
  66. package/logging/index.js +1 -1
  67. package/logging/inspect.d.ts +2 -0
  68. package/logging/inspect.js +11 -0
  69. package/metadata/EntitySchema.d.ts +47 -23
  70. package/metadata/EntitySchema.js +103 -34
  71. package/metadata/MetadataDiscovery.d.ts +65 -18
  72. package/metadata/MetadataDiscovery.js +940 -424
  73. package/metadata/MetadataProvider.d.ts +11 -2
  74. package/metadata/MetadataProvider.js +71 -2
  75. package/metadata/MetadataStorage.d.ts +11 -13
  76. package/metadata/MetadataStorage.js +79 -48
  77. package/metadata/MetadataValidator.d.ts +32 -9
  78. package/metadata/MetadataValidator.js +214 -44
  79. package/metadata/discover-entities.d.ts +5 -0
  80. package/metadata/discover-entities.js +40 -0
  81. package/metadata/index.d.ts +1 -1
  82. package/metadata/index.js +0 -1
  83. package/metadata/types.d.ts +577 -0
  84. package/metadata/types.js +1 -0
  85. package/naming-strategy/AbstractNamingStrategy.d.ts +16 -4
  86. package/naming-strategy/AbstractNamingStrategy.js +26 -5
  87. package/naming-strategy/EntityCaseNamingStrategy.d.ts +3 -3
  88. package/naming-strategy/EntityCaseNamingStrategy.js +7 -6
  89. package/naming-strategy/MongoNamingStrategy.d.ts +3 -3
  90. package/naming-strategy/MongoNamingStrategy.js +6 -6
  91. package/naming-strategy/NamingStrategy.d.ts +28 -4
  92. package/naming-strategy/UnderscoreNamingStrategy.d.ts +3 -3
  93. package/naming-strategy/UnderscoreNamingStrategy.js +6 -6
  94. package/naming-strategy/index.d.ts +1 -1
  95. package/naming-strategy/index.js +0 -1
  96. package/not-supported.d.ts +2 -0
  97. package/not-supported.js +8 -0
  98. package/package.json +47 -36
  99. package/platforms/ExceptionConverter.js +1 -1
  100. package/platforms/Platform.d.ts +33 -15
  101. package/platforms/Platform.js +125 -69
  102. package/serialization/EntitySerializer.d.ts +6 -3
  103. package/serialization/EntitySerializer.js +54 -30
  104. package/serialization/EntityTransformer.js +37 -22
  105. package/serialization/SerializationContext.d.ts +10 -14
  106. package/serialization/SerializationContext.js +24 -19
  107. package/types/ArrayType.d.ts +1 -1
  108. package/types/ArrayType.js +2 -3
  109. package/types/BigIntType.js +1 -1
  110. package/types/BlobType.d.ts +0 -1
  111. package/types/BlobType.js +0 -3
  112. package/types/BooleanType.d.ts +1 -0
  113. package/types/BooleanType.js +3 -0
  114. package/types/DecimalType.js +2 -2
  115. package/types/DoubleType.js +1 -1
  116. package/types/EnumArrayType.js +1 -2
  117. package/types/JsonType.d.ts +1 -1
  118. package/types/JsonType.js +7 -2
  119. package/types/TinyIntType.js +1 -1
  120. package/types/Type.d.ts +2 -4
  121. package/types/Type.js +3 -3
  122. package/types/Uint8ArrayType.d.ts +0 -1
  123. package/types/Uint8ArrayType.js +1 -4
  124. package/types/UuidType.d.ts +2 -0
  125. package/types/UuidType.js +14 -2
  126. package/types/index.d.ts +3 -2
  127. package/typings.d.ts +427 -170
  128. package/typings.js +100 -45
  129. package/unit-of-work/ChangeSet.d.ts +4 -6
  130. package/unit-of-work/ChangeSet.js +8 -9
  131. package/unit-of-work/ChangeSetComputer.d.ts +2 -12
  132. package/unit-of-work/ChangeSetComputer.js +61 -38
  133. package/unit-of-work/ChangeSetPersister.d.ts +10 -17
  134. package/unit-of-work/ChangeSetPersister.js +136 -73
  135. package/unit-of-work/CommitOrderCalculator.d.ts +13 -14
  136. package/unit-of-work/CommitOrderCalculator.js +22 -20
  137. package/unit-of-work/IdentityMap.d.ts +12 -3
  138. package/unit-of-work/IdentityMap.js +51 -13
  139. package/unit-of-work/UnitOfWork.d.ts +39 -23
  140. package/unit-of-work/UnitOfWork.js +441 -246
  141. package/utils/AbstractMigrator.d.ts +101 -0
  142. package/utils/AbstractMigrator.js +303 -0
  143. package/utils/AbstractSchemaGenerator.d.ts +5 -5
  144. package/utils/AbstractSchemaGenerator.js +30 -18
  145. package/utils/AsyncContext.d.ts +6 -0
  146. package/utils/AsyncContext.js +42 -0
  147. package/utils/Configuration.d.ts +647 -185
  148. package/utils/Configuration.js +215 -252
  149. package/utils/ConfigurationLoader.d.ts +1 -52
  150. package/utils/ConfigurationLoader.js +1 -330
  151. package/utils/Cursor.d.ts +3 -6
  152. package/utils/Cursor.js +32 -17
  153. package/utils/DataloaderUtils.d.ts +10 -5
  154. package/utils/DataloaderUtils.js +42 -22
  155. package/utils/EntityComparator.d.ts +21 -21
  156. package/utils/EntityComparator.js +224 -118
  157. package/utils/QueryHelper.d.ts +34 -7
  158. package/utils/QueryHelper.js +183 -72
  159. package/utils/RawQueryFragment.d.ts +28 -34
  160. package/utils/RawQueryFragment.js +37 -72
  161. package/utils/RequestContext.js +2 -2
  162. package/utils/TransactionContext.js +2 -2
  163. package/utils/TransactionManager.js +11 -8
  164. package/utils/Utils.d.ts +16 -127
  165. package/utils/Utils.js +104 -402
  166. package/utils/clone.js +13 -23
  167. package/utils/env-vars.d.ts +7 -0
  168. package/utils/env-vars.js +98 -0
  169. package/utils/fs-utils.d.ts +20 -0
  170. package/utils/fs-utils.js +193 -0
  171. package/utils/index.d.ts +1 -3
  172. package/utils/index.js +1 -3
  173. package/utils/upsert-utils.d.ts +9 -4
  174. package/utils/upsert-utils.js +51 -5
  175. package/decorators/Check.d.ts +0 -3
  176. package/decorators/Check.js +0 -13
  177. package/decorators/CreateRequestContext.d.ts +0 -3
  178. package/decorators/CreateRequestContext.js +0 -32
  179. package/decorators/Embeddable.d.ts +0 -8
  180. package/decorators/Embeddable.js +0 -11
  181. package/decorators/Embedded.d.ts +0 -12
  182. package/decorators/Embedded.js +0 -18
  183. package/decorators/Entity.d.ts +0 -33
  184. package/decorators/Entity.js +0 -12
  185. package/decorators/Enum.d.ts +0 -9
  186. package/decorators/Enum.js +0 -16
  187. package/decorators/Filter.d.ts +0 -2
  188. package/decorators/Filter.js +0 -8
  189. package/decorators/Formula.d.ts +0 -4
  190. package/decorators/Formula.js +0 -15
  191. package/decorators/Indexed.d.ts +0 -19
  192. package/decorators/Indexed.js +0 -20
  193. package/decorators/ManyToMany.d.ts +0 -42
  194. package/decorators/ManyToMany.js +0 -14
  195. package/decorators/ManyToOne.d.ts +0 -34
  196. package/decorators/ManyToOne.js +0 -14
  197. package/decorators/OneToMany.d.ts +0 -28
  198. package/decorators/OneToMany.js +0 -17
  199. package/decorators/OneToOne.d.ts +0 -28
  200. package/decorators/OneToOne.js +0 -7
  201. package/decorators/PrimaryKey.d.ts +0 -8
  202. package/decorators/PrimaryKey.js +0 -20
  203. package/decorators/Property.d.ts +0 -250
  204. package/decorators/Property.js +0 -32
  205. package/decorators/Transactional.d.ts +0 -14
  206. package/decorators/Transactional.js +0 -28
  207. package/decorators/hooks.d.ts +0 -16
  208. package/decorators/hooks.js +0 -47
  209. package/decorators/index.d.ts +0 -17
  210. package/decorators/index.js +0 -17
  211. package/entity/ArrayCollection.d.ts +0 -118
  212. package/entity/ArrayCollection.js +0 -407
  213. package/entity/EntityValidator.d.ts +0 -19
  214. package/entity/EntityValidator.js +0 -150
  215. package/metadata/ReflectMetadataProvider.d.ts +0 -8
  216. package/metadata/ReflectMetadataProvider.js +0 -44
  217. package/utils/resolveContextProvider.d.ts +0 -10
  218. package/utils/resolveContextProvider.js +0 -28
package/typings.js CHANGED
@@ -1,14 +1,18 @@
1
1
  import { ReferenceKind, } from './enums.js';
2
2
  import { Reference } from './entity/Reference.js';
3
3
  import { EntityHelper } from './entity/EntityHelper.js';
4
+ import { helper } from './entity/wrap.js';
4
5
  import { Utils } from './utils/Utils.js';
5
6
  import { EntityComparator } from './utils/EntityComparator.js';
7
+ import { BaseEntity } from './entity/BaseEntity.js';
6
8
  export const EntityRepositoryType = Symbol('EntityRepositoryType');
7
9
  export const PrimaryKeyProp = Symbol('PrimaryKeyProp');
8
10
  export const OptionalProps = Symbol('OptionalProps');
9
11
  export const EagerProps = Symbol('EagerProps');
10
12
  export const HiddenProps = Symbol('HiddenProps');
11
13
  export const Config = Symbol('Config');
14
+ // eslint-disable-next-line @typescript-eslint/no-redeclare
15
+ export const EntityName = Symbol('EntityName');
12
16
  export class EntityMetadata {
13
17
  static counter = 0;
14
18
  _id = 1000 * EntityMetadata.counter++; // keep the id >= 1000 to allow computing cache keys by simple addition
@@ -25,22 +29,22 @@ export class EntityMetadata {
25
29
  this.referencingProperties = [];
26
30
  this.concurrencyCheckKeys = new Set();
27
31
  Object.assign(this, meta);
28
- }
29
- addProperty(prop, sync = true) {
30
- if (prop.pivotTable && !prop.pivotEntity) {
31
- prop.pivotEntity = prop.pivotTable;
32
+ const name = meta.className ?? meta.name;
33
+ if (!this.class && name) {
34
+ const Class = this.extends === BaseEntity ? { [name]: class extends BaseEntity {
35
+ } }[name] : { [name]: class {
36
+ } }[name];
37
+ this.class = Class;
32
38
  }
39
+ }
40
+ addProperty(prop) {
33
41
  this.properties[prop.name] = prop;
34
42
  this.propertyOrder.set(prop.name, this.props.length);
35
- /* v8 ignore next 3 */
36
- if (sync) {
37
- this.sync();
38
- }
43
+ this.sync();
39
44
  }
40
45
  removeProperty(name, sync = true) {
41
46
  delete this.properties[name];
42
47
  this.propertyOrder.delete(name);
43
- /* v8 ignore next 3 */
44
48
  if (sync) {
45
49
  this.sync();
46
50
  }
@@ -60,8 +64,50 @@ export class EntityMetadata {
60
64
  getPrimaryProp() {
61
65
  return this.properties[this.primaryKeys[0]];
62
66
  }
63
- createColumnMappingObject() {
64
- return Object.values(this.properties).reduce((o, prop) => {
67
+ /**
68
+ * Creates a mapping from property names to field names.
69
+ * @param alias - Optional alias to prefix field names. Can be a string (same for all) or a function (per-property).
70
+ * When provided, also adds toString() returning the alias for backwards compatibility with formulas.
71
+ * @param toStringAlias - Optional alias to return from toString(). Defaults to `alias` when it's a string.
72
+ */
73
+ createColumnMappingObject(alias, toStringAlias) {
74
+ const resolveAlias = typeof alias === 'function' ? alias : () => alias;
75
+ const defaultAlias = toStringAlias ?? (typeof alias === 'string' ? alias : undefined);
76
+ const result = Object.values(this.properties).reduce((o, prop) => {
77
+ if (prop.fieldNames) {
78
+ const propAlias = resolveAlias(prop);
79
+ o[prop.name] = propAlias ? `${propAlias}.${prop.fieldNames[0]}` : prop.fieldNames[0];
80
+ }
81
+ return o;
82
+ }, {});
83
+ // Add toString() for backwards compatibility when alias is provided
84
+ Object.defineProperty(result, 'toString', {
85
+ value: () => defaultAlias ?? '',
86
+ enumerable: false,
87
+ });
88
+ // Wrap in Proxy to detect old formula signature usage where the first param was FormulaTable.
89
+ // If user accesses `.alias` or `.qualifiedName` (FormulaTable-only properties), warn them.
90
+ const warnedProps = new Set(['alias', 'qualifiedName']);
91
+ return new Proxy(result, {
92
+ get(target, prop, receiver) {
93
+ if (typeof prop === 'string' && warnedProps.has(prop) && !(prop in target)) {
94
+ // eslint-disable-next-line no-console
95
+ console.warn(`[MikroORM] Detected old formula callback signature. The first parameter is now 'columns', not 'table'. ` +
96
+ `Accessing '.${prop}' on the columns object will return undefined. ` +
97
+ `Update your formula: formula(cols => quote\`\${cols.propName} ...\`). See the v7 upgrade guide.`);
98
+ }
99
+ return Reflect.get(target, prop, receiver);
100
+ },
101
+ });
102
+ }
103
+ /**
104
+ * Creates a column mapping for schema callbacks (indexes, checks, generated columns).
105
+ * For TPT entities, only includes properties that belong to the current table (ownProps).
106
+ */
107
+ createSchemaColumnMappingObject() {
108
+ // For TPT entities, only include properties that belong to this entity's table
109
+ const props = this.inheritanceType === 'tpt' && this.ownProps ? this.ownProps : Object.values(this.properties);
110
+ return props.reduce((o, prop) => {
65
111
  if (prop.fieldNames) {
66
112
  o[prop.name] = prop.fieldNames[0];
67
113
  }
@@ -74,6 +120,9 @@ export class EntityMetadata {
74
120
  set tableName(name) {
75
121
  this.collection = name;
76
122
  }
123
+ get uniqueName() {
124
+ return this.tableName + '_' + this._id;
125
+ }
77
126
  sync(initIndexes = false, config) {
78
127
  this.root ??= this;
79
128
  const props = Object.values(this.properties).sort((a, b) => this.propertyOrder.get(a.name) - this.propertyOrder.get(b.name));
@@ -83,6 +132,12 @@ export class EntityMetadata {
83
132
  this.uniqueProps = this.props.filter(prop => prop.unique);
84
133
  this.getterProps = this.props.filter(prop => prop.getter);
85
134
  this.comparableProps = this.props.filter(prop => EntityComparator.isComparable(prop, this));
135
+ this.validateProps = this.props.filter(prop => {
136
+ if (prop.inherited || (prop.persist === false && prop.userDefined !== false)) {
137
+ return false;
138
+ }
139
+ return prop.kind === ReferenceKind.SCALAR && ['string', 'number', 'boolean', 'Date'].includes(prop.type);
140
+ });
86
141
  this.hydrateProps = this.props.filter(prop => {
87
142
  // `prop.userDefined` is either `undefined` or `false`
88
143
  const discriminator = this.root.discriminatorColumn === prop.name && prop.userDefined === false;
@@ -90,16 +145,26 @@ export class EntityMetadata {
90
145
  const onlyGetter = prop.getter && !prop.setter && prop.persist === false;
91
146
  return !prop.inherited && prop.hydrate !== false && !discriminator && !prop.embedded && !onlyGetter;
92
147
  });
93
- this.trackingProps = this.hydrateProps
94
- .filter(prop => !prop.getter && !prop.setter && prop.trackChanges !== false)
95
- .filter(prop => ![ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(prop.kind))
96
- .filter(prop => !prop.serializedPrimaryKey);
97
- this.selfReferencing = this.relations.some(prop => [this.className, this.root.className].includes(prop.targetMeta?.root.className ?? prop.type));
148
+ this.trackingProps = this.hydrateProps.filter(prop => {
149
+ return !prop.getter && !prop.setter && [ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind);
150
+ });
151
+ this.selfReferencing = this.relations.some(prop => {
152
+ return this.root.uniqueName === prop.targetMeta?.root.uniqueName;
153
+ });
98
154
  this.hasUniqueProps = this.uniques.length + this.uniqueProps.length > 0;
99
- this.virtual = !!this.expression;
155
+ // Normalize object-form `view` option: `view: { materialized: true, withData: false }`
156
+ // into flat metadata fields (`view: true`, `materialized: true`, `withData: false`).
157
+ if (typeof this.view === 'object') {
158
+ this.materialized = this.view.materialized;
159
+ this.withData = this.view.withData;
160
+ this.view = true;
161
+ }
162
+ // If `view` is set, this is a database view entity (not a virtual entity).
163
+ // Virtual entities evaluate expressions at query time, view entities create actual database views.
164
+ this.virtual = !!this.expression && !this.view;
100
165
  if (config) {
101
166
  for (const prop of this.props) {
102
- if (prop.enum && !prop.nativeEnumName && prop.items?.every(item => Utils.isString(item))) {
167
+ if (prop.enum && !prop.nativeEnumName && prop.items?.every(item => typeof item === 'string')) {
103
168
  const name = config.getNamingStrategy().indexName(this.tableName, prop.fieldNames, 'check');
104
169
  const exists = this.checks.findIndex(check => check.name === name);
105
170
  if (exists !== -1) {
@@ -119,16 +184,15 @@ export class EntityMetadata {
119
184
  for (const hook of Utils.keys(this.hooks)) {
120
185
  this.hooks[hook] = Utils.removeDuplicates(this.hooks[hook]);
121
186
  }
122
- if (this.virtual) {
187
+ if (this.virtual || this.view) {
123
188
  this.readonly = true;
124
189
  }
125
190
  if (initIndexes && this.name) {
126
191
  this.props.forEach(prop => this.initIndexes(prop));
127
192
  }
128
193
  this.definedProperties = this.trackingProps.reduce((o, prop) => {
129
- const isCollection = [ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(prop.kind);
130
- const isReference = [ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(prop.kind) && (prop.inversedBy || prop.mappedBy) && !prop.mapToPk;
131
- if (isReference) {
194
+ const hasInverse = (prop.inversedBy || prop.mappedBy) && !prop.mapToPk;
195
+ if (hasInverse) {
132
196
  // eslint-disable-next-line @typescript-eslint/no-this-alias
133
197
  const meta = this;
134
198
  o[prop.name] = {
@@ -140,16 +204,20 @@ export class EntityMetadata {
140
204
  const hydrator = wrapped.hydrator;
141
205
  const entity = Reference.unwrapReference(val ?? wrapped.__data[prop.name]);
142
206
  const old = Reference.unwrapReference(wrapped.__data[prop.name]);
143
- if (old && old !== entity && prop.kind === ReferenceKind.MANY_TO_ONE && prop.inversedBy && old[prop.inversedBy]) {
207
+ if (old &&
208
+ old !== entity &&
209
+ prop.kind === ReferenceKind.MANY_TO_ONE &&
210
+ prop.inversedBy &&
211
+ old[prop.inversedBy]) {
144
212
  old[prop.inversedBy].removeWithoutPropagation(this);
145
213
  }
146
214
  wrapped.__data[prop.name] = Reference.wrapReference(val, prop);
147
215
  // when propagation from inside hydration, we set the FK to the entity data immediately
148
216
  if (val && hydrator.isRunning() && wrapped.__originalEntityData && prop.owner) {
149
- wrapped.__originalEntityData[prop.name] = Utils.getPrimaryKeyValues(val, prop.targetMeta, true);
150
- }
151
- else {
152
- wrapped.__touched = !hydrator.isRunning();
217
+ const targetMeta = prop.targetMeta ?? helper(entity)?.__meta;
218
+ if (targetMeta) {
219
+ wrapped.__originalEntityData[prop.name] = Utils.getPrimaryKeyValues(val, targetMeta, true);
220
+ }
153
221
  }
154
222
  EntityHelper.propagate(meta, entity, this, prop, Reference.unwrapReference(val), old);
155
223
  },
@@ -157,23 +225,6 @@ export class EntityMetadata {
157
225
  configurable: true,
158
226
  };
159
227
  }
160
- if (prop.inherited || prop.primary || isCollection || prop.persist === false || prop.trackChanges === false || isReference || prop.embedded) {
161
- return o;
162
- }
163
- o[prop.name] = {
164
- get() {
165
- return this.__helper.__data[prop.name];
166
- },
167
- set(val) {
168
- if (typeof val === 'object' && !!val && '__raw' in val) {
169
- val.assign();
170
- }
171
- this.__helper.__data[prop.name] = val;
172
- this.__helper.__touched = !this.__helper.hydrator.isRunning();
173
- },
174
- enumerable: true,
175
- configurable: true,
176
- };
177
228
  return o;
178
229
  }, { __gettersDefined: { value: true, enumerable: false } });
179
230
  }
@@ -195,7 +246,7 @@ export class EntityMetadata {
195
246
  this.indexes.push({ properties: prop.name });
196
247
  prop.index = false;
197
248
  }
198
- /* v8 ignore next 4 */
249
+ /* v8 ignore next */
199
250
  if (owner && prop.fieldNames.length > 1 && prop.unique) {
200
251
  this.uniques.push({ properties: prop.name });
201
252
  prop.unique = false;
@@ -205,4 +256,8 @@ export class EntityMetadata {
205
256
  clone() {
206
257
  return this;
207
258
  }
259
+ /** @ignore */
260
+ [Symbol.for('nodejs.util.inspect.custom')]() {
261
+ return `[${this.constructor.name}<${this.className}>]`;
262
+ }
208
263
  }
@@ -1,4 +1,3 @@
1
- import { inspect } from 'node:util';
2
1
  import type { EntityData, EntityMetadata, EntityDictionary, Primary } from '../typings.js';
3
2
  export declare class ChangeSet<T extends object> {
4
3
  entity: T;
@@ -10,19 +9,18 @@ export declare class ChangeSet<T extends object> {
10
9
  constructor(entity: T, type: ChangeSetType, payload: EntityDictionary<T>, meta: EntityMetadata<T>);
11
10
  getPrimaryKey(object?: boolean): Primary<T> | null;
12
11
  getSerializedPrimaryKey(): string | null;
13
- /** @ignore */
14
- [inspect.custom](depth?: number): string;
15
12
  }
16
13
  export interface ChangeSet<T> {
17
- name: string;
18
- rootName: string;
19
- collection: string;
14
+ meta: EntityMetadata<T>;
15
+ rootMeta: EntityMetadata<T>;
20
16
  schema?: string;
21
17
  type: ChangeSetType;
22
18
  entity: T;
23
19
  payload: EntityDictionary<T>;
24
20
  persisted: boolean;
25
21
  originalEntity?: EntityData<T>;
22
+ /** For TPT: changesets for parent tables, ordered from immediate parent to root */
23
+ tptChangeSets?: ChangeSet<T>[];
26
24
  }
27
25
  export declare enum ChangeSetType {
28
26
  CREATE = "create",
@@ -1,6 +1,6 @@
1
- import { inspect } from 'node:util';
2
1
  import { helper } from '../entity/wrap.js';
3
2
  import { Utils } from '../utils/Utils.js';
3
+ import { inspect } from '../logging/inspect.js';
4
4
  export class ChangeSet {
5
5
  entity;
6
6
  type;
@@ -13,9 +13,8 @@ export class ChangeSet {
13
13
  this.type = type;
14
14
  this.payload = payload;
15
15
  this.meta = meta;
16
- this.name = meta.className;
17
- this.rootName = meta.root.className;
18
- this.collection = meta.root.collection;
16
+ this.meta = meta;
17
+ this.rootMeta = meta.root;
19
18
  this.schema = helper(entity).__schema ?? meta.root.schema;
20
19
  }
21
20
  getPrimaryKey(object = false) {
@@ -28,10 +27,10 @@ export class ChangeSet {
28
27
  else {
29
28
  this.primaryKey = this.originalEntity[this.meta.primaryKeys[0]];
30
29
  }
31
- if (!this.meta.compositePK
32
- && this.meta.getPrimaryProp().targetMeta?.compositePK
33
- && typeof this.primaryKey === 'object'
34
- && this.primaryKey !== null) {
30
+ if (!this.meta.compositePK &&
31
+ this.meta.getPrimaryProp().targetMeta?.compositePK &&
32
+ typeof this.primaryKey === 'object' &&
33
+ this.primaryKey !== null) {
35
34
  this.primaryKey = this.meta.getPrimaryProp().targetMeta.primaryKeys.map(childPK => {
36
35
  return this.primaryKey[childPK];
37
36
  });
@@ -46,7 +45,7 @@ export class ChangeSet {
46
45
  return this.serializedPrimaryKey;
47
46
  }
48
47
  /** @ignore */
49
- [inspect.custom](depth = 2) {
48
+ [Symbol.for('nodejs.util.inspect.custom')](depth = 2) {
50
49
  const object = { ...this };
51
50
  const hidden = ['meta', 'serializedPrimaryKey'];
52
51
  hidden.forEach(k => delete object[k]);
@@ -1,20 +1,10 @@
1
- import { type Configuration } from '../utils/Configuration.js';
2
- import type { MetadataStorage } from '../metadata/MetadataStorage.js';
3
1
  import type { AnyEntity } from '../typings.js';
4
2
  import { ChangeSet } from './ChangeSet.js';
5
- import { type EntityValidator } from '../entity/EntityValidator.js';
6
3
  import { type Collection } from '../entity/Collection.js';
7
- import type { Platform } from '../platforms/Platform.js';
8
4
  import type { EntityManager } from '../EntityManager.js';
9
5
  export declare class ChangeSetComputer {
10
- private readonly validator;
11
- private readonly collectionUpdates;
12
- private readonly metadata;
13
- private readonly platform;
14
- private readonly config;
15
- private readonly em;
16
- private readonly comparator;
17
- constructor(validator: EntityValidator, collectionUpdates: Set<Collection<AnyEntity>>, metadata: MetadataStorage, platform: Platform, config: Configuration, em: EntityManager);
6
+ #private;
7
+ constructor(em: EntityManager, collectionUpdates: Set<Collection<AnyEntity>>);
18
8
  computeChangeSet<T extends object>(entity: T): ChangeSet<T> | null;
19
9
  /**
20
10
  * Traverses entity graph and executes `onCreate` and `onUpdate` methods, assigning the values to given properties.
@@ -1,26 +1,28 @@
1
1
  import { Utils } from '../utils/Utils.js';
2
+ import { QueryHelper } from '../utils/QueryHelper.js';
2
3
  import { ChangeSet, ChangeSetType } from './ChangeSet.js';
3
4
  import { helper } from '../entity/wrap.js';
5
+ import { validateEntity } from '../entity/validators.js';
6
+ import { Reference } from '../entity/Reference.js';
7
+ import { PolymorphicRef } from '../entity/PolymorphicRef.js';
4
8
  import { ReferenceKind } from '../enums.js';
5
9
  export class ChangeSetComputer {
6
- validator;
7
- collectionUpdates;
8
- metadata;
9
- platform;
10
- config;
11
- em;
12
- comparator;
13
- constructor(validator, collectionUpdates, metadata, platform, config, em) {
14
- this.validator = validator;
15
- this.collectionUpdates = collectionUpdates;
16
- this.metadata = metadata;
17
- this.platform = platform;
18
- this.config = config;
19
- this.em = em;
20
- this.comparator = this.config.getComparator(this.metadata);
10
+ #comparator;
11
+ #metadata;
12
+ #platform;
13
+ #config;
14
+ #em;
15
+ #collectionUpdates;
16
+ constructor(em, collectionUpdates) {
17
+ this.#em = em;
18
+ this.#collectionUpdates = collectionUpdates;
19
+ this.#config = this.#em.config;
20
+ this.#metadata = this.#em.getMetadata();
21
+ this.#platform = this.#em.getPlatform();
22
+ this.#comparator = this.#config.getComparator(this.#metadata);
21
23
  }
22
24
  computeChangeSet(entity) {
23
- const meta = this.metadata.get(entity.constructor.name);
25
+ const meta = this.#metadata.get(entity.constructor);
24
26
  if (meta.readonly) {
25
27
  return null;
26
28
  }
@@ -29,25 +31,27 @@ export class ChangeSetComputer {
29
31
  const map = new Map();
30
32
  // Execute `onCreate` and `onUpdate` on properties recursively, saves `onUpdate` results
31
33
  // to the `map` as we want to apply those only if something else changed.
32
- if (type === ChangeSetType.CREATE) { // run update hooks only after we know there are other changes
34
+ if (type === ChangeSetType.CREATE) {
35
+ // run update hooks only after we know there are other changes
33
36
  for (const prop of meta.hydrateProps) {
34
37
  this.processPropertyInitializers(entity, prop, type, map);
35
38
  }
36
39
  }
37
- if (type === ChangeSetType.UPDATE && !wrapped.__initialized && !wrapped.isTouched()) {
38
- return null;
40
+ if (type === ChangeSetType.UPDATE && !wrapped.__initialized) {
41
+ const data = this.#comparator.prepareEntity(entity);
42
+ if (Utils.equals(data, wrapped.__originalEntityData)) {
43
+ return null;
44
+ }
39
45
  }
40
46
  const changeSet = new ChangeSet(entity, type, this.computePayload(entity), meta);
41
47
  changeSet.originalEntity = wrapped.__originalEntityData;
42
- if (this.config.get('validate')) {
43
- this.validator.validate(changeSet.entity, changeSet.payload, meta);
44
- }
45
48
  for (const prop of meta.relations.filter(prop => prop.persist !== false || prop.userDefined === false)) {
46
49
  this.processProperty(changeSet, prop);
47
50
  }
48
51
  if (changeSet.type === ChangeSetType.UPDATE && !Utils.hasObjectKeys(changeSet.payload)) {
49
52
  return null;
50
53
  }
54
+ validateEntity(changeSet.entity, meta);
51
55
  // Execute `onCreate` and `onUpdate` on properties recursively, saves `onUpdate` results
52
56
  // to the `map` as we want to apply those only if something else changed.
53
57
  if (type === ChangeSetType.UPDATE) {
@@ -71,15 +75,15 @@ export class ChangeSetComputer {
71
75
  * Traverses entity graph and executes `onCreate` and `onUpdate` methods, assigning the values to given properties.
72
76
  */
73
77
  processPropertyInitializers(entity, prop, type, map, nested) {
74
- if (prop.onCreate
75
- && type === ChangeSetType.CREATE
76
- && (entity[prop.name] == null
77
- || (Utils.isScalarReference(entity[prop.name]) && entity[prop.name].unwrap() == null))) {
78
- entity[prop.name] = prop.onCreate(entity, this.em);
78
+ if (prop.onCreate &&
79
+ type === ChangeSetType.CREATE &&
80
+ (entity[prop.name] == null ||
81
+ (Utils.isScalarReference(entity[prop.name]) && entity[prop.name].unwrap() == null))) {
82
+ entity[prop.name] = prop.onCreate(entity, this.#em);
79
83
  }
80
84
  if (prop.onUpdate && type === ChangeSetType.UPDATE) {
81
85
  const pairs = map.get(entity) ?? [];
82
- pairs.push([prop.name, prop.onUpdate(entity, this.em)]);
86
+ pairs.push([prop.name, prop.onUpdate(entity, this.#em)]);
83
87
  map.set(entity, pairs);
84
88
  }
85
89
  if (prop.kind === ReferenceKind.EMBEDDED && entity[prop.name]) {
@@ -89,9 +93,9 @@ export class ChangeSetComputer {
89
93
  }
90
94
  }
91
95
  computePayload(entity, ignoreUndefined = false) {
92
- const data = this.comparator.prepareEntity(entity);
96
+ const data = this.#comparator.prepareEntity(entity);
93
97
  const wrapped = helper(entity);
94
- const entityName = wrapped.__meta.className;
98
+ const entityName = wrapped.__meta.class;
95
99
  const originalEntityData = wrapped.__originalEntityData;
96
100
  if (!wrapped.__initialized) {
97
101
  for (const prop of wrapped.__meta.primaryKeys) {
@@ -100,7 +104,7 @@ export class ChangeSetComputer {
100
104
  return data;
101
105
  }
102
106
  if (originalEntityData) {
103
- const comparator = this.comparator.getEntityComparator(entityName);
107
+ const comparator = this.#comparator.getEntityComparator(entityName);
104
108
  const diff = comparator(originalEntityData, data);
105
109
  if (ignoreUndefined) {
106
110
  Utils.keys(diff)
@@ -117,7 +121,8 @@ export class ChangeSetComputer {
117
121
  targets.forEach(([t]) => this.processProperty(changeSet, prop, t));
118
122
  return;
119
123
  }
120
- if (Utils.isCollection(target)) { // m:n or 1:m
124
+ if (Utils.isCollection(target)) {
125
+ // m:n or 1:m
121
126
  this.processToMany(prop, changeSet);
122
127
  }
123
128
  if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind)) {
@@ -130,9 +135,25 @@ export class ChangeSetComputer {
130
135
  return;
131
136
  }
132
137
  const targets = Utils.unwrapProperty(changeSet.entity, changeSet.meta, prop);
133
- targets.forEach(([target, idx]) => {
134
- if (!target.__helper.hasPrimaryKey()) {
135
- Utils.setPayloadProperty(changeSet.payload, this.metadata.find(changeSet.name), prop, target.__helper.__identifier, idx);
138
+ targets.forEach(([rawTarget, idx]) => {
139
+ const target = Reference.unwrapReference(rawTarget);
140
+ const needsProcessing = target != null && (prop.targetKey != null || !target.__helper.hasPrimaryKey());
141
+ if (needsProcessing) {
142
+ let value = prop.targetKey ? target[prop.targetKey] : target.__helper.__identifier;
143
+ /* v8 ignore next */
144
+ if (prop.targetKey && prop.targetMeta) {
145
+ const targetProp = prop.targetMeta.properties[prop.targetKey];
146
+ if (targetProp?.customType) {
147
+ value = targetProp.customType.convertToDatabaseValue(value, this.#platform, { mode: 'serialization' });
148
+ }
149
+ }
150
+ if (prop.polymorphic) {
151
+ const discriminator = QueryHelper.findDiscriminatorValue(prop.discriminatorMap, target.constructor);
152
+ Utils.setPayloadProperty(changeSet.payload, changeSet.meta, prop, new PolymorphicRef(discriminator, value), idx);
153
+ }
154
+ else {
155
+ Utils.setPayloadProperty(changeSet.payload, changeSet.meta, prop, value, idx);
156
+ }
136
157
  }
137
158
  });
138
159
  }
@@ -142,10 +163,12 @@ export class ChangeSetComputer {
142
163
  return;
143
164
  }
144
165
  if (target.isDirty()) {
145
- this.collectionUpdates.add(target);
166
+ this.#collectionUpdates.add(target);
146
167
  }
147
- if (prop.owner && !this.platform.usesPivotTable()) {
148
- changeSet.payload[prop.name] = target.getItems(false).map((item) => item.__helper.__identifier ?? item.__helper.getPrimaryKey());
168
+ if (prop.owner && !this.#platform.usesPivotTable()) {
169
+ changeSet.payload[prop.name] = target.getItems(false).map((item) => {
170
+ return item.__helper.__identifier ?? item.__helper.getPrimaryKey();
171
+ });
149
172
  }
150
173
  }
151
174
  }
@@ -1,27 +1,15 @@
1
- import type { MetadataStorage } from '../metadata/MetadataStorage.js';
2
- import type { Dictionary, EntityDictionary, EntityMetadata, IHydrator } from '../typings.js';
3
- import { type EntityFactory } from '../entity/EntityFactory.js';
4
- import { type EntityValidator } from '../entity/EntityValidator.js';
1
+ import type { Dictionary, EntityDictionary, EntityMetadata } from '../typings.js';
5
2
  import { type ChangeSet } from './ChangeSet.js';
6
- import { type Configuration } from '../utils/Configuration.js';
7
- import type { DriverMethodOptions, IDatabaseDriver } from '../drivers/IDatabaseDriver.js';
3
+ import type { DriverMethodOptions } from '../drivers/IDatabaseDriver.js';
8
4
  import type { EntityManager } from '../EntityManager.js';
9
5
  export declare class ChangeSetPersister {
10
- private readonly driver;
11
- private readonly metadata;
12
- private readonly hydrator;
13
- private readonly factory;
14
- private readonly validator;
15
- private readonly config;
16
- private readonly em;
17
- private readonly platform;
18
- private readonly comparator;
19
- private readonly usesReturningStatement;
20
- constructor(driver: IDatabaseDriver, metadata: MetadataStorage, hydrator: IHydrator, factory: EntityFactory, validator: EntityValidator, config: Configuration, em: EntityManager);
6
+ #private;
7
+ constructor(em: EntityManager);
21
8
  executeInserts<T extends object>(changeSets: ChangeSet<T>[], options?: DriverMethodOptions, withSchema?: boolean): Promise<void>;
22
9
  executeUpdates<T extends object>(changeSets: ChangeSet<T>[], batched: boolean, options?: DriverMethodOptions, withSchema?: boolean): Promise<void>;
23
10
  executeDeletes<T extends object>(changeSets: ChangeSet<T>[], options?: DriverMethodOptions, withSchema?: boolean): Promise<void>;
24
11
  private runForEachSchema;
12
+ private validateRequired;
25
13
  private processProperties;
26
14
  private persistNewEntity;
27
15
  private persistNewEntities;
@@ -44,6 +32,11 @@ export declare class ChangeSetPersister {
44
32
  * so we use a single query in case of both versioning and default values is used.
45
33
  */
46
34
  private reloadVersionValues;
35
+ /**
36
+ * For TPT child tables, resolve EntityIdentifier values in PK fields.
37
+ * The parent table insert assigns the actual PK value, which the child table references.
38
+ */
39
+ private resolveTPTIdentifiers;
47
40
  private processProperty;
48
41
  /**
49
42
  * Maps values returned via `returning` statement (postgres) or the inserted id (other sql drivers).