@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
@@ -1,40 +1,39 @@
1
1
  import { EntityIdentifier } from '../entity/EntityIdentifier.js';
2
+ import { PolymorphicRef } from '../entity/PolymorphicRef.js';
2
3
  import { helper } from '../entity/wrap.js';
3
4
  import { ChangeSetType } from './ChangeSet.js';
4
5
  import { isRaw } from '../utils/RawQueryFragment.js';
5
6
  import { Utils } from '../utils/Utils.js';
6
- import { OptimisticLockError } from '../errors.js';
7
+ import { OptimisticLockError, ValidationError } from '../errors.js';
7
8
  import { ReferenceKind } from '../enums.js';
8
9
  export class ChangeSetPersister {
9
- driver;
10
- metadata;
11
- hydrator;
12
- factory;
13
- validator;
14
- config;
15
- em;
16
- platform;
17
- comparator;
18
- usesReturningStatement;
19
- constructor(driver, metadata, hydrator, factory, validator, config, em) {
20
- this.driver = driver;
21
- this.metadata = metadata;
22
- this.hydrator = hydrator;
23
- this.factory = factory;
24
- this.validator = validator;
25
- this.config = config;
26
- this.em = em;
27
- this.platform = this.driver.getPlatform();
28
- this.comparator = this.config.getComparator(this.metadata);
29
- this.usesReturningStatement = this.platform.usesReturningStatement() || this.platform.usesOutputStatement();
10
+ #platform;
11
+ #comparator;
12
+ #usesReturningStatement;
13
+ #driver;
14
+ #metadata;
15
+ #hydrator;
16
+ #factory;
17
+ #config;
18
+ #em;
19
+ constructor(em) {
20
+ this.#em = em;
21
+ this.#driver = this.#em.getDriver();
22
+ this.#config = this.#em.config;
23
+ this.#metadata = this.#em.getMetadata();
24
+ this.#factory = this.#em.getEntityFactory();
25
+ this.#platform = this.#driver.getPlatform();
26
+ this.#hydrator = this.#config.getHydrator(this.#metadata);
27
+ this.#comparator = this.#config.getComparator(this.#metadata);
28
+ this.#usesReturningStatement = this.#platform.usesReturningStatement() || this.#platform.usesOutputStatement();
30
29
  }
31
30
  async executeInserts(changeSets, options, withSchema) {
32
31
  if (!withSchema) {
33
32
  return this.runForEachSchema(changeSets, 'executeInserts', options);
34
33
  }
35
- const meta = this.metadata.find(changeSets[0].name);
34
+ const meta = changeSets[0].meta;
36
35
  changeSets.forEach(changeSet => this.processProperties(changeSet));
37
- if (changeSets.length > 1 && this.config.get('useBatchInserts', this.platform.usesBatchInserts())) {
36
+ if (changeSets.length > 1 && this.#config.get('useBatchInserts', this.#platform.usesBatchInserts())) {
38
37
  return this.persistNewEntities(meta, changeSets, options);
39
38
  }
40
39
  for (const changeSet of changeSets) {
@@ -45,9 +44,15 @@ export class ChangeSetPersister {
45
44
  if (!withSchema) {
46
45
  return this.runForEachSchema(changeSets, 'executeUpdates', options, batched);
47
46
  }
48
- const meta = this.metadata.find(changeSets[0].name);
47
+ const meta = changeSets[0].meta;
49
48
  changeSets.forEach(changeSet => this.processProperties(changeSet));
50
- if (batched && changeSets.length > 1 && this.config.get('useBatchUpdates', this.platform.usesBatchUpdates())) {
49
+ // For STI with conflicting fieldNames (renamedFrom properties), we can't batch mixed child types
50
+ const hasSTIConflicts = meta.root.props.some(p => p.renamedFrom);
51
+ const hasMixedTypes = hasSTIConflicts && changeSets.some(cs => cs.meta.class !== meta.class);
52
+ if (batched &&
53
+ changeSets.length > 1 &&
54
+ !hasMixedTypes &&
55
+ this.#config.get('useBatchUpdates', this.#platform.usesBatchUpdates())) {
51
56
  return this.persistManagedEntities(meta, changeSets, options);
52
57
  }
53
58
  for (const changeSet of changeSets) {
@@ -58,14 +63,14 @@ export class ChangeSetPersister {
58
63
  if (!withSchema) {
59
64
  return this.runForEachSchema(changeSets, 'executeDeletes', options);
60
65
  }
61
- const size = this.config.get('batchSize');
66
+ const size = this.#config.get('batchSize');
62
67
  const meta = changeSets[0].meta;
63
68
  const pk = Utils.getPrimaryKeyHash(meta.primaryKeys);
64
69
  for (let i = 0; i < changeSets.length; i += size) {
65
70
  const chunk = changeSets.slice(i, i + size);
66
71
  const pks = chunk.map(cs => cs.getPrimaryKey());
67
72
  options = this.prepareOptions(meta, options);
68
- await this.driver.nativeDelete(meta.root.className, { [pk]: { $in: pks } }, options);
73
+ await this.#driver.nativeDelete(meta.root.class, { [pk]: { $in: pks } }, options);
69
74
  }
70
75
  }
71
76
  async runForEachSchema(changeSets, method, options, ...args) {
@@ -81,13 +86,32 @@ export class ChangeSetPersister {
81
86
  await this[method](group, ...args, options, true);
82
87
  }
83
88
  }
89
+ validateRequired(entity) {
90
+ const wrapped = helper(entity);
91
+ for (const prop of wrapped.__meta.props) {
92
+ if (!prop.nullable &&
93
+ !prop.autoincrement &&
94
+ !prop.default &&
95
+ !prop.defaultRaw &&
96
+ !prop.onCreate &&
97
+ !prop.generated &&
98
+ !prop.embedded &&
99
+ ![ReferenceKind.ONE_TO_MANY, ReferenceKind.MANY_TO_MANY].includes(prop.kind) &&
100
+ prop.name !== wrapped.__meta.root.discriminatorColumn &&
101
+ prop.type !== 'ObjectId' &&
102
+ prop.persist !== false &&
103
+ entity[prop.name] == null) {
104
+ throw ValidationError.propertyRequired(entity, prop);
105
+ }
106
+ }
107
+ }
84
108
  processProperties(changeSet) {
85
- const meta = this.metadata.find(changeSet.name);
109
+ const meta = changeSet.meta;
86
110
  for (const prop of meta.relations) {
87
111
  this.processProperty(changeSet, prop);
88
112
  }
89
- if (changeSet.type === ChangeSetType.CREATE && this.config.get('validateRequired')) {
90
- this.validator.validateRequired(changeSet.entity);
113
+ if (changeSet.type === ChangeSetType.CREATE && this.#config.get('validateRequired')) {
114
+ this.validateRequired(changeSet.entity);
91
115
  }
92
116
  }
93
117
  async persistNewEntity(meta, changeSet, options) {
@@ -95,31 +119,33 @@ export class ChangeSetPersister {
95
119
  options = this.prepareOptions(meta, options, {
96
120
  convertCustomTypes: false,
97
121
  });
98
- const res = await this.driver.nativeInsertMany(meta.className, [changeSet.payload], options);
122
+ this.resolveTPTIdentifiers(changeSet);
123
+ // Use changeSet's own meta for STI entities to get correct field mappings
124
+ const res = await this.#driver.nativeInsertMany(changeSet.meta.class, [changeSet.payload], options);
99
125
  if (!wrapped.hasPrimaryKey()) {
100
- this.mapPrimaryKey(meta, res.insertId, changeSet);
126
+ this.mapPrimaryKey(meta, res.insertId ?? res.row?.[meta.primaryKeys[0]], changeSet);
101
127
  }
102
128
  this.mapReturnedValues(changeSet.entity, changeSet.payload, res.row, meta);
103
129
  this.markAsPopulated(changeSet, meta);
104
130
  wrapped.__initialized = true;
105
131
  wrapped.__managed = true;
106
- if (!this.usesReturningStatement) {
132
+ if (!this.#usesReturningStatement) {
107
133
  await this.reloadVersionValues(meta, [changeSet], options);
108
134
  }
109
135
  changeSet.persisted = true;
110
136
  }
111
137
  async persistNewEntities(meta, changeSets, options) {
112
- const size = this.config.get('batchSize');
138
+ const size = this.#config.get('batchSize');
113
139
  for (let i = 0; i < changeSets.length; i += size) {
114
140
  const chunk = changeSets.slice(i, i + size);
115
141
  await this.persistNewEntitiesBatch(meta, chunk, options);
116
- if (!this.usesReturningStatement) {
142
+ if (!this.#usesReturningStatement) {
117
143
  await this.reloadVersionValues(meta, chunk, options);
118
144
  }
119
145
  }
120
146
  }
121
147
  prepareOptions(meta, options, additionalOptions) {
122
- const loggerContext = Utils.merge({ id: this.em._id }, this.em.getLoggerContext({ disableContextResolution: true }));
148
+ const loggerContext = Utils.merge({ id: this.#em._id }, this.#em.getLoggerContext({ disableContextResolution: true }));
123
149
  return {
124
150
  ...options,
125
151
  ...additionalOptions,
@@ -132,7 +158,10 @@ export class ChangeSetPersister {
132
158
  convertCustomTypes: false,
133
159
  processCollections: false,
134
160
  });
135
- const res = await this.driver.nativeInsertMany(meta.className, changeSets.map(cs => cs.payload), options);
161
+ for (const changeSet of changeSets) {
162
+ this.resolveTPTIdentifiers(changeSet);
163
+ }
164
+ const res = await this.#driver.nativeInsertMany(meta.class, changeSets.map(cs => cs.payload), options);
136
165
  for (let i = 0; i < changeSets.length; i++) {
137
166
  const changeSet = changeSets[i];
138
167
  const wrapped = helper(changeSet.entity);
@@ -150,7 +179,7 @@ export class ChangeSetPersister {
150
179
  }
151
180
  }
152
181
  async persistManagedEntity(changeSet, options) {
153
- const meta = this.metadata.find(changeSet.name);
182
+ const meta = changeSet.meta;
154
183
  const res = await this.updateEntity(meta, changeSet, options);
155
184
  this.checkOptimisticLock(meta, changeSet, res);
156
185
  this.mapReturnedValues(changeSet.entity, changeSet.payload, res.row, meta);
@@ -158,7 +187,7 @@ export class ChangeSetPersister {
158
187
  changeSet.persisted = true;
159
188
  }
160
189
  async persistManagedEntities(meta, changeSets, options) {
161
- const size = this.config.get('batchSize');
190
+ const size = this.#config.get('batchSize');
162
191
  for (let i = 0; i < changeSets.length; i += size) {
163
192
  const chunk = changeSets.slice(i, i + size);
164
193
  await this.persistManagedEntitiesBatch(meta, chunk, options);
@@ -191,9 +220,9 @@ export class ChangeSetPersister {
191
220
  cond.push(where);
192
221
  payload.push(changeSet.payload);
193
222
  }
194
- const res = await this.driver.nativeUpdateMany(meta.className, cond, payload, options);
223
+ const res = await this.#driver.nativeUpdateMany(meta.class, cond, payload, options);
195
224
  const map = new Map();
196
- res.rows?.forEach(item => map.set(Utils.getCompositeKeyHash(item, meta, true, this.platform, true), item));
225
+ res.rows?.forEach(item => map.set(Utils.getCompositeKeyHash(item, meta, true, this.#platform, true), item));
197
226
  for (const changeSet of changeSets) {
198
227
  if (res.rows) {
199
228
  const row = map.get(helper(changeSet.entity).getSerializedPrimaryKey());
@@ -204,7 +233,7 @@ export class ChangeSetPersister {
204
233
  }
205
234
  mapPrimaryKey(meta, value, changeSet) {
206
235
  const prop = meta.properties[meta.primaryKeys[0]];
207
- const insertId = prop.customType ? prop.customType.convertToJSValue(value, this.platform) : value;
236
+ const insertId = prop.customType ? prop.customType.convertToJSValue(value, this.#platform) : value;
208
237
  const wrapped = helper(changeSet.entity);
209
238
  if (!wrapped.hasPrimaryKey()) {
210
239
  wrapped.setPrimaryKey(insertId);
@@ -212,7 +241,9 @@ export class ChangeSetPersister {
212
241
  // some drivers might be returning bigint PKs as numbers when the number is small enough,
213
242
  // but we need to have it as string so comparison works in change set tracking, so instead
214
243
  // of using the raw value from db, we convert it back to the db value explicitly
215
- value = prop.customType ? prop.customType.convertToDatabaseValue(insertId, this.platform, { mode: 'serialization' }) : value;
244
+ value = prop.customType
245
+ ? prop.customType.convertToDatabaseValue(insertId, this.#platform, { mode: 'serialization' })
246
+ : value;
216
247
  changeSet.payload[wrapped.__meta.primaryKeys[0]] = value;
217
248
  if (wrapped.__identifier && !Array.isArray(wrapped.__identifier)) {
218
249
  wrapped.__identifier.setValue(value);
@@ -222,8 +253,8 @@ export class ChangeSetPersister {
222
253
  * Sets populate flag to new entities so they are serialized like if they were loaded from the db
223
254
  */
224
255
  markAsPopulated(changeSet, meta) {
225
- helper(changeSet.entity).__schema = this.driver.getSchemaName(meta, changeSet);
226
- if (!this.config.get('populateAfterFlush')) {
256
+ helper(changeSet.entity).__schema = this.#driver.getSchemaName(meta, changeSet);
257
+ if (!this.#config.get('populateAfterFlush')) {
227
258
  return;
228
259
  }
229
260
  helper(changeSet.entity).populated();
@@ -242,17 +273,19 @@ export class ChangeSetPersister {
242
273
  options = this.prepareOptions(meta, options, {
243
274
  convertCustomTypes: false,
244
275
  });
245
- if (meta.concurrencyCheckKeys.size === 0 && (!meta.versionProperty || changeSet.entity[meta.versionProperty] == null)) {
246
- return this.driver.nativeUpdate(changeSet.name, cond, changeSet.payload, options);
276
+ if (meta.concurrencyCheckKeys.size === 0 &&
277
+ (!meta.versionProperty || changeSet.entity[meta.versionProperty] == null)) {
278
+ return this.#driver.nativeUpdate(changeSet.meta.class, cond, changeSet.payload, options);
247
279
  }
248
280
  if (meta.versionProperty) {
249
- cond[meta.versionProperty] = this.platform.quoteVersionValue(changeSet.entity[meta.versionProperty], meta.properties[meta.versionProperty]);
281
+ cond[meta.versionProperty] = this.#platform.convertVersionValue(changeSet.entity[meta.versionProperty], meta.properties[meta.versionProperty]);
250
282
  }
251
283
  this.checkConcurrencyKeys(meta, changeSet, cond);
252
- return this.driver.nativeUpdate(changeSet.name, cond, changeSet.payload, options);
284
+ return this.#driver.nativeUpdate(changeSet.meta.class, cond, changeSet.payload, options);
253
285
  }
254
286
  async checkOptimisticLocks(meta, changeSets, options) {
255
- if (meta.concurrencyCheckKeys.size === 0 && (!meta.versionProperty || changeSets.every(cs => cs.entity[meta.versionProperty] == null))) {
287
+ if (meta.concurrencyCheckKeys.size === 0 &&
288
+ (!meta.versionProperty || changeSets.every(cs => cs.entity[meta.versionProperty] == null))) {
256
289
  return;
257
290
  }
258
291
  // skip entity references as they don't have version values loaded
@@ -261,7 +294,7 @@ export class ChangeSetPersister {
261
294
  const cond = Utils.getPrimaryKeyCond(cs.originalEntity, meta.primaryKeys.concat(...meta.concurrencyCheckKeys));
262
295
  if (meta.versionProperty) {
263
296
  // @ts-ignore
264
- cond[meta.versionProperty] = this.platform.quoteVersionValue(cs.entity[meta.versionProperty], meta.properties[meta.versionProperty]);
297
+ cond[meta.versionProperty] = this.#platform.convertVersionValue(cs.entity[meta.versionProperty], meta.properties[meta.versionProperty]);
265
298
  }
266
299
  return cond;
267
300
  });
@@ -269,7 +302,7 @@ export class ChangeSetPersister {
269
302
  options = this.prepareOptions(meta, options, {
270
303
  fields: primaryKeys,
271
304
  });
272
- const res = await this.driver.find(meta.root.className, { $or }, options);
305
+ const res = await this.#driver.find(meta.root.class, { $or }, options);
273
306
  if (res.length !== changeSets.length) {
274
307
  const compare = (a, b, keys) => keys.every(k => a[k] === b[k]);
275
308
  const entity = changeSets.find(cs => {
@@ -288,13 +321,24 @@ export class ChangeSetPersister {
288
321
  * so we use a single query in case of both versioning and default values is used.
289
322
  */
290
323
  async reloadVersionValues(meta, changeSets, options) {
291
- const reloadProps = meta.versionProperty && !this.usesReturningStatement ? [meta.properties[meta.versionProperty]] : [];
324
+ const reloadProps = meta.versionProperty && !this.#usesReturningStatement ? [meta.properties[meta.versionProperty]] : [];
292
325
  if (changeSets[0].type === ChangeSetType.CREATE) {
293
- // do not reload things that already had a runtime value
294
- meta.props
295
- .filter(prop => prop.persist !== false && (prop.autoincrement || prop.generated || prop.defaultRaw))
296
- .filter(prop => (changeSets[0].entity[prop.name] == null && prop.defaultRaw !== 'null') || isRaw(changeSets[0].entity[prop.name]))
297
- .forEach(prop => reloadProps.push(prop));
326
+ for (const prop of meta.props) {
327
+ if (prop.persist === false) {
328
+ continue;
329
+ }
330
+ if (isRaw(changeSets[0].entity[prop.name])) {
331
+ reloadProps.push(prop);
332
+ continue;
333
+ }
334
+ // do not reload things that already had a runtime value
335
+ if (changeSets[0].entity[prop.name] != null || prop.defaultRaw === 'null') {
336
+ continue;
337
+ }
338
+ if (prop.autoincrement || prop.generated || prop.defaultRaw) {
339
+ reloadProps.push(prop);
340
+ }
341
+ }
298
342
  }
299
343
  if (changeSets[0].type === ChangeSetType.UPDATE) {
300
344
  const returning = new Set();
@@ -306,10 +350,8 @@ export class ChangeSetPersister {
306
350
  });
307
351
  });
308
352
  // reload generated columns
309
- if (!this.usesReturningStatement) {
310
- meta.props
311
- .filter(prop => prop.generated && !prop.primary)
312
- .forEach(prop => reloadProps.push(prop));
353
+ if (!this.#usesReturningStatement) {
354
+ meta.props.filter(prop => prop.generated && !prop.primary).forEach(prop => reloadProps.push(prop));
313
355
  reloadProps.push(...returning);
314
356
  }
315
357
  }
@@ -321,35 +363,56 @@ export class ChangeSetPersister {
321
363
  const pks = changeSets.map(cs => {
322
364
  const val = helper(cs.entity).getPrimaryKey(true);
323
365
  if (Utils.isPlainObject(val)) {
324
- return Utils.getCompositeKeyValue(val, meta, false, this.platform);
366
+ return Utils.getCompositeKeyValue(val, meta, false, this.#platform);
325
367
  }
326
368
  return val;
327
369
  });
328
370
  options = this.prepareOptions(meta, options, {
329
371
  fields: Utils.unique(reloadProps.map(prop => prop.name)),
330
372
  });
331
- const data = await this.driver.find(meta.className, { [pk]: { $in: pks } }, options);
373
+ const data = await this.#driver.find(meta.class, { [pk]: { $in: pks } }, options);
332
374
  const map = new Map();
333
- data.forEach(item => map.set(Utils.getCompositeKeyHash(item, meta, false, this.platform, true), item));
375
+ data.forEach(item => map.set(Utils.getCompositeKeyHash(item, meta, false, this.#platform, true), item));
334
376
  for (const changeSet of changeSets) {
335
377
  const data = map.get(helper(changeSet.entity).getSerializedPrimaryKey());
336
- this.hydrator.hydrate(changeSet.entity, meta, data, this.factory, 'full', false, true);
378
+ this.#hydrator.hydrate(changeSet.entity, meta, data, this.#factory, 'full', false, true);
337
379
  Object.assign(changeSet.payload, data); // merge to the changeset payload, so it gets saved to the entity snapshot
338
380
  }
339
381
  }
382
+ /**
383
+ * For TPT child tables, resolve EntityIdentifier values in PK fields.
384
+ * The parent table insert assigns the actual PK value, which the child table references.
385
+ */
386
+ resolveTPTIdentifiers(changeSet) {
387
+ if (changeSet.meta.inheritanceType !== 'tpt' || !changeSet.meta.tptParent) {
388
+ return;
389
+ }
390
+ for (const pk of changeSet.meta.primaryKeys) {
391
+ const value = changeSet.payload[pk];
392
+ if (value instanceof EntityIdentifier) {
393
+ changeSet.payload[pk] = value.getValue();
394
+ }
395
+ }
396
+ }
340
397
  processProperty(changeSet, prop) {
341
- const meta = this.metadata.find(changeSet.name);
398
+ const meta = changeSet.meta;
342
399
  const value = changeSet.payload[prop.name]; // for inline embeddables
343
400
  if (value instanceof EntityIdentifier) {
344
401
  changeSet.payload[prop.name] = value.getValue();
345
402
  return;
346
403
  }
404
+ if (value instanceof PolymorphicRef) {
405
+ if (value.id instanceof EntityIdentifier) {
406
+ value.id = value.id.getValue();
407
+ }
408
+ return;
409
+ }
347
410
  if (Array.isArray(value) && value.every(item => item instanceof EntityIdentifier)) {
348
411
  changeSet.payload[prop.name] = value.map(item => item.getValue());
349
412
  return;
350
413
  }
351
414
  if (prop.kind === ReferenceKind.MANY_TO_MANY && Array.isArray(value)) {
352
- changeSet.payload[prop.name] = value.map(val => val instanceof EntityIdentifier ? val.getValue() : val);
415
+ changeSet.payload[prop.name] = value.map(val => (val instanceof EntityIdentifier ? val.getValue() : val));
353
416
  return;
354
417
  }
355
418
  if (prop.name in changeSet.payload) {
@@ -368,17 +431,17 @@ export class ChangeSetPersister {
368
431
  * We do need to map to the change set payload too, as it will be used in the originalEntityData for new entities.
369
432
  */
370
433
  mapReturnedValues(entity, payload, row, meta, upsert = false) {
371
- if ((!this.usesReturningStatement && !upsert) || !row || !Utils.hasObjectKeys(row)) {
434
+ if ((!this.#usesReturningStatement && !upsert) || !row || !Utils.hasObjectKeys(row)) {
372
435
  return;
373
436
  }
374
- const mapped = this.comparator.mapResult(meta.className, row);
437
+ const mapped = this.#comparator.mapResult(meta, row);
375
438
  if (entity) {
376
- this.hydrator.hydrate(entity, meta, mapped, this.factory, 'full', false, true);
439
+ this.#hydrator.hydrate(entity, meta, mapped, this.#factory, 'full', false, true);
377
440
  }
378
441
  if (upsert) {
379
442
  for (const prop of meta.props) {
380
443
  if (prop.customType && prop.name in mapped) {
381
- mapped[prop.name] = prop.customType.convertToJSValue(mapped[prop.name], this.platform);
444
+ mapped[prop.name] = prop.customType.convertToJSValue(mapped[prop.name], this.#platform);
382
445
  }
383
446
  }
384
447
  }
@@ -1,17 +1,18 @@
1
- import type { Dictionary, EntityProperty } from '../typings.js';
1
+ import type { EntityProperty } from '../typings.js';
2
2
  export declare const enum NodeState {
3
3
  NOT_VISITED = 0,
4
4
  IN_PROGRESS = 1,
5
5
  VISITED = 2
6
6
  }
7
+ type Hash = number;
7
8
  export interface Node {
8
- hash: string;
9
+ hash: Hash;
9
10
  state: NodeState;
10
- dependencies: Dictionary<Edge>;
11
+ dependencies: Map<Hash, Edge>;
11
12
  }
12
13
  export interface Edge {
13
- from: string;
14
- to: string;
14
+ from: Hash;
15
+ to: Hash;
15
16
  weight: number;
16
17
  }
17
18
  /**
@@ -25,30 +26,27 @@ export interface Edge {
25
26
  * @internal
26
27
  */
27
28
  export declare class CommitOrderCalculator {
28
- /** Matrix of nodes, keys are provided hashes and values are the node definition objects. */
29
- private nodes;
30
- /** Volatile variable holding calculated nodes during sorting process. */
31
- private sortedNodeList;
29
+ #private;
32
30
  /**
33
31
  * Checks for node existence in graph.
34
32
  */
35
- hasNode(hash: string): boolean;
33
+ hasNode(hash: Hash): boolean;
36
34
  /**
37
35
  * Adds a new node to the graph, assigning its hash.
38
36
  */
39
- addNode(hash: string): void;
37
+ addNode(hash: Hash): void;
40
38
  /**
41
39
  * Adds a new dependency (edge) to the graph using their hashes.
42
40
  */
43
- addDependency(from: string, to: string, weight: number): void;
44
- discoverProperty(prop: EntityProperty, entityName: string): void;
41
+ addDependency(from: Hash, to: Hash, weight: number): void;
42
+ discoverProperty(prop: EntityProperty, entityName: Hash): void;
45
43
  /**
46
44
  * Return a valid order list of all current nodes.
47
45
  * The desired topological sorting is the reverse post order of these searches.
48
46
  *
49
47
  * @internal Highly performance-sensitive method.
50
48
  */
51
- sort(): string[];
49
+ sort(): Hash[];
52
50
  /**
53
51
  * Visit a given node definition for reordering.
54
52
  *
@@ -60,3 +58,4 @@ export declare class CommitOrderCalculator {
60
58
  */
61
59
  private visitOpenNode;
62
60
  }
61
+ export {};
@@ -17,26 +17,26 @@ export var NodeState;
17
17
  */
18
18
  export class CommitOrderCalculator {
19
19
  /** Matrix of nodes, keys are provided hashes and values are the node definition objects. */
20
- nodes = {};
20
+ #nodes = new Map();
21
21
  /** Volatile variable holding calculated nodes during sorting process. */
22
- sortedNodeList = [];
22
+ #sortedNodeList = [];
23
23
  /**
24
24
  * Checks for node existence in graph.
25
25
  */
26
26
  hasNode(hash) {
27
- return hash in this.nodes;
27
+ return this.#nodes.has(hash);
28
28
  }
29
29
  /**
30
30
  * Adds a new node to the graph, assigning its hash.
31
31
  */
32
32
  addNode(hash) {
33
- this.nodes[hash] = { hash, state: 0 /* NodeState.NOT_VISITED */, dependencies: {} };
33
+ this.#nodes.set(hash, { hash, state: 0 /* NodeState.NOT_VISITED */, dependencies: new Map() });
34
34
  }
35
35
  /**
36
36
  * Adds a new dependency (edge) to the graph using their hashes.
37
37
  */
38
38
  addDependency(from, to, weight) {
39
- this.nodes[from].dependencies[to] = { from, to, weight };
39
+ this.#nodes.get(from).dependencies.set(to, { from, to, weight });
40
40
  }
41
41
  discoverProperty(prop, entityName) {
42
42
  const toOneOwner = (prop.kind === ReferenceKind.ONE_TO_ONE && prop.owner) || prop.kind === ReferenceKind.MANY_TO_ONE;
@@ -44,8 +44,8 @@ export class CommitOrderCalculator {
44
44
  if (!toOneOwner && !toManyOwner) {
45
45
  return;
46
46
  }
47
- const propertyType = prop.targetMeta?.root.className;
48
- if (!propertyType || !this.hasNode(propertyType)) {
47
+ const propertyType = prop.targetMeta?.root._id;
48
+ if (propertyType == null || !this.hasNode(propertyType)) {
49
49
  return;
50
50
  }
51
51
  this.addDependency(propertyType, entityName, prop.nullable || prop.persist === false ? 0 : 1);
@@ -57,15 +57,15 @@ export class CommitOrderCalculator {
57
57
  * @internal Highly performance-sensitive method.
58
58
  */
59
59
  sort() {
60
- for (const vertex of Object.values(this.nodes)) {
60
+ for (const vertex of this.#nodes.values()) {
61
61
  if (vertex.state !== 0 /* NodeState.NOT_VISITED */) {
62
62
  continue;
63
63
  }
64
64
  this.visit(vertex);
65
65
  }
66
- const sortedList = this.sortedNodeList.reverse();
67
- this.nodes = {};
68
- this.sortedNodeList = [];
66
+ const sortedList = this.#sortedNodeList.reverse();
67
+ this.#nodes = new Map();
68
+ this.#sortedNodeList = [];
69
69
  return sortedList;
70
70
  }
71
71
  /**
@@ -75,35 +75,37 @@ export class CommitOrderCalculator {
75
75
  */
76
76
  visit(node) {
77
77
  node.state = 1 /* NodeState.IN_PROGRESS */;
78
- for (const edge of Object.values(node.dependencies)) {
79
- const target = this.nodes[edge.to];
78
+ for (const edge of node.dependencies.values()) {
79
+ const target = this.#nodes.get(edge.to);
80
80
  switch (target.state) {
81
- case 2 /* NodeState.VISITED */: break; // Do nothing, since node was already visited
81
+ case 2 /* NodeState.VISITED */:
82
+ break; // Do nothing, since node was already visited
82
83
  case 1 /* NodeState.IN_PROGRESS */:
83
84
  this.visitOpenNode(node, target, edge);
84
85
  break;
85
- case 0 /* NodeState.NOT_VISITED */: this.visit(target);
86
+ case 0 /* NodeState.NOT_VISITED */:
87
+ this.visit(target);
86
88
  }
87
89
  }
88
90
  if (node.state !== 2 /* NodeState.VISITED */) {
89
91
  node.state = 2 /* NodeState.VISITED */;
90
- this.sortedNodeList.push(node.hash);
92
+ this.#sortedNodeList.push(node.hash);
91
93
  }
92
94
  }
93
95
  /**
94
96
  * Visits all target's dependencies if in cycle with given node
95
97
  */
96
98
  visitOpenNode(node, target, edge) {
97
- if (!target.dependencies[node.hash] || target.dependencies[node.hash].weight >= edge.weight) {
99
+ if (!target.dependencies.has(node.hash) || target.dependencies.get(node.hash).weight >= edge.weight) {
98
100
  return;
99
101
  }
100
- for (const edge of Object.values(target.dependencies)) {
101
- const targetNode = this.nodes[edge.to];
102
+ for (const edge of target.dependencies.values()) {
103
+ const targetNode = this.#nodes.get(edge.to);
102
104
  if (targetNode.state === 0 /* NodeState.NOT_VISITED */) {
103
105
  this.visit(targetNode);
104
106
  }
105
107
  }
106
108
  target.state = 2 /* NodeState.VISITED */;
107
- this.sortedNodeList.push(target.hash);
109
+ this.#sortedNodeList.push(target.hash);
108
110
  }
109
111
  }
@@ -1,9 +1,13 @@
1
1
  import type { AnyEntity, EntityMetadata } from '../typings.js';
2
2
  export declare class IdentityMap {
3
- private readonly defaultSchema?;
4
- constructor(defaultSchema?: string | undefined);
5
- private readonly registry;
3
+ #private;
4
+ constructor(defaultSchema?: string);
6
5
  store<T>(item: T): void;
6
+ /**
7
+ * Stores an entity under an alternate key (non-PK property).
8
+ * This allows looking up entities by unique properties that are not the primary key.
9
+ */
10
+ storeByKey<T>(item: T, key: string, value: string, schema?: string): void;
7
11
  delete<T>(item: T): void;
8
12
  getByHash<T>(meta: EntityMetadata<T>, hash: string): T | undefined;
9
13
  getStore<T>(meta: EntityMetadata<T>): Map<string, T>;
@@ -16,4 +20,9 @@ export declare class IdentityMap {
16
20
  */
17
21
  get<T>(hash: string): T | undefined;
18
22
  private getPkHash;
23
+ /**
24
+ * Creates a hash for an alternate key lookup.
25
+ * Format: `[key]value` or `schema:[key]value`
26
+ */
27
+ getKeyHash(key: string, value: string, schema?: string): string;
19
28
  }