@yandjin-mikro-orm/core 6.1.4-rc-sti-changes-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (264) hide show
  1. package/EntityManager.d.ts +553 -0
  2. package/EntityManager.js +1736 -0
  3. package/LICENSE +21 -0
  4. package/MikroORM.d.ts +102 -0
  5. package/MikroORM.js +258 -0
  6. package/README.md +383 -0
  7. package/cache/CacheAdapter.d.ts +40 -0
  8. package/cache/CacheAdapter.js +2 -0
  9. package/cache/FileCacheAdapter.d.ts +31 -0
  10. package/cache/FileCacheAdapter.js +90 -0
  11. package/cache/GeneratedCacheAdapter.d.ts +25 -0
  12. package/cache/GeneratedCacheAdapter.js +38 -0
  13. package/cache/MemoryCacheAdapter.d.ts +24 -0
  14. package/cache/MemoryCacheAdapter.js +44 -0
  15. package/cache/NullCacheAdapter.d.ts +19 -0
  16. package/cache/NullCacheAdapter.js +30 -0
  17. package/cache/index.d.ts +5 -0
  18. package/cache/index.js +21 -0
  19. package/connections/Connection.d.ts +85 -0
  20. package/connections/Connection.js +128 -0
  21. package/connections/index.d.ts +1 -0
  22. package/connections/index.js +17 -0
  23. package/decorators/Check.d.ts +3 -0
  24. package/decorators/Check.js +17 -0
  25. package/decorators/CreateRequestContext.d.ts +2 -0
  26. package/decorators/CreateRequestContext.js +31 -0
  27. package/decorators/Embeddable.d.ts +8 -0
  28. package/decorators/Embeddable.js +15 -0
  29. package/decorators/Embedded.d.ts +13 -0
  30. package/decorators/Embedded.js +21 -0
  31. package/decorators/EnsureRequestContext.d.ts +2 -0
  32. package/decorators/EnsureRequestContext.js +26 -0
  33. package/decorators/Entity.d.ts +18 -0
  34. package/decorators/Entity.js +17 -0
  35. package/decorators/Enum.d.ts +9 -0
  36. package/decorators/Enum.js +20 -0
  37. package/decorators/Filter.d.ts +2 -0
  38. package/decorators/Filter.js +12 -0
  39. package/decorators/Formula.d.ts +5 -0
  40. package/decorators/Formula.js +19 -0
  41. package/decorators/Indexed.d.ts +12 -0
  42. package/decorators/Indexed.js +25 -0
  43. package/decorators/ManyToMany.d.ts +21 -0
  44. package/decorators/ManyToMany.js +17 -0
  45. package/decorators/ManyToOne.d.ts +15 -0
  46. package/decorators/ManyToOne.js +17 -0
  47. package/decorators/OneToMany.d.ts +18 -0
  48. package/decorators/OneToMany.js +21 -0
  49. package/decorators/OneToOne.d.ts +12 -0
  50. package/decorators/OneToOne.js +11 -0
  51. package/decorators/PrimaryKey.d.ts +8 -0
  52. package/decorators/PrimaryKey.js +24 -0
  53. package/decorators/Property.d.ts +218 -0
  54. package/decorators/Property.js +35 -0
  55. package/decorators/Subscriber.d.ts +1 -0
  56. package/decorators/Subscriber.js +2 -0
  57. package/decorators/hooks.d.ts +16 -0
  58. package/decorators/hooks.js +60 -0
  59. package/decorators/index.d.ts +17 -0
  60. package/decorators/index.js +36 -0
  61. package/drivers/DatabaseDriver.d.ts +72 -0
  62. package/drivers/DatabaseDriver.js +358 -0
  63. package/drivers/IDatabaseDriver.d.ts +193 -0
  64. package/drivers/IDatabaseDriver.js +4 -0
  65. package/drivers/index.d.ts +2 -0
  66. package/drivers/index.js +18 -0
  67. package/entity/ArrayCollection.d.ts +113 -0
  68. package/entity/ArrayCollection.js +386 -0
  69. package/entity/BaseEntity.d.ts +22 -0
  70. package/entity/BaseEntity.js +47 -0
  71. package/entity/Collection.d.ts +104 -0
  72. package/entity/Collection.js +373 -0
  73. package/entity/EntityAssigner.d.ts +28 -0
  74. package/entity/EntityAssigner.js +226 -0
  75. package/entity/EntityFactory.d.ts +41 -0
  76. package/entity/EntityFactory.js +302 -0
  77. package/entity/EntityHelper.d.ts +29 -0
  78. package/entity/EntityHelper.js +250 -0
  79. package/entity/EntityIdentifier.d.ts +10 -0
  80. package/entity/EntityIdentifier.js +19 -0
  81. package/entity/EntityLoader.d.ts +65 -0
  82. package/entity/EntityLoader.js +579 -0
  83. package/entity/EntityRepository.d.ts +161 -0
  84. package/entity/EntityRepository.js +207 -0
  85. package/entity/EntityValidator.d.ts +19 -0
  86. package/entity/EntityValidator.js +152 -0
  87. package/entity/Reference.d.ts +89 -0
  88. package/entity/Reference.js +242 -0
  89. package/entity/WrappedEntity.d.ts +67 -0
  90. package/entity/WrappedEntity.js +146 -0
  91. package/entity/index.d.ts +13 -0
  92. package/entity/index.js +29 -0
  93. package/entity/wrap.d.ts +15 -0
  94. package/entity/wrap.js +26 -0
  95. package/enums.d.ts +160 -0
  96. package/enums.js +169 -0
  97. package/errors.d.ts +65 -0
  98. package/errors.js +222 -0
  99. package/events/EventManager.d.ts +17 -0
  100. package/events/EventManager.js +77 -0
  101. package/events/EventSubscriber.d.ts +39 -0
  102. package/events/EventSubscriber.js +2 -0
  103. package/events/TransactionEventBroadcaster.d.ts +11 -0
  104. package/events/TransactionEventBroadcaster.js +17 -0
  105. package/events/index.d.ts +3 -0
  106. package/events/index.js +19 -0
  107. package/exceptions.d.ts +104 -0
  108. package/exceptions.js +130 -0
  109. package/hydration/Hydrator.d.ts +23 -0
  110. package/hydration/Hydrator.js +51 -0
  111. package/hydration/ObjectHydrator.d.ts +24 -0
  112. package/hydration/ObjectHydrator.js +332 -0
  113. package/hydration/index.d.ts +2 -0
  114. package/hydration/index.js +18 -0
  115. package/index.d.ts +25 -0
  116. package/index.js +50 -0
  117. package/index.mjs +192 -0
  118. package/logging/DefaultLogger.d.ts +32 -0
  119. package/logging/DefaultLogger.js +90 -0
  120. package/logging/Logger.d.ts +56 -0
  121. package/logging/Logger.js +2 -0
  122. package/logging/SimpleLogger.d.ts +17 -0
  123. package/logging/SimpleLogger.js +31 -0
  124. package/logging/colors.d.ts +9 -0
  125. package/logging/colors.js +20 -0
  126. package/logging/index.d.ts +4 -0
  127. package/logging/index.js +20 -0
  128. package/metadata/EntitySchema.d.ts +74 -0
  129. package/metadata/EntitySchema.js +293 -0
  130. package/metadata/MetadataDiscovery.d.ts +71 -0
  131. package/metadata/MetadataDiscovery.js +1244 -0
  132. package/metadata/MetadataProvider.d.ts +11 -0
  133. package/metadata/MetadataProvider.js +23 -0
  134. package/metadata/MetadataStorage.d.ts +22 -0
  135. package/metadata/MetadataStorage.js +87 -0
  136. package/metadata/MetadataValidator.d.ts +24 -0
  137. package/metadata/MetadataValidator.js +213 -0
  138. package/metadata/ReflectMetadataProvider.d.ts +8 -0
  139. package/metadata/ReflectMetadataProvider.js +48 -0
  140. package/metadata/index.d.ts +6 -0
  141. package/metadata/index.js +22 -0
  142. package/naming-strategy/AbstractNamingStrategy.d.ts +18 -0
  143. package/naming-strategy/AbstractNamingStrategy.js +48 -0
  144. package/naming-strategy/EntityCaseNamingStrategy.d.ts +12 -0
  145. package/naming-strategy/EntityCaseNamingStrategy.js +32 -0
  146. package/naming-strategy/MongoNamingStrategy.d.ts +9 -0
  147. package/naming-strategy/MongoNamingStrategy.js +25 -0
  148. package/naming-strategy/NamingStrategy.d.ts +52 -0
  149. package/naming-strategy/NamingStrategy.js +2 -0
  150. package/naming-strategy/UnderscoreNamingStrategy.d.ts +10 -0
  151. package/naming-strategy/UnderscoreNamingStrategy.js +28 -0
  152. package/naming-strategy/index.d.ts +5 -0
  153. package/naming-strategy/index.js +21 -0
  154. package/package.json +70 -0
  155. package/platforms/ExceptionConverter.d.ts +5 -0
  156. package/platforms/ExceptionConverter.js +11 -0
  157. package/platforms/Platform.d.ts +201 -0
  158. package/platforms/Platform.js +452 -0
  159. package/platforms/index.d.ts +2 -0
  160. package/platforms/index.js +18 -0
  161. package/serialization/EntitySerializer.d.ts +34 -0
  162. package/serialization/EntitySerializer.js +206 -0
  163. package/serialization/EntityTransformer.d.ts +8 -0
  164. package/serialization/EntityTransformer.js +192 -0
  165. package/serialization/SerializationContext.d.ts +30 -0
  166. package/serialization/SerializationContext.js +111 -0
  167. package/serialization/index.d.ts +3 -0
  168. package/serialization/index.js +19 -0
  169. package/types/ArrayType.d.ts +13 -0
  170. package/types/ArrayType.js +47 -0
  171. package/types/BigIntType.d.ts +16 -0
  172. package/types/BigIntType.js +45 -0
  173. package/types/BlobType.d.ts +10 -0
  174. package/types/BlobType.js +27 -0
  175. package/types/BooleanType.d.ts +8 -0
  176. package/types/BooleanType.js +16 -0
  177. package/types/DateTimeType.d.ts +8 -0
  178. package/types/DateTimeType.js +16 -0
  179. package/types/DateType.d.ts +8 -0
  180. package/types/DateType.js +16 -0
  181. package/types/DecimalType.d.ts +11 -0
  182. package/types/DecimalType.js +22 -0
  183. package/types/DoubleType.d.ts +11 -0
  184. package/types/DoubleType.js +22 -0
  185. package/types/EnumArrayType.d.ts +9 -0
  186. package/types/EnumArrayType.js +32 -0
  187. package/types/EnumType.d.ts +8 -0
  188. package/types/EnumType.js +16 -0
  189. package/types/FloatType.d.ts +8 -0
  190. package/types/FloatType.js +16 -0
  191. package/types/IntegerType.d.ts +8 -0
  192. package/types/IntegerType.js +16 -0
  193. package/types/IntervalType.d.ts +8 -0
  194. package/types/IntervalType.js +16 -0
  195. package/types/JsonType.d.ts +13 -0
  196. package/types/JsonType.js +34 -0
  197. package/types/MediumIntType.d.ts +6 -0
  198. package/types/MediumIntType.js +10 -0
  199. package/types/SmallIntType.d.ts +8 -0
  200. package/types/SmallIntType.js +16 -0
  201. package/types/StringType.d.ts +8 -0
  202. package/types/StringType.js +16 -0
  203. package/types/TextType.d.ts +8 -0
  204. package/types/TextType.js +16 -0
  205. package/types/TimeType.d.ts +9 -0
  206. package/types/TimeType.js +23 -0
  207. package/types/TinyIntType.d.ts +8 -0
  208. package/types/TinyIntType.js +16 -0
  209. package/types/Type.d.ts +64 -0
  210. package/types/Type.js +84 -0
  211. package/types/Uint8ArrayType.d.ts +11 -0
  212. package/types/Uint8ArrayType.js +37 -0
  213. package/types/UnknownType.d.ts +7 -0
  214. package/types/UnknownType.js +13 -0
  215. package/types/UuidType.d.ts +7 -0
  216. package/types/UuidType.js +13 -0
  217. package/types/index.d.ts +75 -0
  218. package/types/index.js +77 -0
  219. package/typings.d.ts +767 -0
  220. package/typings.js +198 -0
  221. package/unit-of-work/ChangeSet.d.ts +34 -0
  222. package/unit-of-work/ChangeSet.js +62 -0
  223. package/unit-of-work/ChangeSetComputer.d.ts +26 -0
  224. package/unit-of-work/ChangeSetComputer.js +153 -0
  225. package/unit-of-work/ChangeSetPersister.d.ts +50 -0
  226. package/unit-of-work/ChangeSetPersister.js +361 -0
  227. package/unit-of-work/CommitOrderCalculator.d.ts +62 -0
  228. package/unit-of-work/CommitOrderCalculator.js +113 -0
  229. package/unit-of-work/IdentityMap.d.ts +17 -0
  230. package/unit-of-work/IdentityMap.js +84 -0
  231. package/unit-of-work/UnitOfWork.d.ts +124 -0
  232. package/unit-of-work/UnitOfWork.js +1013 -0
  233. package/unit-of-work/index.d.ts +6 -0
  234. package/unit-of-work/index.js +22 -0
  235. package/utils/AbstractSchemaGenerator.d.ts +38 -0
  236. package/utils/AbstractSchemaGenerator.js +101 -0
  237. package/utils/Configuration.d.ts +390 -0
  238. package/utils/Configuration.js +357 -0
  239. package/utils/ConfigurationLoader.d.ts +29 -0
  240. package/utils/ConfigurationLoader.js +282 -0
  241. package/utils/Cursor.d.ts +77 -0
  242. package/utils/Cursor.js +169 -0
  243. package/utils/DataloaderUtils.d.ts +43 -0
  244. package/utils/DataloaderUtils.js +194 -0
  245. package/utils/EntityComparator.d.ts +73 -0
  246. package/utils/EntityComparator.js +568 -0
  247. package/utils/NullHighlighter.d.ts +4 -0
  248. package/utils/NullHighlighter.js +9 -0
  249. package/utils/QueryHelper.d.ts +28 -0
  250. package/utils/QueryHelper.js +228 -0
  251. package/utils/RawQueryFragment.d.ts +96 -0
  252. package/utils/RawQueryFragment.js +188 -0
  253. package/utils/RequestContext.d.ts +34 -0
  254. package/utils/RequestContext.js +54 -0
  255. package/utils/TransactionContext.d.ts +19 -0
  256. package/utils/TransactionContext.js +34 -0
  257. package/utils/Utils.d.ts +274 -0
  258. package/utils/Utils.js +1073 -0
  259. package/utils/clone.d.ts +6 -0
  260. package/utils/clone.js +127 -0
  261. package/utils/index.d.ts +13 -0
  262. package/utils/index.js +29 -0
  263. package/utils/upsert-utils.d.ts +6 -0
  264. package/utils/upsert-utils.js +33 -0
@@ -0,0 +1,1013 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.UnitOfWork = void 0;
4
+ const async_hooks_1 = require("async_hooks");
5
+ const entity_1 = require("../entity");
6
+ const ChangeSet_1 = require("./ChangeSet");
7
+ const ChangeSetComputer_1 = require("./ChangeSetComputer");
8
+ const ChangeSetPersister_1 = require("./ChangeSetPersister");
9
+ const CommitOrderCalculator_1 = require("./CommitOrderCalculator");
10
+ const Utils_1 = require("../utils/Utils");
11
+ const enums_1 = require("../enums");
12
+ const errors_1 = require("../errors");
13
+ const events_1 = require("../events");
14
+ const IdentityMap_1 = require("./IdentityMap");
15
+ // to deal with validation for flush inside flush hooks and `Promise.all`
16
+ const insideFlush = new async_hooks_1.AsyncLocalStorage();
17
+ class UnitOfWork {
18
+ em;
19
+ /** map of references to managed entities */
20
+ identityMap = new IdentityMap_1.IdentityMap();
21
+ persistStack = new Set();
22
+ removeStack = new Set();
23
+ orphanRemoveStack = new Set();
24
+ changeSets = new Map();
25
+ collectionUpdates = new Set();
26
+ extraUpdates = new Set();
27
+ metadata;
28
+ platform;
29
+ eventManager;
30
+ comparator;
31
+ changeSetComputer;
32
+ changeSetPersister;
33
+ queuedActions = new Set();
34
+ loadedEntities = new Set();
35
+ flushQueue = [];
36
+ working = false;
37
+ constructor(em) {
38
+ this.em = em;
39
+ this.metadata = this.em.getMetadata();
40
+ this.platform = this.em.getPlatform();
41
+ this.eventManager = this.em.getEventManager();
42
+ this.comparator = this.em.getComparator();
43
+ this.changeSetComputer = new ChangeSetComputer_1.ChangeSetComputer(this.em.getValidator(), this.collectionUpdates, this.metadata, this.platform, this.em.config, this.em);
44
+ this.changeSetPersister = new ChangeSetPersister_1.ChangeSetPersister(this.em.getDriver(), this.metadata, this.em.config.getHydrator(this.metadata), this.em.getEntityFactory(), this.em.getValidator(), this.em.config);
45
+ }
46
+ merge(entity, visited) {
47
+ const wrapped = (0, entity_1.helper)(entity);
48
+ wrapped.__em = this.em;
49
+ if (!wrapped.hasPrimaryKey()) {
50
+ return;
51
+ }
52
+ // skip new entities that could be linked from already persisted entity
53
+ // that is being re-fetched (but allow calling `merge(e)` explicitly for those)
54
+ if (!wrapped.__managed && visited) {
55
+ return;
56
+ }
57
+ this.identityMap.store(entity);
58
+ // if visited is available, we are cascading, and need to be careful when resetting the entity data
59
+ // as there can be some entity with already changed state that is not yet flushed
60
+ if (wrapped.__initialized && (!visited || !wrapped.__originalEntityData)) {
61
+ wrapped.__originalEntityData = this.comparator.prepareEntity(entity);
62
+ wrapped.__touched = false;
63
+ }
64
+ this.cascade(entity, enums_1.Cascade.MERGE, visited ?? new Set());
65
+ }
66
+ /**
67
+ * @internal
68
+ */
69
+ register(entity, data, options) {
70
+ this.identityMap.store(entity);
71
+ entity_1.EntityHelper.ensurePropagation(entity);
72
+ if (options?.newEntity) {
73
+ return entity;
74
+ }
75
+ const wrapped = (0, entity_1.helper)(entity);
76
+ if (options?.loaded && wrapped.__initialized && !wrapped.__onLoadFired) {
77
+ this.loadedEntities.add(entity);
78
+ }
79
+ wrapped.__em ??= this.em;
80
+ wrapped.__managed = true;
81
+ if (data && (options?.refresh || !wrapped.__originalEntityData)) {
82
+ Object.keys(data).forEach((key) => wrapped.__loadedProperties.add(key));
83
+ wrapped.__meta.relations.forEach((prop) => {
84
+ if (Utils_1.Utils.isPlainObject(data[prop.name])) {
85
+ data[prop.name] = Utils_1.Utils.getPrimaryKeyValues(data[prop.name], prop.targetMeta.primaryKeys, true);
86
+ }
87
+ });
88
+ wrapped.__meta.props.forEach((prop) => {
89
+ if (prop.kind === enums_1.ReferenceKind.EMBEDDED &&
90
+ !prop.object &&
91
+ Utils_1.Utils.isPlainObject(data[prop.name])) {
92
+ prop.targetMeta?.props.forEach((p) => {
93
+ const prefix = prop.prefix === false
94
+ ? ""
95
+ : prop.prefix === true
96
+ ? prop.name + "_"
97
+ : prop.prefix;
98
+ data[(prefix + p.name)] =
99
+ data[prop.name][p.name];
100
+ });
101
+ data[prop.name] = Utils_1.Utils.getPrimaryKeyValues(data[prop.name], prop.targetMeta.primaryKeys, true);
102
+ }
103
+ });
104
+ if (this.em.config.get("forceUndefined")) {
105
+ Utils_1.Utils.keys(data).forEach((key) => {
106
+ if (data[key] === null) {
107
+ data[key] = undefined;
108
+ }
109
+ });
110
+ }
111
+ wrapped.__originalEntityData = data;
112
+ wrapped.__touched = false;
113
+ }
114
+ return entity;
115
+ }
116
+ /**
117
+ * @internal
118
+ */
119
+ async dispatchOnLoadEvent() {
120
+ for (const entity of this.loadedEntities) {
121
+ if (this.eventManager.hasListeners(enums_1.EventType.onLoad, entity.__meta)) {
122
+ await this.eventManager.dispatchEvent(enums_1.EventType.onLoad, {
123
+ entity,
124
+ meta: entity.__meta,
125
+ em: this.em,
126
+ });
127
+ (0, entity_1.helper)(entity).__onLoadFired = true;
128
+ }
129
+ }
130
+ this.loadedEntities.clear();
131
+ }
132
+ /**
133
+ * Returns entity from the identity map. For composite keys, you need to pass an array of PKs in the same order as they are defined in `meta.primaryKeys`.
134
+ */
135
+ getById(entityName, id, schema) {
136
+ if (id == null || (Array.isArray(id) && id.length === 0)) {
137
+ return undefined;
138
+ }
139
+ const meta = this.metadata.find(entityName).root;
140
+ let hash;
141
+ if (meta.simplePK) {
142
+ hash = "" + id;
143
+ }
144
+ else {
145
+ const keys = Array.isArray(id)
146
+ ? Utils_1.Utils.flatten(id)
147
+ : [id];
148
+ hash = Utils_1.Utils.getPrimaryKeyHash(keys);
149
+ }
150
+ schema ??= meta.schema ?? this.em.config.get("schema");
151
+ if (schema) {
152
+ hash = `${schema}:${hash}`;
153
+ }
154
+ return this.identityMap.getByHash(meta, hash);
155
+ }
156
+ tryGetById(entityName, where, schema, strict = true) {
157
+ const pk = Utils_1.Utils.extractPK(where, this.metadata.find(entityName), strict);
158
+ if (!pk) {
159
+ return null;
160
+ }
161
+ return this.getById(entityName, pk, schema);
162
+ }
163
+ /**
164
+ * Returns map of all managed entities.
165
+ */
166
+ getIdentityMap() {
167
+ return this.identityMap;
168
+ }
169
+ /**
170
+ * Returns stored snapshot of entity state that is used for change set computation.
171
+ */
172
+ getOriginalEntityData(entity) {
173
+ return (0, entity_1.helper)(entity).__originalEntityData;
174
+ }
175
+ getPersistStack() {
176
+ return this.persistStack;
177
+ }
178
+ getRemoveStack() {
179
+ return this.removeStack;
180
+ }
181
+ getChangeSets() {
182
+ return [...this.changeSets.values()];
183
+ }
184
+ getCollectionUpdates() {
185
+ return [...this.collectionUpdates];
186
+ }
187
+ getExtraUpdates() {
188
+ return this.extraUpdates;
189
+ }
190
+ shouldAutoFlush(meta) {
191
+ if (insideFlush.getStore()) {
192
+ return false;
193
+ }
194
+ if (this.queuedActions.has(meta.className) ||
195
+ this.queuedActions.has(meta.root.className)) {
196
+ return true;
197
+ }
198
+ for (const entity of this.identityMap.getStore(meta).values()) {
199
+ if ((0, entity_1.helper)(entity).__initialized && (0, entity_1.helper)(entity).isTouched()) {
200
+ return true;
201
+ }
202
+ }
203
+ return false;
204
+ }
205
+ clearActionsQueue() {
206
+ this.queuedActions.clear();
207
+ }
208
+ computeChangeSet(entity, type) {
209
+ const wrapped = (0, entity_1.helper)(entity);
210
+ if (type) {
211
+ this.changeSets.set(entity, new ChangeSet_1.ChangeSet(entity, type, {}, wrapped.__meta));
212
+ return;
213
+ }
214
+ const cs = this.changeSetComputer.computeChangeSet(entity);
215
+ if (!cs || this.checkUniqueProps(cs)) {
216
+ return;
217
+ }
218
+ this.initIdentifier(entity);
219
+ this.changeSets.set(entity, cs);
220
+ this.persistStack.delete(entity);
221
+ wrapped.__originalEntityData = this.comparator.prepareEntity(entity);
222
+ wrapped.__touched = false;
223
+ }
224
+ recomputeSingleChangeSet(entity) {
225
+ const changeSet = this.changeSets.get(entity);
226
+ if (!changeSet) {
227
+ return;
228
+ }
229
+ const cs = this.changeSetComputer.computeChangeSet(entity);
230
+ /* istanbul ignore else */
231
+ if (cs && !this.checkUniqueProps(cs)) {
232
+ Object.assign(changeSet.payload, cs.payload);
233
+ (0, entity_1.helper)(entity).__originalEntityData =
234
+ this.comparator.prepareEntity(entity);
235
+ (0, entity_1.helper)(entity).__touched = false;
236
+ }
237
+ }
238
+ persist(entity, visited, options = {}) {
239
+ entity_1.EntityHelper.ensurePropagation(entity);
240
+ if (options.checkRemoveStack && this.removeStack.has(entity)) {
241
+ return;
242
+ }
243
+ const wrapped = (0, entity_1.helper)(entity);
244
+ this.persistStack.add(entity);
245
+ this.queuedActions.add(wrapped.__meta.className);
246
+ this.removeStack.delete(entity);
247
+ if (!wrapped.__managed && wrapped.hasPrimaryKey()) {
248
+ this.identityMap.store(entity);
249
+ }
250
+ if (options.cascade ?? true) {
251
+ this.cascade(entity, enums_1.Cascade.PERSIST, visited, options);
252
+ }
253
+ }
254
+ remove(entity, visited, options = {}) {
255
+ // allow removing not managed entities if they are not part of the persist stack
256
+ if ((0, entity_1.helper)(entity).__managed || !this.persistStack.has(entity)) {
257
+ this.removeStack.add(entity);
258
+ this.queuedActions.add((0, entity_1.helper)(entity).__meta.className);
259
+ }
260
+ else {
261
+ this.persistStack.delete(entity);
262
+ this.identityMap.delete(entity);
263
+ }
264
+ // remove from referencing relations that are nullable
265
+ for (const prop of (0, entity_1.helper)(entity).__meta.bidirectionalRelations) {
266
+ const inverseProp = prop.mappedBy || prop.inversedBy;
267
+ const relation = entity_1.Reference.unwrapReference(entity[prop.name]);
268
+ const prop2 = prop.targetMeta.properties[inverseProp];
269
+ if (prop.kind === enums_1.ReferenceKind.ONE_TO_MANY &&
270
+ prop2.nullable &&
271
+ Utils_1.Utils.isCollection(relation)) {
272
+ relation.getItems(false).forEach((item) => delete item[inverseProp]);
273
+ continue;
274
+ }
275
+ const target = relation && relation[inverseProp];
276
+ if (relation && Utils_1.Utils.isCollection(target)) {
277
+ target.removeWithoutPropagation(entity);
278
+ }
279
+ }
280
+ if (options.cascade ?? true) {
281
+ this.cascade(entity, enums_1.Cascade.REMOVE, visited);
282
+ }
283
+ }
284
+ async commit() {
285
+ if (this.working) {
286
+ if (insideFlush.getStore()) {
287
+ throw errors_1.ValidationError.cannotCommit();
288
+ }
289
+ return new Promise((resolve, reject) => {
290
+ this.flushQueue.push(() => {
291
+ return insideFlush.run(true, () => {
292
+ return this.doCommit().then(resolve, reject);
293
+ });
294
+ });
295
+ });
296
+ }
297
+ try {
298
+ this.working = true;
299
+ await insideFlush.run(true, () => this.doCommit());
300
+ while (this.flushQueue.length) {
301
+ await this.flushQueue.shift()();
302
+ }
303
+ }
304
+ finally {
305
+ this.postCommitCleanup();
306
+ this.working = false;
307
+ }
308
+ }
309
+ async doCommit() {
310
+ const oldTx = this.em.getTransactionContext();
311
+ try {
312
+ await this.eventManager.dispatchEvent(enums_1.EventType.beforeFlush, {
313
+ em: this.em,
314
+ uow: this,
315
+ });
316
+ this.computeChangeSets();
317
+ this.changeSets.forEach((cs) => {
318
+ cs.entity.__helper.__processing = true;
319
+ });
320
+ await this.eventManager.dispatchEvent(enums_1.EventType.onFlush, {
321
+ em: this.em,
322
+ uow: this,
323
+ });
324
+ // nothing to do, do not start transaction
325
+ if (this.changeSets.size === 0 &&
326
+ this.collectionUpdates.size === 0 &&
327
+ this.extraUpdates.size === 0) {
328
+ return void (await this.eventManager.dispatchEvent(enums_1.EventType.afterFlush, { em: this.em, uow: this }));
329
+ }
330
+ const groups = this.getChangeSetGroups();
331
+ const platform = this.em.getPlatform();
332
+ const runInTransaction = !this.em.isInTransaction() &&
333
+ platform.supportsTransactions() &&
334
+ this.em.config.get("implicitTransactions");
335
+ if (runInTransaction) {
336
+ await this.em
337
+ .getConnection("write")
338
+ .transactional((trx) => this.persistToDatabase(groups, trx), {
339
+ ctx: oldTx,
340
+ eventBroadcaster: new events_1.TransactionEventBroadcaster(this.em, this),
341
+ });
342
+ }
343
+ else {
344
+ await this.persistToDatabase(groups, this.em.getTransactionContext());
345
+ }
346
+ this.resetTransaction(oldTx);
347
+ this.changeSets.forEach((cs) => {
348
+ cs.entity.__helper.__processing = false;
349
+ });
350
+ await this.eventManager.dispatchEvent(enums_1.EventType.afterFlush, {
351
+ em: this.em,
352
+ uow: this,
353
+ });
354
+ }
355
+ finally {
356
+ this.resetTransaction(oldTx);
357
+ }
358
+ }
359
+ async lock(entity, options) {
360
+ if (!this.getById(entity.constructor.name, (0, entity_1.helper)(entity).__primaryKeys, (0, entity_1.helper)(entity).__schema)) {
361
+ throw errors_1.ValidationError.entityNotManaged(entity);
362
+ }
363
+ const meta = this.metadata.find(entity.constructor.name);
364
+ if (options.lockMode === enums_1.LockMode.OPTIMISTIC) {
365
+ await this.lockOptimistic(entity, meta, options.lockVersion);
366
+ }
367
+ else if (options.lockMode != null) {
368
+ await this.lockPessimistic(entity, options);
369
+ }
370
+ }
371
+ clear() {
372
+ this.identityMap.clear();
373
+ this.loadedEntities.clear();
374
+ this.postCommitCleanup();
375
+ }
376
+ unsetIdentity(entity) {
377
+ this.identityMap.delete(entity);
378
+ const wrapped = (0, entity_1.helper)(entity);
379
+ // remove references of this entity in all managed entities, otherwise flushing could reinsert the entity
380
+ for (const { meta, prop } of wrapped.__meta.referencingProperties) {
381
+ for (const referrer of this.identityMap.getStore(meta).values()) {
382
+ const rel = entity_1.Reference.unwrapReference(referrer[prop.name]);
383
+ if (Utils_1.Utils.isCollection(rel)) {
384
+ rel.removeWithoutPropagation(entity);
385
+ }
386
+ else if (rel === entity) {
387
+ delete (0, entity_1.helper)(referrer).__data[prop.name];
388
+ }
389
+ }
390
+ }
391
+ delete wrapped.__identifier;
392
+ delete wrapped.__originalEntityData;
393
+ wrapped.__touched = false;
394
+ wrapped.__managed = false;
395
+ }
396
+ computeChangeSets() {
397
+ this.changeSets.clear();
398
+ const visited = new Set();
399
+ for (const entity of this.removeStack) {
400
+ this.cascade(entity, enums_1.Cascade.REMOVE, visited);
401
+ }
402
+ visited.clear();
403
+ for (const entity of this.persistStack) {
404
+ this.cascade(entity, enums_1.Cascade.PERSIST, visited, {
405
+ checkRemoveStack: true,
406
+ });
407
+ }
408
+ for (const entity of this.identityMap) {
409
+ if (!this.removeStack.has(entity) &&
410
+ !this.persistStack.has(entity) &&
411
+ !this.orphanRemoveStack.has(entity)) {
412
+ this.persistStack.add(entity);
413
+ this.cascade(entity, enums_1.Cascade.PERSIST, visited, {
414
+ checkRemoveStack: true,
415
+ });
416
+ }
417
+ }
418
+ visited.clear();
419
+ for (const entity of this.persistStack) {
420
+ this.findNewEntities(entity, visited);
421
+ }
422
+ for (const entity of this.orphanRemoveStack) {
423
+ if (!(0, entity_1.helper)(entity).__processing) {
424
+ this.removeStack.add(entity);
425
+ }
426
+ }
427
+ // Check insert stack if there are any entities matching something from delete stack. This can happen when recreating entities.
428
+ const inserts = {};
429
+ for (const cs of this.changeSets.values()) {
430
+ if (cs.type === ChangeSet_1.ChangeSetType.CREATE) {
431
+ inserts[cs.meta.className] ??= [];
432
+ inserts[cs.meta.className].push(cs);
433
+ }
434
+ }
435
+ for (const cs of this.changeSets.values()) {
436
+ if (cs.type === ChangeSet_1.ChangeSetType.UPDATE) {
437
+ this.findEarlyUpdates(cs, inserts[cs.meta.className]);
438
+ }
439
+ }
440
+ for (const entity of this.removeStack) {
441
+ const wrapped = (0, entity_1.helper)(entity);
442
+ /* istanbul ignore next */
443
+ if (wrapped.__processing) {
444
+ continue;
445
+ }
446
+ const deletePkHash = [
447
+ wrapped.getSerializedPrimaryKey(),
448
+ ...this.expandUniqueProps(entity),
449
+ ];
450
+ let type = ChangeSet_1.ChangeSetType.DELETE;
451
+ for (const cs of inserts[wrapped.__meta.className] ?? []) {
452
+ if (deletePkHash.some((hash) => hash === cs.getSerializedPrimaryKey() ||
453
+ this.expandUniqueProps(cs.entity).find((child) => hash === child))) {
454
+ type = ChangeSet_1.ChangeSetType.DELETE_EARLY;
455
+ }
456
+ }
457
+ this.computeChangeSet(entity, type);
458
+ }
459
+ }
460
+ scheduleExtraUpdate(changeSet, props) {
461
+ if (props.length === 0) {
462
+ return;
463
+ }
464
+ this.extraUpdates.add([
465
+ changeSet.entity,
466
+ props.map((p) => p.name),
467
+ props.map((p) => changeSet.entity[p.name]),
468
+ changeSet,
469
+ ]);
470
+ props.forEach((p) => delete changeSet.entity[p.name]);
471
+ props.forEach((p) => delete changeSet.payload[p.name]);
472
+ }
473
+ scheduleOrphanRemoval(entity, visited) {
474
+ if (entity) {
475
+ this.orphanRemoveStack.add(entity);
476
+ this.queuedActions.add(entity.__meta.className);
477
+ this.cascade(entity, enums_1.Cascade.SCHEDULE_ORPHAN_REMOVAL, visited);
478
+ }
479
+ }
480
+ cancelOrphanRemoval(entity, visited) {
481
+ this.orphanRemoveStack.delete(entity);
482
+ this.cascade(entity, enums_1.Cascade.CANCEL_ORPHAN_REMOVAL, visited);
483
+ }
484
+ getOrphanRemoveStack() {
485
+ return this.orphanRemoveStack;
486
+ }
487
+ getChangeSetPersister() {
488
+ return this.changeSetPersister;
489
+ }
490
+ findNewEntities(entity, visited, idx = 0, processed = new Set()) {
491
+ if (visited.has(entity)) {
492
+ return;
493
+ }
494
+ visited.add(entity);
495
+ processed.add(entity);
496
+ const wrapped = (0, entity_1.helper)(entity);
497
+ if (wrapped.__processing ||
498
+ this.removeStack.has(entity) ||
499
+ this.orphanRemoveStack.has(entity)) {
500
+ return;
501
+ }
502
+ // Set entityManager default schema
503
+ wrapped.__schema ??= this.em.schema;
504
+ this.initIdentifier(entity);
505
+ for (const prop of (0, entity_1.helper)(entity).__meta.relations) {
506
+ const targets = Utils_1.Utils.unwrapProperty(entity, (0, entity_1.helper)(entity).__meta, prop);
507
+ targets.forEach(([target]) => {
508
+ const kind = entity_1.Reference.unwrapReference(target);
509
+ this.processReference(entity, prop, kind, visited, processed, idx);
510
+ });
511
+ }
512
+ const changeSet = this.changeSetComputer.computeChangeSet(entity);
513
+ if (changeSet && !this.checkUniqueProps(changeSet)) {
514
+ this.changeSets.set(entity, changeSet);
515
+ }
516
+ }
517
+ /**
518
+ * Returns `true` when the change set should be skipped as it will be empty after the extra update.
519
+ */
520
+ checkUniqueProps(changeSet) {
521
+ if (this.platform.allowsUniqueBatchUpdates() ||
522
+ changeSet.type !== ChangeSet_1.ChangeSetType.UPDATE) {
523
+ return false;
524
+ }
525
+ // when changing a unique nullable property (or a 1:1 relation), we can't do it in a single query as it would cause unique constraint violations
526
+ const uniqueProps = changeSet.meta.uniqueProps.filter((prop) => prop.nullable && changeSet.payload[prop.name] != null);
527
+ this.scheduleExtraUpdate(changeSet, uniqueProps);
528
+ return (changeSet.type === ChangeSet_1.ChangeSetType.UPDATE &&
529
+ !Utils_1.Utils.hasObjectKeys(changeSet.payload));
530
+ }
531
+ expandUniqueProps(entity) {
532
+ const wrapped = (0, entity_1.helper)(entity);
533
+ if (!wrapped.__meta.hasUniqueProps) {
534
+ return [];
535
+ }
536
+ const simpleUniqueHashes = wrapped.__meta.uniqueProps
537
+ .map((prop) => {
538
+ if (entity[prop.name] != null) {
539
+ return prop.kind === enums_1.ReferenceKind.SCALAR || prop.mapToPk
540
+ ? entity[prop.name]
541
+ : (0, entity_1.helper)(entity[prop.name]).getSerializedPrimaryKey();
542
+ }
543
+ if (wrapped.__originalEntityData?.[prop.name] != null) {
544
+ return Utils_1.Utils.getPrimaryKeyHash(Utils_1.Utils.asArray(wrapped.__originalEntityData[prop.name]));
545
+ }
546
+ return undefined;
547
+ })
548
+ .filter((i) => i);
549
+ const compoundUniqueHashes = wrapped.__meta.uniques
550
+ .map((unique) => {
551
+ const props = Utils_1.Utils.asArray(unique.properties);
552
+ if (props.every((prop) => entity[prop] != null)) {
553
+ return Utils_1.Utils.getPrimaryKeyHash(props.map((p) => {
554
+ const prop = wrapped.__meta.properties[p];
555
+ return prop.kind === enums_1.ReferenceKind.SCALAR || prop.mapToPk
556
+ ? entity[prop.name]
557
+ : (0, entity_1.helper)(entity[prop.name]).getSerializedPrimaryKey();
558
+ }));
559
+ }
560
+ return undefined;
561
+ })
562
+ .filter((i) => i);
563
+ return simpleUniqueHashes.concat(compoundUniqueHashes);
564
+ }
565
+ initIdentifier(entity) {
566
+ const wrapped = entity && (0, entity_1.helper)(entity);
567
+ if (!wrapped || wrapped.__identifier || wrapped.hasPrimaryKey()) {
568
+ return;
569
+ }
570
+ const pk = wrapped.__meta.getPrimaryProps()[0];
571
+ if (pk.kind === enums_1.ReferenceKind.SCALAR) {
572
+ wrapped.__identifier = new entity_1.EntityIdentifier();
573
+ }
574
+ else if (entity[pk.name]) {
575
+ this.initIdentifier(entity[pk.name]);
576
+ wrapped.__identifier = (0, entity_1.helper)(entity[pk.name])?.__identifier;
577
+ }
578
+ }
579
+ processReference(parent, prop, kind, visited, processed, idx) {
580
+ const isToOne = prop.kind === enums_1.ReferenceKind.MANY_TO_ONE ||
581
+ prop.kind === enums_1.ReferenceKind.ONE_TO_ONE;
582
+ if (isToOne && Utils_1.Utils.isEntity(kind)) {
583
+ return this.processToOneReference(kind, visited, processed, idx);
584
+ }
585
+ if (Utils_1.Utils.isCollection(kind)) {
586
+ kind
587
+ .getItems(false)
588
+ .filter((item) => !item.__helper.__originalEntityData)
589
+ .forEach((item) => {
590
+ // propagate schema from parent
591
+ item.__helper.__schema ??= (0, entity_1.helper)(parent).__schema;
592
+ });
593
+ if (prop.kind === enums_1.ReferenceKind.MANY_TO_MANY && kind.isDirty()) {
594
+ this.processToManyReference(kind, visited, processed, parent, prop);
595
+ }
596
+ }
597
+ }
598
+ processToOneReference(kind, visited, processed, idx) {
599
+ if (!kind.__helper.__managed) {
600
+ this.findNewEntities(kind, visited, idx, processed);
601
+ }
602
+ }
603
+ processToManyReference(collection, visited, processed, parent, prop) {
604
+ if (this.isCollectionSelfReferenced(collection, processed)) {
605
+ this.extraUpdates.add([parent, prop.name, collection, undefined]);
606
+ const coll = new entity_1.Collection(parent);
607
+ coll.property = prop;
608
+ parent[prop.name] = coll;
609
+ return;
610
+ }
611
+ collection
612
+ .getItems(false)
613
+ .filter((item) => !item.__helper.__originalEntityData)
614
+ .forEach((item) => this.findNewEntities(item, visited, 0, processed));
615
+ }
616
+ async runHooks(type, changeSet, sync = false) {
617
+ const meta = changeSet.meta;
618
+ if (!this.eventManager.hasListeners(type, meta)) {
619
+ return;
620
+ }
621
+ if (!sync) {
622
+ await this.eventManager.dispatchEvent(type, {
623
+ entity: changeSet.entity,
624
+ meta,
625
+ em: this.em,
626
+ changeSet,
627
+ });
628
+ return;
629
+ }
630
+ const copy = this.comparator.prepareEntity(changeSet.entity);
631
+ await this.eventManager.dispatchEvent(type, {
632
+ entity: changeSet.entity,
633
+ meta,
634
+ em: this.em,
635
+ changeSet,
636
+ });
637
+ const current = this.comparator.prepareEntity(changeSet.entity);
638
+ const diff = this.comparator.diffEntities(changeSet.name, copy, current);
639
+ Object.assign(changeSet.payload, diff);
640
+ const wrapped = (0, entity_1.helper)(changeSet.entity);
641
+ if (wrapped.__identifier && diff[wrapped.__meta.primaryKeys[0]]) {
642
+ wrapped.__identifier.setValue(diff[wrapped.__meta.primaryKeys[0]]);
643
+ }
644
+ }
645
+ postCommitCleanup() {
646
+ this.changeSets.forEach((cs) => {
647
+ const wrapped = (0, entity_1.helper)(cs.entity);
648
+ wrapped.__processing = false;
649
+ delete wrapped.__pk;
650
+ });
651
+ this.persistStack.clear();
652
+ this.removeStack.clear();
653
+ this.orphanRemoveStack.clear();
654
+ this.changeSets.clear();
655
+ this.collectionUpdates.clear();
656
+ this.extraUpdates.clear();
657
+ this.queuedActions.clear();
658
+ this.working = false;
659
+ }
660
+ cascade(entity, type, visited = new Set(), options = {}) {
661
+ if (visited.has(entity)) {
662
+ return;
663
+ }
664
+ visited.add(entity);
665
+ switch (type) {
666
+ case enums_1.Cascade.PERSIST:
667
+ this.persist(entity, visited, options);
668
+ break;
669
+ case enums_1.Cascade.MERGE:
670
+ this.merge(entity, visited);
671
+ break;
672
+ case enums_1.Cascade.REMOVE:
673
+ this.remove(entity, visited, options);
674
+ break;
675
+ case enums_1.Cascade.SCHEDULE_ORPHAN_REMOVAL:
676
+ this.scheduleOrphanRemoval(entity, visited);
677
+ break;
678
+ case enums_1.Cascade.CANCEL_ORPHAN_REMOVAL:
679
+ this.cancelOrphanRemoval(entity, visited);
680
+ break;
681
+ }
682
+ for (const prop of (0, entity_1.helper)(entity).__meta.relations) {
683
+ this.cascadeReference(entity, prop, type, visited, options);
684
+ }
685
+ }
686
+ cascadeReference(entity, prop, type, visited, options) {
687
+ this.fixMissingReference(entity, prop);
688
+ if (!this.shouldCascade(prop, type)) {
689
+ return;
690
+ }
691
+ const kind = entity_1.Reference.unwrapReference(entity[prop.name]);
692
+ if ([enums_1.ReferenceKind.MANY_TO_ONE, enums_1.ReferenceKind.ONE_TO_ONE].includes(prop.kind) &&
693
+ Utils_1.Utils.isEntity(kind)) {
694
+ return this.cascade(kind, type, visited, options);
695
+ }
696
+ const collection = kind;
697
+ if ([enums_1.ReferenceKind.ONE_TO_MANY, enums_1.ReferenceKind.MANY_TO_MANY].includes(prop.kind) &&
698
+ collection) {
699
+ collection
700
+ .getItems(false)
701
+ .forEach((item) => this.cascade(item, type, visited, options));
702
+ }
703
+ }
704
+ isCollectionSelfReferenced(collection, processed) {
705
+ const filtered = collection
706
+ .getItems(false)
707
+ .filter((item) => !(0, entity_1.helper)(item).__originalEntityData);
708
+ return filtered.some((items) => processed.has(items));
709
+ }
710
+ shouldCascade(prop, type) {
711
+ if ([
712
+ enums_1.Cascade.REMOVE,
713
+ enums_1.Cascade.SCHEDULE_ORPHAN_REMOVAL,
714
+ enums_1.Cascade.CANCEL_ORPHAN_REMOVAL,
715
+ enums_1.Cascade.ALL,
716
+ ].includes(type) &&
717
+ prop.orphanRemoval) {
718
+ return true;
719
+ }
720
+ // ignore user settings for merge, it is kept only for back compatibility, this should have never been configurable
721
+ if (type === enums_1.Cascade.MERGE) {
722
+ return true;
723
+ }
724
+ return (prop.cascade &&
725
+ (prop.cascade.includes(type) || prop.cascade.includes(enums_1.Cascade.ALL)));
726
+ }
727
+ async lockPessimistic(entity, options) {
728
+ if (!this.em.isInTransaction()) {
729
+ throw errors_1.ValidationError.transactionRequired();
730
+ }
731
+ await this.em
732
+ .getDriver()
733
+ .lockPessimistic(entity, {
734
+ ctx: this.em.getTransactionContext(),
735
+ ...options,
736
+ });
737
+ }
738
+ async lockOptimistic(entity, meta, version) {
739
+ if (!meta.versionProperty) {
740
+ throw errors_1.OptimisticLockError.notVersioned(meta);
741
+ }
742
+ if (!Utils_1.Utils.isDefined(version)) {
743
+ return;
744
+ }
745
+ const wrapped = (0, entity_1.helper)(entity);
746
+ if (!wrapped.__initialized) {
747
+ await wrapped.init();
748
+ }
749
+ const previousVersion = entity[meta.versionProperty];
750
+ if (previousVersion !== version) {
751
+ throw errors_1.OptimisticLockError.lockFailedVersionMismatch(entity, version, previousVersion);
752
+ }
753
+ }
754
+ fixMissingReference(entity, prop) {
755
+ const reference = entity[prop.name];
756
+ const kind = entity_1.Reference.unwrapReference(reference);
757
+ if ([enums_1.ReferenceKind.MANY_TO_ONE, enums_1.ReferenceKind.ONE_TO_ONE].includes(prop.kind) &&
758
+ kind &&
759
+ !prop.mapToPk) {
760
+ if (!Utils_1.Utils.isEntity(kind)) {
761
+ entity[prop.name] = this.em.getReference(prop.type, kind, {
762
+ wrapped: !!prop.ref,
763
+ });
764
+ }
765
+ else if (!(0, entity_1.helper)(kind).__initialized && !(0, entity_1.helper)(kind).__em) {
766
+ const pk = (0, entity_1.helper)(kind).getPrimaryKey();
767
+ entity[prop.name] = this.em.getReference(prop.type, pk, {
768
+ wrapped: !!prop.ref,
769
+ });
770
+ }
771
+ }
772
+ // perf: set the `Collection._property` to skip the getter, as it can be slow when there is a lot of relations
773
+ if (Utils_1.Utils.isCollection(kind)) {
774
+ kind.property = prop;
775
+ }
776
+ const isCollection = [
777
+ enums_1.ReferenceKind.ONE_TO_MANY,
778
+ enums_1.ReferenceKind.MANY_TO_MANY,
779
+ ].includes(prop.kind);
780
+ if (isCollection && Array.isArray(kind)) {
781
+ const collection = new entity_1.Collection(entity);
782
+ collection.property = prop;
783
+ entity[prop.name] = collection;
784
+ collection.set(kind);
785
+ }
786
+ }
787
+ async persistToDatabase(groups, ctx) {
788
+ if (ctx) {
789
+ this.em.setTransactionContext(ctx);
790
+ }
791
+ const commitOrder = this.getCommitOrder();
792
+ const commitOrderReversed = [...commitOrder].reverse();
793
+ // 1. early delete - when we recreate entity in the same UoW, we need to issue those delete queries before inserts
794
+ for (const name of commitOrderReversed) {
795
+ await this.commitDeleteChangeSets(groups[ChangeSet_1.ChangeSetType.DELETE_EARLY].get(name) ?? [], ctx);
796
+ }
797
+ // 2. early update - when we recreate entity in the same UoW, we need to issue those delete queries before inserts
798
+ for (const name of commitOrder) {
799
+ await this.commitUpdateChangeSets(groups[ChangeSet_1.ChangeSetType.UPDATE_EARLY].get(name) ?? [], ctx);
800
+ }
801
+ // 3. create
802
+ for (const name of commitOrder) {
803
+ await this.commitCreateChangeSets(groups[ChangeSet_1.ChangeSetType.CREATE].get(name) ?? [], ctx);
804
+ }
805
+ // 4. update
806
+ for (const name of commitOrder) {
807
+ await this.commitUpdateChangeSets(groups[ChangeSet_1.ChangeSetType.UPDATE].get(name) ?? [], ctx);
808
+ }
809
+ // 5. extra updates
810
+ await this.commitExtraUpdates(ctx);
811
+ // 6. collection updates
812
+ await this.em.getDriver().syncCollections(this.collectionUpdates, { ctx });
813
+ for (const coll of this.collectionUpdates) {
814
+ coll.takeSnapshot();
815
+ }
816
+ // 7. delete - entity deletions need to be in reverse commit order
817
+ for (const name of commitOrderReversed) {
818
+ await this.commitDeleteChangeSets(groups[ChangeSet_1.ChangeSetType.DELETE].get(name) ?? [], ctx);
819
+ }
820
+ // 8. take snapshots of all persisted collections
821
+ const visited = new Set();
822
+ for (const changeSet of this.changeSets.values()) {
823
+ this.takeCollectionSnapshots(changeSet.entity, visited);
824
+ }
825
+ }
826
+ async commitCreateChangeSets(changeSets, ctx) {
827
+ if (changeSets.length === 0) {
828
+ return;
829
+ }
830
+ const props = changeSets[0].meta.root.relations.filter((prop) => {
831
+ return ((prop.kind === enums_1.ReferenceKind.ONE_TO_ONE && prop.owner) ||
832
+ prop.kind === enums_1.ReferenceKind.MANY_TO_ONE ||
833
+ (prop.kind === enums_1.ReferenceKind.MANY_TO_MANY &&
834
+ prop.owner &&
835
+ !this.platform.usesPivotTable()));
836
+ });
837
+ for (const changeSet of changeSets) {
838
+ this.findExtraUpdates(changeSet, props);
839
+ await this.runHooks(enums_1.EventType.beforeCreate, changeSet, true);
840
+ }
841
+ await this.changeSetPersister.executeInserts(changeSets, { ctx });
842
+ for (const changeSet of changeSets) {
843
+ this.register(changeSet.entity, changeSet.payload, { refresh: true });
844
+ await this.runHooks(enums_1.EventType.afterCreate, changeSet);
845
+ }
846
+ }
847
+ findExtraUpdates(changeSet, props) {
848
+ for (const prop of props) {
849
+ const ref = changeSet.entity[prop.name];
850
+ if (!ref) {
851
+ continue;
852
+ }
853
+ if (Utils_1.Utils.isCollection(ref)) {
854
+ ref.getItems(false).some((item) => {
855
+ const cs = this.changeSets.get(entity_1.Reference.unwrapReference(item));
856
+ const isScheduledForInsert = cs && cs.type === ChangeSet_1.ChangeSetType.CREATE && !cs.persisted;
857
+ if (isScheduledForInsert) {
858
+ this.scheduleExtraUpdate(changeSet, [prop]);
859
+ return true;
860
+ }
861
+ return false;
862
+ });
863
+ }
864
+ const cs = this.changeSets.get(entity_1.Reference.unwrapReference(ref));
865
+ const isScheduledForInsert = cs && cs.type === ChangeSet_1.ChangeSetType.CREATE && !cs.persisted;
866
+ if (isScheduledForInsert) {
867
+ this.scheduleExtraUpdate(changeSet, [prop]);
868
+ }
869
+ }
870
+ }
871
+ findEarlyUpdates(changeSet, inserts = []) {
872
+ const props = changeSet.meta.uniqueProps;
873
+ for (const prop of props) {
874
+ const insert = inserts.find((c) => Utils_1.Utils.equals(c.payload[prop.name], changeSet.originalEntity[prop.name]));
875
+ const propEmpty = changeSet.payload[prop.name] === null ||
876
+ changeSet.payload[prop.name] === undefined;
877
+ if (prop.name in changeSet.payload &&
878
+ insert &&
879
+ // We only want to update early if the unique property on the changeset is going to be empty, so that
880
+ // the previous unique value can be set on a different entity without constraint issues
881
+ propEmpty) {
882
+ changeSet.type = ChangeSet_1.ChangeSetType.UPDATE_EARLY;
883
+ }
884
+ }
885
+ }
886
+ async commitUpdateChangeSets(changeSets, ctx, batched = true) {
887
+ if (changeSets.length === 0) {
888
+ return;
889
+ }
890
+ for (const changeSet of changeSets) {
891
+ await this.runHooks(enums_1.EventType.beforeUpdate, changeSet, true);
892
+ }
893
+ await this.changeSetPersister.executeUpdates(changeSets, batched, { ctx });
894
+ for (const changeSet of changeSets) {
895
+ (0, entity_1.helper)(changeSet.entity).__originalEntityData =
896
+ this.comparator.prepareEntity(changeSet.entity);
897
+ (0, entity_1.helper)(changeSet.entity).__touched = false;
898
+ (0, entity_1.helper)(changeSet.entity).__initialized = true;
899
+ await this.runHooks(enums_1.EventType.afterUpdate, changeSet);
900
+ }
901
+ }
902
+ async commitDeleteChangeSets(changeSets, ctx) {
903
+ if (changeSets.length === 0) {
904
+ return;
905
+ }
906
+ for (const changeSet of changeSets) {
907
+ await this.runHooks(enums_1.EventType.beforeDelete, changeSet, true);
908
+ }
909
+ await this.changeSetPersister.executeDeletes(changeSets, { ctx });
910
+ for (const changeSet of changeSets) {
911
+ this.unsetIdentity(changeSet.entity);
912
+ await this.runHooks(enums_1.EventType.afterDelete, changeSet);
913
+ }
914
+ }
915
+ async commitExtraUpdates(ctx) {
916
+ const extraUpdates = [];
917
+ for (const extraUpdate of this.extraUpdates) {
918
+ if (Array.isArray(extraUpdate[1])) {
919
+ extraUpdate[1].forEach((p, i) => (extraUpdate[0][p] = extraUpdate[2][i]));
920
+ }
921
+ else {
922
+ extraUpdate[0][extraUpdate[1]] = extraUpdate[2];
923
+ }
924
+ const changeSet = this.changeSetComputer.computeChangeSet(extraUpdate[0]);
925
+ if (changeSet) {
926
+ extraUpdates.push([changeSet, extraUpdate[3]]);
927
+ }
928
+ }
929
+ await this.commitUpdateChangeSets(extraUpdates.map((u) => u[0]), ctx, false);
930
+ // propagate the new values to the original changeset
931
+ for (const extraUpdate of extraUpdates) {
932
+ if (extraUpdate[1]) {
933
+ Object.assign(extraUpdate[1].payload, extraUpdate[0].payload);
934
+ }
935
+ }
936
+ }
937
+ /**
938
+ * Orders change sets so FK constrains are maintained, ensures stable order (needed for node < 11)
939
+ */
940
+ getChangeSetGroups() {
941
+ const groups = {
942
+ [ChangeSet_1.ChangeSetType.CREATE]: new Map(),
943
+ [ChangeSet_1.ChangeSetType.UPDATE]: new Map(),
944
+ [ChangeSet_1.ChangeSetType.DELETE]: new Map(),
945
+ [ChangeSet_1.ChangeSetType.UPDATE_EARLY]: new Map(),
946
+ [ChangeSet_1.ChangeSetType.DELETE_EARLY]: new Map(),
947
+ };
948
+ this.changeSets.forEach((cs) => {
949
+ const group = groups[cs.type];
950
+ const classGroup = group.get(cs.name) ?? [];
951
+ classGroup.push(cs);
952
+ if (!group.has(cs.name)) {
953
+ group.set(cs.name, classGroup);
954
+ }
955
+ });
956
+ return groups;
957
+ }
958
+ getCommitOrder() {
959
+ // add only roots with all the properties of their children to make ordering easier
960
+ const calc = new CommitOrderCalculator_1.CommitOrderCalculator();
961
+ const set = new Set();
962
+ const rootMap = new Map();
963
+ this.changeSets.forEach((cs) => {
964
+ const { name, rootName } = cs;
965
+ set.add(name);
966
+ if (!rootMap.has(rootName)) {
967
+ rootMap.set(rootName, new Set());
968
+ }
969
+ rootMap.get(rootName).add(name);
970
+ });
971
+ const rootSet = Array.from(rootMap.keys());
972
+ rootSet.forEach((entityName) => calc.addNode(entityName));
973
+ for (const entityName of set) {
974
+ const meta = this.metadata.find(entityName);
975
+ for (const prop of meta.props) {
976
+ calc.discoverProperty(prop, meta.root.name);
977
+ }
978
+ }
979
+ // re-map to children
980
+ return calc
981
+ .sort()
982
+ .map((rootName) => rootMap.get(rootName))
983
+ .reduce((groups, curr) => [...groups, ...curr.values()], []);
984
+ }
985
+ resetTransaction(oldTx) {
986
+ if (oldTx) {
987
+ this.em.setTransactionContext(oldTx);
988
+ }
989
+ else {
990
+ this.em.resetTransactionContext();
991
+ }
992
+ }
993
+ /**
994
+ * Takes snapshots of all processed collections
995
+ */
996
+ takeCollectionSnapshots(entity, visited) {
997
+ if (visited.has(entity)) {
998
+ return;
999
+ }
1000
+ visited.add(entity);
1001
+ (0, entity_1.helper)(entity)?.__meta.relations.forEach((prop) => {
1002
+ const value = entity[prop.name];
1003
+ if (Utils_1.Utils.isCollection(value)) {
1004
+ value.takeSnapshot();
1005
+ }
1006
+ // cascade to m:1 relations as we need to snapshot the 1:m inverse side (for `removeAll()` with orphan removal)
1007
+ if (prop.kind === enums_1.ReferenceKind.MANY_TO_ONE && value) {
1008
+ this.takeCollectionSnapshots(entity_1.Reference.unwrapReference(value), visited);
1009
+ }
1010
+ });
1011
+ }
1012
+ }
1013
+ exports.UnitOfWork = UnitOfWork;