@mikro-orm/core 7.0.0-dev.1 → 7.0.0-dev.100

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 (281) hide show
  1. package/EntityManager.d.ts +96 -58
  2. package/EntityManager.js +465 -395
  3. package/MikroORM.d.ts +45 -35
  4. package/MikroORM.js +109 -160
  5. package/README.md +3 -2
  6. package/cache/CacheAdapter.js +1 -2
  7. package/cache/FileCacheAdapter.d.ts +2 -2
  8. package/cache/FileCacheAdapter.js +20 -27
  9. package/cache/GeneratedCacheAdapter.d.ts +2 -3
  10. package/cache/GeneratedCacheAdapter.js +1 -7
  11. package/cache/MemoryCacheAdapter.d.ts +1 -1
  12. package/cache/MemoryCacheAdapter.js +1 -5
  13. package/cache/NullCacheAdapter.d.ts +1 -1
  14. package/cache/NullCacheAdapter.js +1 -5
  15. package/cache/index.d.ts +4 -5
  16. package/cache/index.js +4 -21
  17. package/connections/Connection.d.ts +22 -14
  18. package/connections/Connection.js +27 -23
  19. package/connections/index.d.ts +1 -1
  20. package/connections/index.js +1 -17
  21. package/drivers/DatabaseDriver.d.ts +25 -15
  22. package/drivers/DatabaseDriver.js +77 -64
  23. package/drivers/IDatabaseDriver.d.ts +40 -16
  24. package/drivers/IDatabaseDriver.js +1 -4
  25. package/drivers/index.d.ts +2 -2
  26. package/drivers/index.js +2 -18
  27. package/entity/BaseEntity.d.ts +6 -7
  28. package/entity/BaseEntity.js +16 -23
  29. package/entity/Collection.d.ts +98 -34
  30. package/entity/Collection.js +466 -131
  31. package/entity/EntityAssigner.d.ts +3 -3
  32. package/entity/EntityAssigner.js +67 -64
  33. package/entity/EntityFactory.d.ts +10 -3
  34. package/entity/EntityFactory.js +112 -91
  35. package/entity/EntityHelper.d.ts +2 -2
  36. package/entity/EntityHelper.js +66 -53
  37. package/entity/EntityIdentifier.d.ts +1 -1
  38. package/entity/EntityIdentifier.js +1 -5
  39. package/entity/EntityLoader.d.ts +8 -7
  40. package/entity/EntityLoader.js +161 -128
  41. package/entity/EntityRepository.d.ts +8 -8
  42. package/entity/EntityRepository.js +7 -11
  43. package/entity/Reference.d.ts +10 -13
  44. package/entity/Reference.js +64 -46
  45. package/entity/WrappedEntity.d.ts +12 -17
  46. package/entity/WrappedEntity.js +22 -31
  47. package/entity/defineEntity.d.ts +568 -0
  48. package/entity/defineEntity.js +529 -0
  49. package/entity/index.d.ts +14 -13
  50. package/entity/index.js +14 -29
  51. package/entity/utils.d.ts +8 -1
  52. package/entity/utils.js +22 -13
  53. package/entity/validators.d.ts +11 -0
  54. package/entity/validators.js +65 -0
  55. package/entity/wrap.d.ts +1 -1
  56. package/entity/wrap.js +2 -6
  57. package/enums.d.ts +24 -9
  58. package/enums.js +50 -41
  59. package/errors.d.ts +11 -3
  60. package/errors.js +42 -32
  61. package/events/EventManager.d.ts +5 -4
  62. package/events/EventManager.js +26 -22
  63. package/events/EventSubscriber.d.ts +8 -5
  64. package/events/EventSubscriber.js +1 -2
  65. package/events/TransactionEventBroadcaster.d.ts +3 -3
  66. package/events/TransactionEventBroadcaster.js +1 -5
  67. package/events/index.d.ts +3 -3
  68. package/events/index.js +3 -19
  69. package/exceptions.js +18 -39
  70. package/hydration/Hydrator.d.ts +5 -5
  71. package/hydration/Hydrator.js +2 -6
  72. package/hydration/ObjectHydrator.d.ts +7 -7
  73. package/hydration/ObjectHydrator.js +58 -50
  74. package/hydration/index.d.ts +2 -2
  75. package/hydration/index.js +2 -18
  76. package/index.d.ts +21 -21
  77. package/index.js +20 -46
  78. package/logging/DefaultLogger.d.ts +2 -2
  79. package/logging/DefaultLogger.js +10 -13
  80. package/logging/Logger.d.ts +1 -1
  81. package/logging/Logger.js +1 -2
  82. package/logging/SimpleLogger.d.ts +3 -3
  83. package/logging/SimpleLogger.js +2 -6
  84. package/logging/colors.js +1 -5
  85. package/logging/index.d.ts +5 -4
  86. package/logging/index.js +5 -20
  87. package/logging/inspect.d.ts +2 -0
  88. package/logging/inspect.js +16 -0
  89. package/metadata/EntitySchema.d.ts +14 -10
  90. package/metadata/EntitySchema.js +78 -64
  91. package/metadata/MetadataDiscovery.d.ts +11 -14
  92. package/metadata/MetadataDiscovery.js +278 -317
  93. package/metadata/MetadataProvider.d.ts +13 -4
  94. package/metadata/MetadataProvider.js +47 -8
  95. package/metadata/MetadataStorage.d.ts +2 -7
  96. package/metadata/MetadataStorage.js +19 -35
  97. package/metadata/MetadataValidator.d.ts +3 -10
  98. package/metadata/MetadataValidator.js +51 -64
  99. package/metadata/discover-entities.d.ts +5 -0
  100. package/metadata/discover-entities.js +40 -0
  101. package/metadata/index.d.ts +6 -6
  102. package/metadata/index.js +6 -22
  103. package/metadata/types.d.ts +480 -0
  104. package/metadata/types.js +1 -0
  105. package/naming-strategy/AbstractNamingStrategy.d.ts +7 -3
  106. package/naming-strategy/AbstractNamingStrategy.js +11 -9
  107. package/naming-strategy/EntityCaseNamingStrategy.d.ts +1 -1
  108. package/naming-strategy/EntityCaseNamingStrategy.js +2 -6
  109. package/naming-strategy/MongoNamingStrategy.d.ts +1 -1
  110. package/naming-strategy/MongoNamingStrategy.js +2 -6
  111. package/naming-strategy/NamingStrategy.d.ts +12 -2
  112. package/naming-strategy/NamingStrategy.js +1 -2
  113. package/naming-strategy/UnderscoreNamingStrategy.d.ts +1 -1
  114. package/naming-strategy/UnderscoreNamingStrategy.js +2 -6
  115. package/naming-strategy/index.d.ts +5 -5
  116. package/naming-strategy/index.js +5 -21
  117. package/not-supported.d.ts +2 -0
  118. package/not-supported.js +4 -0
  119. package/package.json +19 -20
  120. package/platforms/ExceptionConverter.d.ts +2 -2
  121. package/platforms/ExceptionConverter.js +4 -8
  122. package/platforms/Platform.d.ts +15 -22
  123. package/platforms/Platform.js +58 -88
  124. package/platforms/index.d.ts +2 -2
  125. package/platforms/index.js +2 -18
  126. package/serialization/EntitySerializer.d.ts +4 -2
  127. package/serialization/EntitySerializer.js +64 -51
  128. package/serialization/EntityTransformer.d.ts +1 -1
  129. package/serialization/EntityTransformer.js +48 -42
  130. package/serialization/SerializationContext.d.ts +2 -2
  131. package/serialization/SerializationContext.js +24 -25
  132. package/serialization/index.d.ts +3 -3
  133. package/serialization/index.js +3 -19
  134. package/types/ArrayType.d.ts +3 -3
  135. package/types/ArrayType.js +6 -11
  136. package/types/BigIntType.d.ts +12 -9
  137. package/types/BigIntType.js +6 -6
  138. package/types/BlobType.d.ts +3 -4
  139. package/types/BlobType.js +2 -11
  140. package/types/BooleanType.d.ts +5 -4
  141. package/types/BooleanType.js +5 -6
  142. package/types/CharacterType.d.ts +3 -3
  143. package/types/CharacterType.js +2 -6
  144. package/types/DateTimeType.d.ts +3 -3
  145. package/types/DateTimeType.js +2 -6
  146. package/types/DateType.d.ts +3 -3
  147. package/types/DateType.js +2 -6
  148. package/types/DecimalType.d.ts +9 -7
  149. package/types/DecimalType.js +5 -8
  150. package/types/DoubleType.d.ts +3 -3
  151. package/types/DoubleType.js +4 -7
  152. package/types/EnumArrayType.d.ts +4 -4
  153. package/types/EnumArrayType.js +4 -10
  154. package/types/EnumType.d.ts +3 -3
  155. package/types/EnumType.js +2 -6
  156. package/types/FloatType.d.ts +3 -3
  157. package/types/FloatType.js +2 -6
  158. package/types/IntegerType.d.ts +3 -3
  159. package/types/IntegerType.js +2 -6
  160. package/types/IntervalType.d.ts +3 -3
  161. package/types/IntervalType.js +2 -6
  162. package/types/JsonType.d.ts +4 -4
  163. package/types/JsonType.js +9 -8
  164. package/types/MediumIntType.d.ts +3 -3
  165. package/types/MediumIntType.js +2 -6
  166. package/types/SmallIntType.d.ts +3 -3
  167. package/types/SmallIntType.js +2 -6
  168. package/types/StringType.d.ts +3 -3
  169. package/types/StringType.js +2 -6
  170. package/types/TextType.d.ts +3 -3
  171. package/types/TextType.js +2 -6
  172. package/types/TimeType.d.ts +3 -3
  173. package/types/TimeType.js +4 -8
  174. package/types/TinyIntType.d.ts +3 -3
  175. package/types/TinyIntType.js +3 -6
  176. package/types/Type.d.ts +4 -6
  177. package/types/Type.js +6 -10
  178. package/types/Uint8ArrayType.d.ts +3 -4
  179. package/types/Uint8ArrayType.js +3 -12
  180. package/types/UnknownType.d.ts +3 -3
  181. package/types/UnknownType.js +2 -6
  182. package/types/UuidType.d.ts +3 -3
  183. package/types/UuidType.js +2 -6
  184. package/types/index.d.ts +25 -25
  185. package/types/index.js +52 -79
  186. package/typings.d.ts +134 -93
  187. package/typings.js +67 -65
  188. package/unit-of-work/ChangeSet.d.ts +1 -4
  189. package/unit-of-work/ChangeSet.js +13 -17
  190. package/unit-of-work/ChangeSetComputer.d.ts +8 -9
  191. package/unit-of-work/ChangeSetComputer.js +36 -38
  192. package/unit-of-work/ChangeSetPersister.d.ts +11 -9
  193. package/unit-of-work/ChangeSetPersister.js +100 -65
  194. package/unit-of-work/CommitOrderCalculator.d.ts +1 -1
  195. package/unit-of-work/CommitOrderCalculator.js +6 -10
  196. package/unit-of-work/IdentityMap.d.ts +1 -1
  197. package/unit-of-work/IdentityMap.js +1 -5
  198. package/unit-of-work/UnitOfWork.d.ts +16 -8
  199. package/unit-of-work/UnitOfWork.js +266 -209
  200. package/unit-of-work/index.d.ts +6 -6
  201. package/unit-of-work/index.js +6 -22
  202. package/utils/AbstractSchemaGenerator.d.ts +11 -11
  203. package/utils/AbstractSchemaGenerator.js +21 -20
  204. package/utils/Configuration.d.ts +774 -224
  205. package/utils/Configuration.js +166 -216
  206. package/utils/ConfigurationLoader.d.ts +1 -53
  207. package/utils/ConfigurationLoader.js +1 -367
  208. package/utils/Cursor.d.ts +6 -9
  209. package/utils/Cursor.js +25 -25
  210. package/utils/DataloaderUtils.d.ts +18 -8
  211. package/utils/DataloaderUtils.js +63 -21
  212. package/utils/EntityComparator.d.ts +9 -5
  213. package/utils/EntityComparator.js +155 -108
  214. package/utils/NullHighlighter.d.ts +1 -1
  215. package/utils/NullHighlighter.js +1 -5
  216. package/utils/QueryHelper.d.ts +12 -4
  217. package/utils/QueryHelper.js +110 -53
  218. package/utils/RawQueryFragment.d.ts +37 -14
  219. package/utils/RawQueryFragment.js +50 -33
  220. package/utils/RequestContext.d.ts +2 -2
  221. package/utils/RequestContext.js +3 -7
  222. package/utils/TransactionContext.d.ts +1 -1
  223. package/utils/TransactionContext.js +4 -8
  224. package/utils/TransactionManager.d.ts +65 -0
  225. package/utils/TransactionManager.js +223 -0
  226. package/utils/Utils.d.ts +16 -100
  227. package/utils/Utils.js +114 -332
  228. package/utils/clone.js +7 -11
  229. package/utils/env-vars.d.ts +3 -0
  230. package/utils/env-vars.js +87 -0
  231. package/utils/fs-utils.d.ts +12 -0
  232. package/utils/fs-utils.js +97 -0
  233. package/utils/index.d.ts +14 -13
  234. package/utils/index.js +14 -29
  235. package/utils/upsert-utils.d.ts +8 -3
  236. package/utils/upsert-utils.js +57 -10
  237. package/decorators/Check.d.ts +0 -3
  238. package/decorators/Check.js +0 -16
  239. package/decorators/CreateRequestContext.d.ts +0 -3
  240. package/decorators/CreateRequestContext.js +0 -33
  241. package/decorators/Embeddable.d.ts +0 -8
  242. package/decorators/Embeddable.js +0 -14
  243. package/decorators/Embedded.d.ts +0 -18
  244. package/decorators/Embedded.js +0 -20
  245. package/decorators/Entity.d.ts +0 -18
  246. package/decorators/Entity.js +0 -16
  247. package/decorators/Enum.d.ts +0 -9
  248. package/decorators/Enum.js +0 -19
  249. package/decorators/Filter.d.ts +0 -2
  250. package/decorators/Filter.js +0 -11
  251. package/decorators/Formula.d.ts +0 -5
  252. package/decorators/Formula.js +0 -18
  253. package/decorators/Indexed.d.ts +0 -17
  254. package/decorators/Indexed.js +0 -24
  255. package/decorators/ManyToMany.d.ts +0 -40
  256. package/decorators/ManyToMany.js +0 -16
  257. package/decorators/ManyToOne.d.ts +0 -30
  258. package/decorators/ManyToOne.js +0 -16
  259. package/decorators/OneToMany.d.ts +0 -28
  260. package/decorators/OneToMany.js +0 -20
  261. package/decorators/OneToOne.d.ts +0 -24
  262. package/decorators/OneToOne.js +0 -10
  263. package/decorators/PrimaryKey.d.ts +0 -9
  264. package/decorators/PrimaryKey.js +0 -23
  265. package/decorators/Property.d.ts +0 -250
  266. package/decorators/Property.js +0 -34
  267. package/decorators/Transactional.d.ts +0 -13
  268. package/decorators/Transactional.js +0 -31
  269. package/decorators/hooks.d.ts +0 -16
  270. package/decorators/hooks.js +0 -59
  271. package/decorators/index.d.ts +0 -17
  272. package/decorators/index.js +0 -36
  273. package/entity/ArrayCollection.d.ts +0 -116
  274. package/entity/ArrayCollection.js +0 -399
  275. package/entity/EntityValidator.d.ts +0 -19
  276. package/entity/EntityValidator.js +0 -154
  277. package/index.mjs +0 -199
  278. package/metadata/ReflectMetadataProvider.d.ts +0 -8
  279. package/metadata/ReflectMetadataProvider.js +0 -48
  280. package/utils/resolveContextProvider.d.ts +0 -10
  281. package/utils/resolveContextProvider.js +0 -31
package/EntityManager.js CHANGED
@@ -1,29 +1,30 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.EntityManager = void 0;
7
- const node_util_1 = require("node:util");
8
- const dataloader_1 = __importDefault(require("dataloader"));
9
- const upsert_utils_1 = require("./utils/upsert-utils");
10
- const Utils_1 = require("./utils/Utils");
11
- const Cursor_1 = require("./utils/Cursor");
12
- const DataloaderUtils_1 = require("./utils/DataloaderUtils");
13
- const QueryHelper_1 = require("./utils/QueryHelper");
14
- const TransactionContext_1 = require("./utils/TransactionContext");
15
- const RawQueryFragment_1 = require("./utils/RawQueryFragment");
16
- const entity_1 = require("./entity");
17
- const unit_of_work_1 = require("./unit-of-work");
18
- const enums_1 = require("./enums");
19
- const events_1 = require("./events");
20
- const errors_1 = require("./errors");
1
+ import { getOnConflictReturningFields, getWhereCondition } from './utils/upsert-utils.js';
2
+ import { Utils } from './utils/Utils.js';
3
+ import { Cursor } from './utils/Cursor.js';
4
+ import { DataloaderUtils } from './utils/DataloaderUtils.js';
5
+ import { QueryHelper } from './utils/QueryHelper.js';
6
+ import { TransactionContext } from './utils/TransactionContext.js';
7
+ import { isRaw, RawQueryFragment } from './utils/RawQueryFragment.js';
8
+ import { EntityFactory } from './entity/EntityFactory.js';
9
+ import { EntityAssigner } from './entity/EntityAssigner.js';
10
+ import { validateEmptyWhere, validateParams, validatePrimaryKey, validateProperty } from './entity/validators.js';
11
+ import { EntityLoader } from './entity/EntityLoader.js';
12
+ import { Reference } from './entity/Reference.js';
13
+ import { helper } from './entity/wrap.js';
14
+ import { ChangeSet, ChangeSetType } from './unit-of-work/ChangeSet.js';
15
+ import { UnitOfWork } from './unit-of-work/UnitOfWork.js';
16
+ import { EventType, FlushMode, LoadStrategy, LockMode, PopulateHint, PopulatePath, QueryFlag, ReferenceKind, SCALAR_TYPES, } from './enums.js';
17
+ import { EventManager } from './events/EventManager.js';
18
+ import { TransactionEventBroadcaster } from './events/TransactionEventBroadcaster.js';
19
+ import { OptimisticLockError, ValidationError } from './errors.js';
20
+ import { getLoadingStrategy } from './entity/utils.js';
21
+ import { TransactionManager } from './utils/TransactionManager.js';
21
22
  /**
22
23
  * The EntityManager is the central access point to ORM functionality. It is a facade to all different ORM subsystems
23
24
  * such as UnitOfWork, Query Language, and Repository API.
24
25
  * @template {IDatabaseDriver} Driver current driver type
25
26
  */
26
- class EntityManager {
27
+ export class EntityManager {
27
28
  config;
28
29
  driver;
29
30
  metadata;
@@ -33,9 +34,7 @@ class EntityManager {
33
34
  _id = EntityManager.counter++;
34
35
  global = false;
35
36
  name;
36
- refLoader = new dataloader_1.default(DataloaderUtils_1.DataloaderUtils.getRefBatchLoadFn(this));
37
- colLoader = new dataloader_1.default(DataloaderUtils_1.DataloaderUtils.getColBatchLoadFn(this));
38
- validator;
37
+ loaders = {};
39
38
  repositoryMap = {};
40
39
  entityLoader;
41
40
  comparator;
@@ -52,20 +51,19 @@ class EntityManager {
52
51
  /**
53
52
  * @internal
54
53
  */
55
- constructor(config, driver, metadata, useContext = true, eventManager = new events_1.EventManager(config.get('subscribers'))) {
54
+ constructor(config, driver, metadata, useContext = true, eventManager = new EventManager(config.get('subscribers'))) {
56
55
  this.config = config;
57
56
  this.driver = driver;
58
57
  this.metadata = metadata;
59
58
  this.useContext = useContext;
60
59
  this.eventManager = eventManager;
61
- this.entityLoader = new entity_1.EntityLoader(this);
60
+ this.entityLoader = new EntityLoader(this);
62
61
  this.name = this.config.get('contextName');
63
- this.validator = new entity_1.EntityValidator(this.config.get('strict'));
64
62
  this.comparator = this.config.getComparator(this.metadata);
65
63
  this.resultCache = this.config.getResultCacheAdapter();
66
64
  this.disableTransactions = this.config.get('disableTransactions');
67
- this.entityFactory = new entity_1.EntityFactory(this);
68
- this.unitOfWork = new unit_of_work_1.UnitOfWork(this);
65
+ this.entityFactory = new EntityFactory(this);
66
+ this.unitOfWork = new UnitOfWork(this);
69
67
  }
70
68
  /**
71
69
  * Gets the Driver instance used by this EntityManager.
@@ -90,7 +88,7 @@ class EntityManager {
90
88
  * Gets repository for given entity. You can pass either string name or entity class reference.
91
89
  */
92
90
  getRepository(entityName) {
93
- entityName = Utils_1.Utils.className(entityName);
91
+ entityName = Utils.className(entityName);
94
92
  if (!this.repositoryMap[entityName]) {
95
93
  const meta = this.metadata.get(entityName);
96
94
  const RepositoryClass = this.config.getRepositoryClass(meta.repository);
@@ -104,12 +102,6 @@ class EntityManager {
104
102
  repo(entityName) {
105
103
  return this.getRepository(entityName);
106
104
  }
107
- /**
108
- * Gets EntityValidator instance
109
- */
110
- getValidator() {
111
- return this.validator;
112
- }
113
105
  /**
114
106
  * Finds all entities matching your `where` query. You can pass additional options via the `options` parameter.
115
107
  */
@@ -124,9 +116,9 @@ class EntityManager {
124
116
  const em = this.getContext();
125
117
  em.prepareOptions(options);
126
118
  await em.tryFlush(entityName, options);
127
- entityName = Utils_1.Utils.className(entityName);
119
+ entityName = Utils.className(entityName);
128
120
  where = await em.processWhere(entityName, where, options, 'read');
129
- em.validator.validateParams(where);
121
+ validateParams(where);
130
122
  options.orderBy = options.orderBy || {};
131
123
  options.populate = await em.preparePopulate(entityName, options);
132
124
  const populate = options.populate;
@@ -136,7 +128,6 @@ class EntityManager {
136
128
  await em.entityLoader.populate(entityName, cached.data, populate, {
137
129
  ...options,
138
130
  ...em.getPopulateWhere(where, options),
139
- convertCustomTypes: false,
140
131
  ignoreLazyScalarProperties: true,
141
132
  lookup: false,
142
133
  });
@@ -147,8 +138,8 @@ class EntityManager {
147
138
  // save the original hint value so we know it was infer/all
148
139
  options._populateWhere = options.populateWhere ?? this.config.get('populateWhere');
149
140
  options.populateWhere = this.createPopulateWhere({ ...where }, options);
150
- options.populateFilter = await this.getJoinedFilters(meta, { ...where }, options);
151
- const results = await em.driver.find(entityName, where, { ctx: em.transactionContext, ...options });
141
+ options.populateFilter = await this.getJoinedFilters(meta, options);
142
+ const results = await em.driver.find(entityName, where, { ctx: em.transactionContext, em, ...options });
152
143
  if (results.length === 0) {
153
144
  await em.storeCache(options.cache, cached, []);
154
145
  return [];
@@ -163,11 +154,10 @@ class EntityManager {
163
154
  });
164
155
  ret.push(entity);
165
156
  }
166
- const unique = Utils_1.Utils.unique(ret);
157
+ const unique = Utils.unique(ret);
167
158
  await em.entityLoader.populate(entityName, unique, populate, {
168
159
  ...options,
169
160
  ...em.getPopulateWhere(where, options),
170
- convertCustomTypes: false,
171
161
  ignoreLazyScalarProperties: true,
172
162
  lookup: false,
173
163
  });
@@ -176,10 +166,65 @@ class EntityManager {
176
166
  await em.storeCache(options.cache, cached, () => ret);
177
167
  }
178
168
  else {
179
- await em.storeCache(options.cache, cached, () => unique.map(e => (0, entity_1.helper)(e).toPOJO()));
169
+ await em.storeCache(options.cache, cached, () => unique.map(e => helper(e).toPOJO()));
180
170
  }
181
171
  return unique;
182
172
  }
173
+ /**
174
+ * Finds all entities and returns an async iterable (async generator) that yields results one by one.
175
+ * The results are merged and mapped to entity instances, without adding them to the identity map.
176
+ * You can disable merging by passing the options `{ mergeResults: false }`.
177
+ * With `mergeResults` disabled, to-many collections will contain at most one item, and you will get duplicate
178
+ * root entities when there are multiple items in the populated collection.
179
+ * This is useful for processing large datasets without loading everything into memory at once.
180
+ *
181
+ * ```ts
182
+ * const stream = em.stream(Book, { populate: ['author'] });
183
+ *
184
+ * for await (const book of stream) {
185
+ * // book is an instance of Book entity
186
+ * console.log(book.title, book.author.name);
187
+ * }
188
+ * ```
189
+ */
190
+ async *stream(entityName, options = {}) {
191
+ const em = this.getContext();
192
+ em.prepareOptions(options);
193
+ options.strategy = 'joined';
194
+ await em.tryFlush(entityName, options);
195
+ entityName = Utils.className(entityName);
196
+ const where = await em.processWhere(entityName, options.where ?? {}, options, 'read');
197
+ validateParams(where);
198
+ options.orderBy = options.orderBy || {};
199
+ options.populate = await em.preparePopulate(entityName, options);
200
+ const meta = this.metadata.get(entityName);
201
+ options = { ...options };
202
+ // save the original hint value so we know it was infer/all
203
+ options._populateWhere = options.populateWhere ?? this.config.get('populateWhere');
204
+ options.populateWhere = this.createPopulateWhere({ ...where }, options);
205
+ options.populateFilter = await this.getJoinedFilters(meta, options);
206
+ const stream = em.driver.stream(entityName, where, {
207
+ ctx: em.transactionContext,
208
+ mapResults: false,
209
+ ...options,
210
+ });
211
+ for await (const data of stream) {
212
+ const fork = em.fork();
213
+ const entity = fork.entityFactory.create(entityName, data, {
214
+ refresh: options.refresh,
215
+ schema: options.schema,
216
+ convertCustomTypes: true,
217
+ });
218
+ helper(entity).setSerializationContext({
219
+ populate: options.populate,
220
+ fields: options.fields,
221
+ exclude: options.exclude,
222
+ });
223
+ await fork.unitOfWork.dispatchOnLoadEvent();
224
+ fork.clear();
225
+ yield entity;
226
+ }
227
+ }
183
228
  /**
184
229
  * Finds all entities of given type, optionally matching the `where` condition provided in the `options` parameter.
185
230
  */
@@ -190,11 +235,11 @@ class EntityManager {
190
235
  if (options.populateWhere === undefined) {
191
236
  options.populateWhere = this.config.get('populateWhere');
192
237
  }
193
- if (options.populateWhere === enums_1.PopulateHint.ALL) {
238
+ if (options.populateWhere === PopulateHint.ALL) {
194
239
  return { where: {}, populateWhere: options.populateWhere };
195
240
  }
196
- /* istanbul ignore next */
197
- if (options.populateWhere === enums_1.PopulateHint.INFER) {
241
+ /* v8 ignore next */
242
+ if (options.populateWhere === PopulateHint.INFER) {
198
243
  return { where, populateWhere: options.populateWhere };
199
244
  }
200
245
  return { where: options.populateWhere };
@@ -202,12 +247,12 @@ class EntityManager {
202
247
  /**
203
248
  * Registers global filter to this entity manager. Global filters are enabled by default (unless disabled via last parameter).
204
249
  */
205
- addFilter(name, cond, entityName, enabled = true) {
206
- const options = { name, cond, default: enabled };
207
- if (entityName) {
208
- options.entity = Utils_1.Utils.asArray(entityName).map(n => Utils_1.Utils.className(n));
250
+ addFilter(options) {
251
+ if (options.entity) {
252
+ options.entity = Utils.asArray(options.entity).map(n => Utils.className(n));
209
253
  }
210
- this.getContext(false).filters[name] = options;
254
+ options.default ??= true;
255
+ this.getContext(false).filters[options.name] = options;
211
256
  }
212
257
  /**
213
258
  * Sets filter parameter values globally inside context defined by this entity manager.
@@ -231,8 +276,8 @@ class EntityManager {
231
276
  /**
232
277
  * Gets logger context for this entity manager.
233
278
  */
234
- getLoggerContext() {
235
- const em = this.getContext();
279
+ getLoggerContext(options) {
280
+ const em = options?.disableContextResolution ? this : this.getContext();
236
281
  em.loggerContext ??= {};
237
282
  return em.loggerContext;
238
283
  }
@@ -240,7 +285,7 @@ class EntityManager {
240
285
  this.getContext(false).flushMode = flushMode;
241
286
  }
242
287
  async processWhere(entityName, where, options, type) {
243
- where = QueryHelper_1.QueryHelper.processWhere({
288
+ where = QueryHelper.processWhere({
244
289
  where,
245
290
  entityName,
246
291
  metadata: this.metadata,
@@ -249,7 +294,7 @@ class EntityManager {
249
294
  aliased: type === 'read',
250
295
  });
251
296
  where = (await this.applyFilters(entityName, where, options.filters ?? {}, type, options));
252
- where = await this.applyDiscriminatorCondition(entityName, where);
297
+ where = this.applyDiscriminatorCondition(entityName, where);
253
298
  return where;
254
299
  }
255
300
  // this method only handles the problem for mongo driver, SQL drivers have their implementation inside QueryBuilder
@@ -267,43 +312,54 @@ class EntityManager {
267
312
  return children;
268
313
  };
269
314
  lookUpChildren(children, meta.className);
270
- /* istanbul ignore next */
315
+ /* v8 ignore next */
271
316
  where[meta.root.discriminatorColumn] = children.length > 0 ? { $in: [meta.discriminatorValue, ...children.map(c => c.discriminatorValue)] } : meta.discriminatorValue;
272
317
  return where;
273
318
  }
274
319
  createPopulateWhere(cond, options) {
275
320
  const ret = {};
276
321
  const populateWhere = options.populateWhere ?? this.config.get('populateWhere');
277
- if (populateWhere === enums_1.PopulateHint.INFER) {
278
- Utils_1.Utils.merge(ret, cond);
322
+ if (populateWhere === PopulateHint.INFER) {
323
+ Utils.merge(ret, cond);
279
324
  }
280
325
  else if (typeof populateWhere === 'object') {
281
- Utils_1.Utils.merge(ret, populateWhere);
326
+ Utils.merge(ret, populateWhere);
282
327
  }
283
328
  return ret;
284
329
  }
285
- async getJoinedFilters(meta, cond, options) {
330
+ async getJoinedFilters(meta, options) {
331
+ if (!this.config.get('filtersOnRelations') || !options.populate) {
332
+ return undefined;
333
+ }
286
334
  const ret = {};
287
- if (options.populate) {
288
- for (const hint of options.populate) {
289
- const field = hint.field.split(':')[0];
290
- const prop = meta.properties[field];
291
- const joined = (prop.strategy || options.strategy || hint.strategy || this.config.get('loadStrategy')) === enums_1.LoadStrategy.JOINED && prop.kind !== enums_1.ReferenceKind.SCALAR;
292
- if (!joined && !hint.filter) {
293
- continue;
294
- }
295
- const where = await this.applyFilters(prop.type, {}, options.filters ?? {}, 'read', { ...options, populate: hint.children });
296
- const where2 = await this.getJoinedFilters(prop.targetMeta, {}, { ...options, populate: hint.children, populateWhere: enums_1.PopulateHint.ALL });
297
- if (Utils_1.Utils.hasObjectKeys(where)) {
298
- ret[field] = ret[field] ? { $and: [where, ret[field]] } : where;
335
+ for (const hint of options.populate) {
336
+ const field = hint.field.split(':')[0];
337
+ const prop = meta.properties[field];
338
+ const strategy = getLoadingStrategy(prop.strategy || hint.strategy || options.strategy || this.config.get('loadStrategy'), prop.kind);
339
+ const joined = strategy === LoadStrategy.JOINED && prop.kind !== ReferenceKind.SCALAR;
340
+ if (!joined && !hint.filter) {
341
+ continue;
342
+ }
343
+ const filters = QueryHelper.mergePropertyFilters(prop.filters, options.filters);
344
+ const where = await this.applyFilters(prop.type, {}, filters, 'read', {
345
+ ...options,
346
+ populate: hint.children,
347
+ });
348
+ const where2 = await this.getJoinedFilters(prop.targetMeta, {
349
+ ...options,
350
+ filters,
351
+ populate: hint.children,
352
+ populateWhere: PopulateHint.ALL,
353
+ });
354
+ if (Utils.hasObjectKeys(where)) {
355
+ ret[field] = ret[field] ? { $and: [where, ret[field]] } : where;
356
+ }
357
+ if (where2 && Utils.hasObjectKeys(where2)) {
358
+ if (ret[field]) {
359
+ Utils.merge(ret[field], where2);
299
360
  }
300
- if (Utils_1.Utils.hasObjectKeys(where2)) {
301
- if (ret[field]) {
302
- Utils_1.Utils.merge(ret[field], where2);
303
- }
304
- else {
305
- ret[field] = where2;
306
- }
361
+ else {
362
+ ret[field] = where2;
307
363
  }
308
364
  }
309
365
  }
@@ -312,27 +368,45 @@ class EntityManager {
312
368
  /**
313
369
  * When filters are active on M:1 or 1:1 relations, we need to ref join them eagerly as they might affect the FK value.
314
370
  */
315
- async autoJoinRefsForFilters(meta, options) {
316
- if (!meta || !this.config.get('autoJoinRefsForFilters')) {
371
+ async autoJoinRefsForFilters(meta, options, parent) {
372
+ if (!meta || !this.config.get('autoJoinRefsForFilters') || options.filters === false) {
317
373
  return;
318
374
  }
319
- const props = meta.relations.filter(prop => {
320
- return !prop.object && [enums_1.ReferenceKind.MANY_TO_ONE, enums_1.ReferenceKind.ONE_TO_ONE].includes(prop.kind)
321
- && ((options.fields?.length ?? 0) === 0 || options.fields?.some(f => prop.name === f || prop.name.startsWith(`${String(f)}.`)));
322
- });
323
375
  const ret = options.populate;
324
- for (const prop of props) {
325
- const cond = await this.applyFilters(prop.type, {}, options.filters ?? {}, 'read', options);
326
- if (!Utils_1.Utils.isEmpty(cond)) {
376
+ for (const prop of meta.relations) {
377
+ if (prop.object
378
+ || ![ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind)
379
+ || !((options.fields?.length ?? 0) === 0 || options.fields?.some(f => prop.name === f || prop.name.startsWith(`${String(f)}.`)))
380
+ || (parent?.className === prop.targetMeta.root.className && parent.propName === prop.inversedBy)) {
381
+ continue;
382
+ }
383
+ options = { ...options, filters: QueryHelper.mergePropertyFilters(prop.filters, options.filters) };
384
+ const cond = await this.applyFilters(prop.type, {}, options.filters, 'read', options);
385
+ if (!Utils.isEmpty(cond)) {
327
386
  const populated = options.populate.filter(({ field }) => field.split(':')[0] === prop.name);
328
- if (populated.length > 0) {
329
- populated.forEach(hint => hint.filter = true);
387
+ let found = false;
388
+ for (const hint of populated) {
389
+ if (!hint.all) {
390
+ hint.filter = true;
391
+ }
392
+ const strategy = getLoadingStrategy(prop.strategy || hint.strategy || options.strategy || this.config.get('loadStrategy'), prop.kind);
393
+ if (hint.field === `${prop.name}:ref` || (hint.filter && strategy === LoadStrategy.JOINED)) {
394
+ found = true;
395
+ }
330
396
  }
331
- else {
332
- ret.push({ field: `${prop.name}:ref`, strategy: enums_1.LoadStrategy.JOINED, filter: true });
397
+ if (!found) {
398
+ ret.push({ field: `${prop.name}:ref`, strategy: LoadStrategy.JOINED, filter: true });
333
399
  }
334
400
  }
335
401
  }
402
+ for (const hint of ret) {
403
+ const [field, ref] = hint.field.split(':');
404
+ const prop = meta?.properties[field];
405
+ if (prop && !ref) {
406
+ hint.children ??= [];
407
+ await this.autoJoinRefsForFilters(prop.targetMeta, { ...options, populate: hint.children }, { className: meta.root.className, propName: prop.name });
408
+ }
409
+ }
336
410
  }
337
411
  /**
338
412
  * @internal
@@ -346,7 +420,7 @@ class EntityManager {
346
420
  }
347
421
  const active = new Set();
348
422
  const push = (source) => {
349
- const activeFilters = QueryHelper_1.QueryHelper
423
+ const activeFilters = QueryHelper
350
424
  .getActiveFilters(entityName, options, source)
351
425
  .filter(f => !active.has(f.name));
352
426
  filters.push(...activeFilters);
@@ -362,24 +436,28 @@ class EntityManager {
362
436
  let cond;
363
437
  if (filter.cond instanceof Function) {
364
438
  // @ts-ignore
365
- const args = Utils_1.Utils.isPlainObject(options[filter.name]) ? options[filter.name] : this.getContext().filterParams[filter.name];
439
+ const args = Utils.isPlainObject(options?.[filter.name]) ? options[filter.name] : this.getContext().filterParams[filter.name];
366
440
  if (!args && filter.cond.length > 0 && filter.args !== false) {
367
441
  throw new Error(`No arguments provided for filter '${filter.name}'`);
368
442
  }
369
- cond = await filter.cond(args, type, this, findOptions);
443
+ cond = await filter.cond(args, type, this, findOptions, entityName);
370
444
  }
371
445
  else {
372
446
  cond = filter.cond;
373
447
  }
374
- ret.push(QueryHelper_1.QueryHelper.processWhere({
448
+ cond = QueryHelper.processWhere({
375
449
  where: cond,
376
450
  entityName,
377
451
  metadata: this.metadata,
378
452
  platform: this.driver.getPlatform(),
379
453
  aliased: type === 'read',
380
- }));
454
+ });
455
+ if (filter.strict) {
456
+ Object.defineProperty(cond, '__strict', { value: filter.strict, enumerable: false });
457
+ }
458
+ ret.push(cond);
381
459
  }
382
- const conds = [...ret, where].filter(c => Utils_1.Utils.hasObjectKeys(c));
460
+ const conds = [...ret, where].filter(c => Utils.hasObjectKeys(c));
383
461
  return conds.length > 1 ? { $and: conds } : conds[0];
384
462
  }
385
463
  /**
@@ -390,7 +468,7 @@ class EntityManager {
390
468
  const em = this.getContext(false);
391
469
  await em.tryFlush(entityName, options);
392
470
  options.flushMode = 'commit'; // do not try to auto flush again
393
- return RawQueryFragment_1.RawQueryFragment.run(async () => {
471
+ return RawQueryFragment.run(async () => {
394
472
  return Promise.all([
395
473
  em.find(entityName, where, options),
396
474
  em.count(entityName, where, options),
@@ -432,6 +510,10 @@ class EntityManager {
432
510
  * });
433
511
  * ```
434
512
  *
513
+ * The options also support an `includeCount` (true by default) option. If set to false, the `totalCount` is not
514
+ * returned as part of the cursor. This is useful for performance reason, when you don't care about the total number
515
+ * of pages.
516
+ *
435
517
  * The `Cursor` object provides the following interface:
436
518
  *
437
519
  * ```ts
@@ -441,7 +523,7 @@ class EntityManager {
441
523
  * User { ... },
442
524
  * User { ... },
443
525
  * ],
444
- * totalCount: 50,
526
+ * totalCount: 50, // not included if `includeCount: false`
445
527
  * startCursor: 'WzRd',
446
528
  * endCursor: 'WzZd',
447
529
  * hasPrevPage: true,
@@ -451,13 +533,15 @@ class EntityManager {
451
533
  */
452
534
  async findByCursor(entityName, where, options) {
453
535
  const em = this.getContext(false);
454
- entityName = Utils_1.Utils.className(entityName);
536
+ entityName = Utils.className(entityName);
455
537
  options.overfetch ??= true;
456
- if (Utils_1.Utils.isEmpty(options.orderBy)) {
538
+ if (Utils.isEmpty(options.orderBy)) {
457
539
  throw new Error('Explicit `orderBy` option required');
458
540
  }
459
- const [entities, count] = await em.findAndCount(entityName, where, options);
460
- return new Cursor_1.Cursor(entities, count, options, this.metadata.get(entityName));
541
+ const [entities, count] = options.includeCount !== false
542
+ ? await em.findAndCount(entityName, where, options)
543
+ : [await em.find(entityName, where, options)];
544
+ return new Cursor(entities, count, options, this.metadata.get(entityName));
461
545
  }
462
546
  /**
463
547
  * Refreshes the persistent state of an entity from the database, overriding any local changes that have not yet been
@@ -469,7 +553,7 @@ class EntityManager {
469
553
  if (!ret) {
470
554
  options.failHandler ??= this.config.get('findOneOrFailHandler');
471
555
  const entityName = entity.constructor.name;
472
- const where = (0, entity_1.helper)(entity).getPrimaryKey();
556
+ const where = helper(entity).getPrimaryKey();
473
557
  throw options.failHandler(entityName, where);
474
558
  }
475
559
  return ret;
@@ -482,18 +566,31 @@ class EntityManager {
482
566
  async refresh(entity, options = {}) {
483
567
  const fork = this.fork({ keepTransactionContext: true });
484
568
  const entityName = entity.constructor.name;
569
+ const wrapped = helper(entity);
485
570
  const reloaded = await fork.findOne(entityName, entity, {
486
- schema: (0, entity_1.helper)(entity).__schema,
571
+ schema: wrapped.__schema,
487
572
  ...options,
488
- flushMode: enums_1.FlushMode.COMMIT,
573
+ flushMode: FlushMode.COMMIT,
489
574
  });
490
- if (reloaded) {
491
- this.config.getHydrator(this.metadata).hydrate(entity, (0, entity_1.helper)(entity).__meta, (0, entity_1.helper)(reloaded).toPOJO(), this.getEntityFactory(), 'full');
575
+ const em = this.getContext();
576
+ if (!reloaded) {
577
+ em.unitOfWork.unsetIdentity(entity);
578
+ return null;
492
579
  }
493
- else {
494
- this.getUnitOfWork().unsetIdentity(entity);
580
+ let found = false;
581
+ for (const e of fork.unitOfWork.getIdentityMap()) {
582
+ const ref = em.getReference(e.constructor.name, helper(e).getPrimaryKey());
583
+ const data = helper(e).serialize({ ignoreSerializers: true, includeHidden: true });
584
+ em.config.getHydrator(this.metadata).hydrate(ref, helper(ref).__meta, data, em.entityFactory, 'full', false, true);
585
+ Utils.merge(helper(ref).__originalEntityData, this.comparator.prepareEntity(e));
586
+ found ||= ref === entity;
587
+ }
588
+ if (!found) {
589
+ const data = helper(reloaded).serialize({ ignoreSerializers: true, includeHidden: true });
590
+ em.config.getHydrator(this.metadata).hydrate(entity, wrapped.__meta, data, em.entityFactory, 'full', false, true);
591
+ Utils.merge(wrapped.__originalEntityData, this.comparator.prepareEntity(reloaded));
495
592
  }
496
- return reloaded ? entity : reloaded;
593
+ return entity;
497
594
  }
498
595
  /**
499
596
  * Finds first entity matching your `where` query.
@@ -507,45 +604,47 @@ class EntityManager {
507
604
  return ret;
508
605
  }
509
606
  const em = this.getContext();
510
- entityName = Utils_1.Utils.className(entityName);
607
+ entityName = Utils.className(entityName);
511
608
  em.prepareOptions(options);
512
609
  let entity = em.unitOfWork.tryGetById(entityName, where, options.schema);
513
610
  // query for a not managed entity which is already in the identity map as it
514
611
  // was provided with a PK this entity does not exist in the db, there can't
515
612
  // be any relations to it, so no need to deal with the populate hint
516
- if (entity && !(0, entity_1.helper)(entity).__managed) {
613
+ if (entity && !helper(entity).__managed) {
517
614
  return entity;
518
615
  }
519
616
  await em.tryFlush(entityName, options);
520
617
  const meta = em.metadata.get(entityName);
521
618
  where = await em.processWhere(entityName, where, options, 'read');
522
- em.validator.validateEmptyWhere(where);
619
+ validateEmptyWhere(where);
523
620
  em.checkLockRequirements(options.lockMode, meta);
524
- const isOptimisticLocking = !Utils_1.Utils.isDefined(options.lockMode) || options.lockMode === enums_1.LockMode.OPTIMISTIC;
621
+ const isOptimisticLocking = options.lockMode == null || options.lockMode === LockMode.OPTIMISTIC;
525
622
  if (entity && !em.shouldRefresh(meta, entity, options) && isOptimisticLocking) {
526
623
  return em.lockAndPopulate(meta, entity, where, options);
527
624
  }
528
- em.validator.validateParams(where);
625
+ validateParams(where);
529
626
  options.populate = await em.preparePopulate(entityName, options);
530
627
  const cacheKey = em.cacheKey(entityName, options, 'em.findOne', where);
531
628
  const cached = await em.tryCache(entityName, options.cache, cacheKey, options.refresh, true);
532
- if (cached?.data) {
533
- await em.entityLoader.populate(entityName, [cached.data], options.populate, {
534
- ...options,
535
- ...em.getPopulateWhere(where, options),
536
- convertCustomTypes: false,
537
- ignoreLazyScalarProperties: true,
538
- lookup: false,
539
- });
629
+ if (cached?.data !== undefined) {
630
+ if (cached.data) {
631
+ await em.entityLoader.populate(entityName, [cached.data], options.populate, {
632
+ ...options,
633
+ ...em.getPopulateWhere(where, options),
634
+ ignoreLazyScalarProperties: true,
635
+ lookup: false,
636
+ });
637
+ }
540
638
  return cached.data;
541
639
  }
542
640
  options = { ...options };
543
641
  // save the original hint value so we know it was infer/all
544
642
  options._populateWhere = options.populateWhere ?? this.config.get('populateWhere');
545
643
  options.populateWhere = this.createPopulateWhere({ ...where }, options);
546
- options.populateFilter = await this.getJoinedFilters(meta, { ...where }, options);
644
+ options.populateFilter = await this.getJoinedFilters(meta, options);
547
645
  const data = await em.driver.findOne(entityName, where, {
548
646
  ctx: em.transactionContext,
647
+ em,
549
648
  ...options,
550
649
  });
551
650
  if (!data) {
@@ -560,7 +659,7 @@ class EntityManager {
560
659
  });
561
660
  await em.lockAndPopulate(meta, entity, where, options);
562
661
  await em.unitOfWork.dispatchOnLoadEvent();
563
- await em.storeCache(options.cache, cached, () => (0, entity_1.helper)(entity).toPOJO());
662
+ await em.storeCache(options.cache, cached, () => helper(entity).toPOJO());
564
663
  return entity;
565
664
  }
566
665
  /**
@@ -583,9 +682,9 @@ class EntityManager {
583
682
  if (!entity || isStrictViolation) {
584
683
  const key = options.strict ? 'findExactlyOneOrFailHandler' : 'findOneOrFailHandler';
585
684
  options.failHandler ??= this.config.get(key);
586
- entityName = Utils_1.Utils.className(entityName);
587
- /* istanbul ignore next */
588
- where = Utils_1.Utils.isEntity(where) ? (0, entity_1.helper)(where).getPrimaryKey() : where;
685
+ entityName = Utils.className(entityName);
686
+ /* v8 ignore next */
687
+ where = Utils.isEntity(where) ? helper(where).getPrimaryKey() : where;
589
688
  throw options.failHandler(entityName, where);
590
689
  }
591
690
  return entity;
@@ -630,22 +729,22 @@ class EntityManager {
630
729
  data = entityNameOrEntity;
631
730
  }
632
731
  else {
633
- entityName = Utils_1.Utils.className(entityNameOrEntity);
732
+ entityName = Utils.className(entityNameOrEntity);
634
733
  }
635
734
  const meta = this.metadata.get(entityName);
636
- const convertCustomTypes = !Utils_1.Utils.isEntity(data);
637
- if (Utils_1.Utils.isEntity(data)) {
735
+ const convertCustomTypes = !Utils.isEntity(data);
736
+ if (Utils.isEntity(data)) {
638
737
  entity = data;
639
- if ((0, entity_1.helper)(entity).__managed && (0, entity_1.helper)(entity).__em === em && !this.config.get('upsertManaged')) {
738
+ if (helper(entity).__managed && helper(entity).__em === em && !this.config.get('upsertManaged')) {
640
739
  em.entityFactory.mergeData(meta, entity, data, { initialized: true });
641
740
  return entity;
642
741
  }
643
- where = (0, entity_1.helper)(entity).getPrimaryKey();
742
+ where = helper(entity).getPrimaryKey();
644
743
  data = em.comparator.prepareEntity(entity);
645
744
  }
646
745
  else {
647
- data = Utils_1.Utils.copy(QueryHelper_1.QueryHelper.processParams(data));
648
- where = Utils_1.Utils.extractPK(data, meta);
746
+ data = Utils.copy(QueryHelper.processParams(data));
747
+ where = Utils.extractPK(data, meta);
649
748
  if (where && !this.config.get('upsertManaged')) {
650
749
  const exists = em.unitOfWork.getById(entityName, where, options.schema);
651
750
  if (exists) {
@@ -653,28 +752,11 @@ class EntityManager {
653
752
  }
654
753
  }
655
754
  }
656
- const unique = options.onConflictFields ?? meta.props.filter(p => p.unique).map(p => p.name);
657
- const propIndex = !(0, RawQueryFragment_1.isRaw)(unique) && unique.findIndex(p => data[p] != null);
658
- if (options.onConflictFields || where == null) {
659
- if (propIndex !== false && propIndex >= 0) {
660
- where = { [unique[propIndex]]: data[unique[propIndex]] };
661
- }
662
- else if (meta.uniques.length > 0) {
663
- for (const u of meta.uniques) {
664
- if (Utils_1.Utils.asArray(u.properties).every(p => data[p] != null)) {
665
- where = Utils_1.Utils.asArray(u.properties).reduce((o, key) => {
666
- o[key] = data[key];
667
- return o;
668
- }, {});
669
- break;
670
- }
671
- }
672
- }
673
- }
674
- data = QueryHelper_1.QueryHelper.processObjectParams(data);
675
- em.validator.validateParams(data, 'insert data');
676
- if (em.eventManager.hasListeners(enums_1.EventType.beforeUpsert, meta)) {
677
- await em.eventManager.dispatchEvent(enums_1.EventType.beforeUpsert, { entity: data, em, meta }, meta);
755
+ where = getWhereCondition(meta, options.onConflictFields, data, where).where;
756
+ data = QueryHelper.processObjectParams(data);
757
+ validateParams(data, 'insert data');
758
+ if (em.eventManager.hasListeners(EventType.beforeUpsert, meta)) {
759
+ await em.eventManager.dispatchEvent(EventType.beforeUpsert, { entity: data, em, meta }, meta);
678
760
  }
679
761
  const ret = await em.driver.nativeUpdate(entityName, where, data, {
680
762
  ctx: em.transactionContext,
@@ -688,9 +770,9 @@ class EntityManager {
688
770
  initialized: true,
689
771
  schema: options.schema,
690
772
  });
691
- const uniqueFields = options.onConflictFields ?? (Utils_1.Utils.isPlainObject(where) ? Object.keys(where) : meta.primaryKeys);
692
- const returning = (0, upsert_utils_1.getOnConflictReturningFields)(meta, data, uniqueFields, options);
693
- if (options.onConflictAction === 'ignore' || !(0, entity_1.helper)(entity).hasPrimaryKey() || (returning.length > 0 && !(this.getPlatform().usesReturningStatement() && ret.row))) {
773
+ const uniqueFields = options.onConflictFields ?? (Utils.isPlainObject(where) ? Object.keys(where) : meta.primaryKeys);
774
+ const returning = getOnConflictReturningFields(meta, data, uniqueFields, options);
775
+ if (options.onConflictAction === 'ignore' || !helper(entity).hasPrimaryKey() || (returning.length > 0 && !(this.getPlatform().usesReturningStatement() && ret.row))) {
694
776
  const where = {};
695
777
  if (Array.isArray(uniqueFields)) {
696
778
  for (const prop of uniqueFields) {
@@ -715,14 +797,15 @@ class EntityManager {
715
797
  ctx: em.transactionContext,
716
798
  convertCustomTypes: true,
717
799
  connectionType: 'write',
800
+ schema: options.schema,
718
801
  });
719
- em.getHydrator().hydrate(entity, meta, data2, em.entityFactory, 'full');
802
+ em.getHydrator().hydrate(entity, meta, data2, em.entityFactory, 'full', false, true);
720
803
  }
721
804
  // recompute the data as there might be some values missing (e.g. those with db column defaults)
722
805
  const snapshot = this.comparator.prepareEntity(entity);
723
806
  em.unitOfWork.register(entity, snapshot, { refresh: true });
724
- if (em.eventManager.hasListeners(enums_1.EventType.afterUpsert, meta)) {
725
- await em.eventManager.dispatchEvent(enums_1.EventType.afterUpsert, { entity, em, meta }, meta);
807
+ if (em.eventManager.hasListeners(EventType.afterUpsert, meta)) {
808
+ await em.eventManager.dispatchEvent(EventType.afterUpsert, { entity, em, meta }, meta);
726
809
  }
727
810
  return entity;
728
811
  }
@@ -768,19 +851,19 @@ class EntityManager {
768
851
  data = entityNameOrEntity;
769
852
  }
770
853
  else {
771
- entityName = Utils_1.Utils.className(entityNameOrEntity);
854
+ entityName = Utils.className(entityNameOrEntity);
772
855
  }
773
856
  const batchSize = options.batchSize ?? this.config.get('batchSize');
774
857
  if (data.length > batchSize) {
775
858
  const ret = [];
776
859
  for (let i = 0; i < data.length; i += batchSize) {
777
860
  const chunk = data.slice(i, i + batchSize);
778
- ret.push(...await this.upsertMany(entityName, chunk, options));
861
+ ret.push(...(await this.upsertMany(entityName, chunk, options)));
779
862
  }
780
863
  return ret;
781
864
  }
782
865
  const meta = this.metadata.get(entityName);
783
- const convertCustomTypes = !Utils_1.Utils.isEntity(data[0]);
866
+ const convertCustomTypes = !Utils.isEntity(data[0]);
784
867
  const allData = [];
785
868
  const allWhere = [];
786
869
  const entities = new Map();
@@ -788,20 +871,20 @@ class EntityManager {
788
871
  for (let i = 0; i < data.length; i++) {
789
872
  let row = data[i];
790
873
  let where;
791
- if (Utils_1.Utils.isEntity(row)) {
874
+ if (Utils.isEntity(row)) {
792
875
  const entity = row;
793
- if ((0, entity_1.helper)(entity).__managed && (0, entity_1.helper)(entity).__em === em && !this.config.get('upsertManaged')) {
876
+ if (helper(entity).__managed && helper(entity).__em === em && !this.config.get('upsertManaged')) {
794
877
  em.entityFactory.mergeData(meta, entity, row, { initialized: true });
795
878
  entities.set(entity, row);
796
879
  entitiesByData.set(row, entity);
797
880
  continue;
798
881
  }
799
- where = (0, entity_1.helper)(entity).getPrimaryKey();
882
+ where = helper(entity).getPrimaryKey();
800
883
  row = em.comparator.prepareEntity(entity);
801
884
  }
802
885
  else {
803
- row = data[i] = Utils_1.Utils.copy(QueryHelper_1.QueryHelper.processParams(row));
804
- where = Utils_1.Utils.extractPK(row, meta);
886
+ row = data[i] = Utils.copy(QueryHelper.processParams(row));
887
+ where = Utils.extractPK(row, meta);
805
888
  if (where && !this.config.get('upsertManaged')) {
806
889
  const exists = em.unitOfWork.getById(entityName, where, options.schema);
807
890
  if (exists) {
@@ -812,42 +895,28 @@ class EntityManager {
812
895
  }
813
896
  }
814
897
  }
815
- const unique = meta.props.filter(p => p.unique).map(p => p.name);
816
- propIndex = unique.findIndex(p => row[p] != null);
817
- if (options.onConflictFields || where == null) {
818
- if (propIndex >= 0) {
819
- where = { [unique[propIndex]]: row[unique[propIndex]] };
820
- }
821
- else if (meta.uniques.length > 0) {
822
- for (const u of meta.uniques) {
823
- if (Utils_1.Utils.asArray(u.properties).every(p => row[p] != null)) {
824
- where = Utils_1.Utils.asArray(u.properties).reduce((o, key) => {
825
- o[key] = row[key];
826
- return o;
827
- }, {});
828
- break;
829
- }
830
- }
831
- }
832
- }
833
- row = QueryHelper_1.QueryHelper.processObjectParams(row);
834
- where = QueryHelper_1.QueryHelper.processWhere({
835
- where,
898
+ const unique = options.onConflictFields ?? meta.props.filter(p => p.unique).map(p => p.name);
899
+ propIndex = !isRaw(unique) && unique.findIndex(p => data[p] ?? data[p.substring(0, p.indexOf('.'))] != null);
900
+ const tmp = getWhereCondition(meta, options.onConflictFields, row, where);
901
+ propIndex = tmp.propIndex;
902
+ where = QueryHelper.processWhere({
903
+ where: tmp.where,
836
904
  entityName,
837
905
  metadata: this.metadata,
838
906
  platform: this.getPlatform(),
839
907
  });
840
- em.validator.validateParams(row, 'insert data');
908
+ row = QueryHelper.processObjectParams(row);
909
+ validateParams(row, 'insert data');
841
910
  allData.push(row);
842
911
  allWhere.push(where);
843
912
  }
844
913
  if (entities.size === data.length) {
845
914
  return [...entities.keys()];
846
915
  }
847
- if (em.eventManager.hasListeners(enums_1.EventType.beforeUpsert, meta)) {
916
+ if (em.eventManager.hasListeners(EventType.beforeUpsert, meta)) {
848
917
  for (const dto of data) {
849
918
  const entity = entitiesByData.get(dto) ?? dto;
850
- await em.eventManager.dispatchEvent(enums_1.EventType.beforeUpsert, { entity, em, meta }, meta);
919
+ await em.eventManager.dispatchEvent(EventType.beforeUpsert, { entity, em, meta }, meta);
851
920
  }
852
921
  }
853
922
  const res = await em.driver.nativeUpdateMany(entityName, allWhere, allData, {
@@ -860,27 +929,27 @@ class EntityManager {
860
929
  entitiesByData.clear();
861
930
  const loadPK = new Map();
862
931
  allData.forEach((row, i) => {
863
- em.unitOfWork.getChangeSetPersister().mapReturnedValues(Utils_1.Utils.isEntity(data[i]) ? data[i] : null, Utils_1.Utils.isEntity(data[i]) ? {} : data[i], res.rows?.[i], meta, true);
864
- const entity = Utils_1.Utils.isEntity(data[i]) ? data[i] : em.entityFactory.create(entityName, row, {
932
+ em.unitOfWork.getChangeSetPersister().mapReturnedValues(Utils.isEntity(data[i]) ? data[i] : null, Utils.isEntity(data[i]) ? {} : data[i], res.rows?.[i], meta, true);
933
+ const entity = Utils.isEntity(data[i]) ? data[i] : em.entityFactory.create(entityName, row, {
865
934
  refresh: true,
866
935
  initialized: true,
867
936
  schema: options.schema,
868
937
  });
869
- if (!(0, entity_1.helper)(entity).hasPrimaryKey()) {
938
+ if (!helper(entity).hasPrimaryKey()) {
870
939
  loadPK.set(entity, allWhere[i]);
871
940
  }
872
941
  entities.set(entity, row);
873
942
  entitiesByData.set(row, entity);
874
943
  });
875
944
  // skip if we got the PKs via returning statement (`rows`)
876
- const uniqueFields = options.onConflictFields ?? (Utils_1.Utils.isPlainObject(allWhere[0]) ? Object.keys(allWhere[0]).flatMap(key => Utils_1.Utils.splitPrimaryKeys(key)) : meta.primaryKeys);
877
- const returning = (0, upsert_utils_1.getOnConflictReturningFields)(meta, data[0], uniqueFields, options);
945
+ const uniqueFields = options.onConflictFields ?? (Utils.isPlainObject(allWhere[0]) ? Object.keys(allWhere[0]).flatMap(key => Utils.splitPrimaryKeys(key)) : meta.primaryKeys);
946
+ const returning = getOnConflictReturningFields(meta, data[0], uniqueFields, options);
878
947
  const reloadFields = returning.length > 0 && !(this.getPlatform().usesReturningStatement() && res.rows?.length);
879
948
  if (options.onConflictAction === 'ignore' || (!res.rows?.length && loadPK.size > 0) || reloadFields) {
880
949
  const unique = meta.hydrateProps.filter(p => !p.lazy).map(p => p.name);
881
- const add = new Set(propIndex >= 0 ? [unique[propIndex]] : []);
950
+ const add = new Set(propIndex !== false && propIndex >= 0 ? [unique[propIndex]] : []);
882
951
  for (const cond of loadPK.values()) {
883
- Utils_1.Utils.keys(cond).forEach(key => add.add(key));
952
+ Utils.keys(cond).forEach(key => add.add(key));
884
953
  }
885
954
  const where = { $or: [] };
886
955
  data.forEach((item, idx) => {
@@ -895,6 +964,7 @@ class EntityManager {
895
964
  ctx: em.transactionContext,
896
965
  convertCustomTypes: true,
897
966
  connectionType: 'write',
967
+ schema: options.schema,
898
968
  });
899
969
  for (const [entity, cond] of loadPK.entries()) {
900
970
  const row = data2.find(row => {
@@ -906,11 +976,11 @@ class EntityManager {
906
976
  });
907
977
  return this.comparator.matching(entityName, cond, tmp);
908
978
  });
909
- /* istanbul ignore next */
979
+ /* v8 ignore next */
910
980
  if (!row) {
911
981
  throw new Error(`Cannot find matching entity for condition ${JSON.stringify(cond)}`);
912
982
  }
913
- em.getHydrator().hydrate(entity, meta, row, em.entityFactory, 'full');
983
+ em.getHydrator().hydrate(entity, meta, row, em.entityFactory, 'full', false, true);
914
984
  }
915
985
  if (loadPK.size !== data2.length && Array.isArray(uniqueFields)) {
916
986
  for (let i = 0; i < allData.length; i++) {
@@ -929,7 +999,7 @@ class EntityManager {
929
999
  }, {});
930
1000
  return this.comparator.matching(entityName, cond, pk);
931
1001
  });
932
- /* istanbul ignore next */
1002
+ /* v8 ignore next */
933
1003
  if (!row) {
934
1004
  throw new Error(`Cannot find matching entity for condition ${JSON.stringify(cond)}`);
935
1005
  }
@@ -942,54 +1012,46 @@ class EntityManager {
942
1012
  const snapshot = this.comparator.prepareEntity(entity);
943
1013
  em.unitOfWork.register(entity, snapshot, { refresh: true });
944
1014
  }
945
- if (em.eventManager.hasListeners(enums_1.EventType.afterUpsert, meta)) {
1015
+ if (em.eventManager.hasListeners(EventType.afterUpsert, meta)) {
946
1016
  for (const [entity] of entities) {
947
- await em.eventManager.dispatchEvent(enums_1.EventType.afterUpsert, { entity, em, meta }, meta);
1017
+ await em.eventManager.dispatchEvent(EventType.afterUpsert, { entity, em, meta }, meta);
948
1018
  }
949
1019
  }
950
1020
  return [...entities.keys()];
951
1021
  }
952
1022
  /**
953
1023
  * Runs your callback wrapped inside a database transaction.
1024
+ *
1025
+ * If a transaction is already active, a new savepoint (nested transaction) will be created by default. This behavior
1026
+ * can be controlled via the `propagation` option. Use the provided EntityManager instance for all operations that
1027
+ * should be part of the transaction. You can safely use a global EntityManager instance from a DI container, as this
1028
+ * method automatically creates an async context for the transaction.
1029
+ *
1030
+ * **Concurrency note:** When running multiple transactions concurrently (e.g. in parallel requests or jobs), use the
1031
+ * `clear: true` option. This ensures the callback runs in a clear fork of the EntityManager, providing full isolation
1032
+ * between concurrent transactional handlers. Using `clear: true` is an alternative to forking explicitly and calling
1033
+ * the method on the new fork – it already provides the necessary isolation for safe concurrent usage.
1034
+ *
1035
+ * **Propagation note:** Changes made within a transaction (whether top-level or nested) are always propagated to the
1036
+ * parent context, unless the parent context is a global one. If you want to avoid that, fork the EntityManager first
1037
+ * and then call this method on the fork.
1038
+ *
1039
+ * **Example:**
1040
+ * ```ts
1041
+ * await em.transactional(async (em) => {
1042
+ * const author = new Author('Jon');
1043
+ * em.persist(author);
1044
+ * // flush is called automatically at the end of the callback
1045
+ * });
1046
+ * ```
954
1047
  */
955
1048
  async transactional(cb, options = {}) {
956
1049
  const em = this.getContext(false);
957
1050
  if (this.disableTransactions || em.disableTransactions) {
958
1051
  return cb(em);
959
1052
  }
960
- const fork = em.fork({
961
- clear: options.clear ?? false, // state will be merged once resolves
962
- flushMode: options.flushMode,
963
- cloneEventManager: true,
964
- disableTransactions: options.ignoreNestedTransactions,
965
- loggerContext: options.loggerContext,
966
- });
967
- options.ctx ??= em.transactionContext;
968
- const propagateToUpperContext = !em.global || this.config.get('allowGlobalContext');
969
- return TransactionContext_1.TransactionContext.create(fork, async () => {
970
- return fork.getConnection().transactional(async (trx) => {
971
- fork.transactionContext = trx;
972
- if (propagateToUpperContext) {
973
- fork.eventManager.registerSubscriber({
974
- afterFlush(args) {
975
- args.uow.getChangeSets()
976
- .filter(cs => [unit_of_work_1.ChangeSetType.DELETE, unit_of_work_1.ChangeSetType.DELETE_EARLY].includes(cs.type))
977
- .forEach(cs => em.unitOfWork.unsetIdentity(cs.entity));
978
- },
979
- });
980
- }
981
- const ret = await cb(fork);
982
- await fork.flush();
983
- if (propagateToUpperContext) {
984
- // ensure all entities from inner context are merged to the upper one
985
- for (const entity of fork.unitOfWork.getIdentityMap()) {
986
- em.unitOfWork.register(entity);
987
- entity.__helper.__em = em;
988
- }
989
- }
990
- return ret;
991
- }, { ...options, eventBroadcaster: new events_1.TransactionEventBroadcaster(fork, { topLevelTransaction: !options.ctx }) });
992
- });
1053
+ const manager = new TransactionManager(this);
1054
+ return manager.handle(cb, options);
993
1055
  }
994
1056
  /**
995
1057
  * Starts new transaction bound to this EntityManager. Use `ctx` parameter to provide the parent when nesting transactions.
@@ -1001,7 +1063,7 @@ class EntityManager {
1001
1063
  const em = this.getContext(false);
1002
1064
  em.transactionContext = await em.getConnection('write').begin({
1003
1065
  ...options,
1004
- eventBroadcaster: new events_1.TransactionEventBroadcaster(em, { topLevelTransaction: !options.ctx }),
1066
+ eventBroadcaster: new TransactionEventBroadcaster(em, { topLevelTransaction: !options.ctx }),
1005
1067
  });
1006
1068
  }
1007
1069
  /**
@@ -1014,10 +1076,10 @@ class EntityManager {
1014
1076
  return;
1015
1077
  }
1016
1078
  if (!em.transactionContext) {
1017
- throw errors_1.ValidationError.transactionRequired();
1079
+ throw ValidationError.transactionRequired();
1018
1080
  }
1019
1081
  await em.flush();
1020
- await em.getConnection('write').commit(em.transactionContext, new events_1.TransactionEventBroadcaster(em));
1082
+ await em.getConnection('write').commit(em.transactionContext, new TransactionEventBroadcaster(em));
1021
1083
  delete em.transactionContext;
1022
1084
  }
1023
1085
  /**
@@ -1029,9 +1091,9 @@ class EntityManager {
1029
1091
  }
1030
1092
  const em = this.getContext(false);
1031
1093
  if (!em.transactionContext) {
1032
- throw errors_1.ValidationError.transactionRequired();
1094
+ throw ValidationError.transactionRequired();
1033
1095
  }
1034
- await em.getConnection('write').rollback(em.transactionContext, new events_1.TransactionEventBroadcaster(em));
1096
+ await em.getConnection('write').rollback(em.transactionContext, new TransactionEventBroadcaster(em));
1035
1097
  delete em.transactionContext;
1036
1098
  em.unitOfWork.clearActionsQueue();
1037
1099
  }
@@ -1039,7 +1101,7 @@ class EntityManager {
1039
1101
  * Runs your callback wrapped inside a database transaction.
1040
1102
  */
1041
1103
  async lock(entity, lockMode, options = {}) {
1042
- options = Utils_1.Utils.isPlainObject(options) ? options : { lockVersion: options };
1104
+ options = Utils.isPlainObject(options) ? options : { lockVersion: options };
1043
1105
  await this.getUnitOfWork().lock(entity, { lockMode, ...options });
1044
1106
  }
1045
1107
  /**
@@ -1054,26 +1116,26 @@ class EntityManager {
1054
1116
  data = entityNameOrEntity;
1055
1117
  }
1056
1118
  else {
1057
- entityName = Utils_1.Utils.className(entityNameOrEntity);
1119
+ entityName = Utils.className(entityNameOrEntity);
1058
1120
  }
1059
- if (Utils_1.Utils.isEntity(data)) {
1060
- if (options.schema && (0, entity_1.helper)(data).getSchema() == null) {
1061
- (0, entity_1.helper)(data).setSchema(options.schema);
1121
+ if (Utils.isEntity(data)) {
1122
+ if (options.schema && helper(data).getSchema() == null) {
1123
+ helper(data).setSchema(options.schema);
1062
1124
  }
1063
- if (!(0, entity_1.helper)(data).__managed) {
1125
+ if (!helper(data).__managed) {
1064
1126
  // the entity might have been created via `em.create()`, which adds it to the persist stack automatically
1065
1127
  em.unitOfWork.getPersistStack().delete(data);
1066
1128
  // it can be also in the identity map if it had a PK value already
1067
1129
  em.unitOfWork.unsetIdentity(data);
1068
1130
  }
1069
- const meta = (0, entity_1.helper)(data).__meta;
1131
+ const meta = helper(data).__meta;
1070
1132
  const payload = em.comparator.prepareEntity(data);
1071
- const cs = new unit_of_work_1.ChangeSet(data, unit_of_work_1.ChangeSetType.CREATE, payload, meta);
1133
+ const cs = new ChangeSet(data, ChangeSetType.CREATE, payload, meta);
1072
1134
  await em.unitOfWork.getChangeSetPersister().executeInserts([cs], { ctx: em.transactionContext, ...options });
1073
1135
  return cs.getPrimaryKey();
1074
1136
  }
1075
- data = QueryHelper_1.QueryHelper.processObjectParams(data);
1076
- em.validator.validateParams(data, 'insert data');
1137
+ data = QueryHelper.processObjectParams(data);
1138
+ validateParams(data, 'insert data');
1077
1139
  const res = await em.driver.nativeInsert(entityName, data, { ctx: em.transactionContext, ...options });
1078
1140
  return res.insertId;
1079
1141
  }
@@ -1089,31 +1151,31 @@ class EntityManager {
1089
1151
  data = entityNameOrEntities;
1090
1152
  }
1091
1153
  else {
1092
- entityName = Utils_1.Utils.className(entityNameOrEntities);
1154
+ entityName = Utils.className(entityNameOrEntities);
1093
1155
  }
1094
1156
  if (data.length === 0) {
1095
1157
  return [];
1096
1158
  }
1097
- if (Utils_1.Utils.isEntity(data[0])) {
1098
- const meta = (0, entity_1.helper)(data[0]).__meta;
1159
+ if (Utils.isEntity(data[0])) {
1160
+ const meta = helper(data[0]).__meta;
1099
1161
  const css = data.map(row => {
1100
- if (options.schema && (0, entity_1.helper)(row).getSchema() == null) {
1101
- (0, entity_1.helper)(row).setSchema(options.schema);
1162
+ if (options.schema && helper(row).getSchema() == null) {
1163
+ helper(row).setSchema(options.schema);
1102
1164
  }
1103
- if (!(0, entity_1.helper)(row).__managed) {
1165
+ if (!helper(row).__managed) {
1104
1166
  // the entity might have been created via `em.create()`, which adds it to the persist stack automatically
1105
1167
  em.unitOfWork.getPersistStack().delete(row);
1106
1168
  // it can be also in the identity map if it had a PK value already
1107
1169
  em.unitOfWork.unsetIdentity(row);
1108
1170
  }
1109
1171
  const payload = em.comparator.prepareEntity(row);
1110
- return new unit_of_work_1.ChangeSet(row, unit_of_work_1.ChangeSetType.CREATE, payload, meta);
1172
+ return new ChangeSet(row, ChangeSetType.CREATE, payload, meta);
1111
1173
  });
1112
1174
  await em.unitOfWork.getChangeSetPersister().executeInserts(css, { ctx: em.transactionContext, ...options });
1113
1175
  return css.map(cs => cs.getPrimaryKey());
1114
1176
  }
1115
- data = data.map(row => QueryHelper_1.QueryHelper.processObjectParams(row));
1116
- data.forEach(row => em.validator.validateParams(row, 'insert data'));
1177
+ data = data.map(row => QueryHelper.processObjectParams(row));
1178
+ data.forEach(row => validateParams(row, 'insert data'));
1117
1179
  const res = await em.driver.nativeInsertMany(entityName, data, { ctx: em.transactionContext, ...options });
1118
1180
  if (res.insertedIds) {
1119
1181
  return res.insertedIds;
@@ -1126,11 +1188,11 @@ class EntityManager {
1126
1188
  async nativeUpdate(entityName, where, data, options = {}) {
1127
1189
  const em = this.getContext(false);
1128
1190
  em.prepareOptions(options);
1129
- entityName = Utils_1.Utils.className(entityName);
1130
- data = QueryHelper_1.QueryHelper.processObjectParams(data);
1191
+ entityName = Utils.className(entityName);
1192
+ data = QueryHelper.processObjectParams(data);
1131
1193
  where = await em.processWhere(entityName, where, { ...options, convertCustomTypes: false }, 'update');
1132
- em.validator.validateParams(data, 'update data');
1133
- em.validator.validateParams(where, 'update condition');
1194
+ validateParams(data, 'update data');
1195
+ validateParams(where, 'update condition');
1134
1196
  const res = await em.driver.nativeUpdate(entityName, where, data, { ctx: em.transactionContext, ...options });
1135
1197
  return res.affectedRows;
1136
1198
  }
@@ -1140,9 +1202,9 @@ class EntityManager {
1140
1202
  async nativeDelete(entityName, where, options = {}) {
1141
1203
  const em = this.getContext(false);
1142
1204
  em.prepareOptions(options);
1143
- entityName = Utils_1.Utils.className(entityName);
1205
+ entityName = Utils.className(entityName);
1144
1206
  where = await em.processWhere(entityName, where, options, 'delete');
1145
- em.validator.validateParams(where, 'delete condition');
1207
+ validateParams(where, 'delete condition');
1146
1208
  const res = await em.driver.nativeDelete(entityName, where, { ctx: em.transactionContext, ...options });
1147
1209
  return res.affectedRows;
1148
1210
  }
@@ -1150,18 +1212,20 @@ class EntityManager {
1150
1212
  * Maps raw database result to an entity and merges it to this EntityManager.
1151
1213
  */
1152
1214
  map(entityName, result, options = {}) {
1153
- entityName = Utils_1.Utils.className(entityName);
1215
+ entityName = Utils.className(entityName);
1154
1216
  const meta = this.metadata.get(entityName);
1155
1217
  const data = this.driver.mapResult(result, meta);
1156
- Object.keys(data).forEach(k => {
1218
+ for (const k of Object.keys(data)) {
1157
1219
  const prop = meta.properties[k];
1158
- if (prop && prop.kind === enums_1.ReferenceKind.SCALAR && enums_1.SCALAR_TYPES.includes(prop.runtimeType) && !prop.customType && (prop.setter || !prop.getter)) {
1159
- data[k] = this.validator.validateProperty(prop, data[k], data);
1220
+ if (prop?.kind === ReferenceKind.SCALAR && SCALAR_TYPES.has(prop.runtimeType) && !prop.customType && (prop.setter || !prop.getter)) {
1221
+ validateProperty(prop, data[k], data);
1160
1222
  }
1161
- });
1223
+ }
1162
1224
  return this.merge(entityName, data, {
1163
1225
  convertCustomTypes: true,
1164
- refresh: true, ...options,
1226
+ refresh: true,
1227
+ validate: false,
1228
+ ...options,
1165
1229
  });
1166
1230
  }
1167
1231
  /**
@@ -1169,22 +1233,23 @@ class EntityManager {
1169
1233
  * via second parameter. By default, it will return already loaded entities without modifying them.
1170
1234
  */
1171
1235
  merge(entityName, data, options = {}) {
1172
- const em = this.getContext();
1173
- if (Utils_1.Utils.isEntity(entityName)) {
1174
- return em.merge(entityName.constructor.name, entityName, data);
1236
+ if (Utils.isEntity(entityName)) {
1237
+ return this.merge(entityName.constructor.name, entityName, data);
1175
1238
  }
1239
+ const em = options.disableContextResolution ? this : this.getContext();
1176
1240
  options.schema ??= em._schema;
1177
- entityName = Utils_1.Utils.className(entityName);
1178
- em.validator.validatePrimaryKey(data, em.metadata.get(entityName));
1241
+ options.validate ??= true;
1242
+ options.cascade ??= true;
1243
+ entityName = Utils.className(entityName);
1244
+ validatePrimaryKey(data, em.metadata.get(entityName));
1179
1245
  let entity = em.unitOfWork.tryGetById(entityName, data, options.schema, false);
1180
- if (entity && (0, entity_1.helper)(entity).__managed && (0, entity_1.helper)(entity).__initialized && !options.refresh) {
1246
+ if (entity && helper(entity).__managed && helper(entity).__initialized && !options.refresh) {
1181
1247
  return entity;
1182
1248
  }
1183
- const meta = em.metadata.find(entityName);
1184
- const childMeta = em.metadata.getByDiscriminatorColumn(meta, data);
1185
- entity = Utils_1.Utils.isEntity(data) ? data : em.entityFactory.create(entityName, data, { merge: true, ...options });
1186
- em.validator.validate(entity, data, childMeta ?? meta);
1187
- em.unitOfWork.merge(entity);
1249
+ const dataIsEntity = Utils.isEntity(data);
1250
+ entity = dataIsEntity ? data : em.entityFactory.create(entityName, data, { merge: true, ...options });
1251
+ const visited = options.cascade ? undefined : new Set([entity]);
1252
+ em.unitOfWork.merge(entity, visited);
1188
1253
  return entity;
1189
1254
  }
1190
1255
  /**
@@ -1209,6 +1274,7 @@ class EntityManager {
1209
1274
  ...options,
1210
1275
  newEntity: !options.managed,
1211
1276
  merge: options.managed,
1277
+ normalizeAccessors: true,
1212
1278
  });
1213
1279
  options.persist ??= em.config.get('persistOnCreate');
1214
1280
  if (options.persist && !this.getMetadata(entityName).embeddable) {
@@ -1220,7 +1286,7 @@ class EntityManager {
1220
1286
  * Shortcut for `wrap(entity).assign(data, { em })`
1221
1287
  */
1222
1288
  assign(entity, data, options = {}) {
1223
- return entity_1.EntityAssigner.assign(entity, data, { em: this.getContext(), ...options });
1289
+ return EntityAssigner.assign(entity, data, { em: this.getContext(), ...options });
1224
1290
  }
1225
1291
  /**
1226
1292
  * Gets a reference to the entity identified by the given type and identifier without actually loading it, if the entity is not yet loaded
@@ -1228,16 +1294,16 @@ class EntityManager {
1228
1294
  getReference(entityName, id, options = {}) {
1229
1295
  options.schema ??= this.schema;
1230
1296
  options.convertCustomTypes ??= false;
1231
- const meta = this.metadata.get(Utils_1.Utils.className(entityName));
1232
- if (Utils_1.Utils.isPrimaryKey(id)) {
1297
+ const meta = this.metadata.get(Utils.className(entityName));
1298
+ if (Utils.isPrimaryKey(id)) {
1233
1299
  if (meta.compositePK) {
1234
- throw errors_1.ValidationError.invalidCompositeIdentifier(meta);
1300
+ throw ValidationError.invalidCompositeIdentifier(meta);
1235
1301
  }
1236
1302
  id = [id];
1237
1303
  }
1238
1304
  const entity = this.getEntityFactory().createReference(entityName, id, { merge: true, ...options });
1239
1305
  if (options.wrapped) {
1240
- return entity_1.Reference.create(entity);
1306
+ return Reference.create(entity);
1241
1307
  }
1242
1308
  return entity;
1243
1309
  }
@@ -1247,11 +1313,9 @@ class EntityManager {
1247
1313
  async count(entityName, where = {}, options = {}) {
1248
1314
  const em = this.getContext(false);
1249
1315
  // Shallow copy options since the object will be modified when deleting orderBy
1250
- options = {
1251
- schema: em._schema,
1252
- ...options,
1253
- };
1254
- entityName = Utils_1.Utils.className(entityName);
1316
+ options = { ...options };
1317
+ em.prepareOptions(options);
1318
+ entityName = Utils.className(entityName);
1255
1319
  await em.tryFlush(entityName, options);
1256
1320
  where = await em.processWhere(entityName, where, options, 'read');
1257
1321
  options.populate = await em.preparePopulate(entityName, options);
@@ -1260,15 +1324,15 @@ class EntityManager {
1260
1324
  const meta = em.metadata.find(entityName);
1261
1325
  options._populateWhere = options.populateWhere ?? this.config.get('populateWhere');
1262
1326
  options.populateWhere = this.createPopulateWhere({ ...where }, options);
1263
- options.populateFilter = await this.getJoinedFilters(meta, { ...where }, options);
1264
- em.validator.validateParams(where);
1327
+ options.populateFilter = await this.getJoinedFilters(meta, options);
1328
+ validateParams(where);
1265
1329
  delete options.orderBy;
1266
1330
  const cacheKey = em.cacheKey(entityName, options, 'em.count', where);
1267
1331
  const cached = await em.tryCache(entityName, options.cache, cacheKey);
1268
- if (cached?.data) {
1332
+ if (cached?.data !== undefined) {
1269
1333
  return cached.data;
1270
1334
  }
1271
- const count = await em.driver.count(entityName, where, { ctx: em.transactionContext, ...options });
1335
+ const count = await em.driver.count(entityName, where, { ctx: em.transactionContext, em, ...options });
1272
1336
  await em.storeCache(options.cache, cached, () => +count);
1273
1337
  return +count;
1274
1338
  }
@@ -1278,30 +1342,23 @@ class EntityManager {
1278
1342
  */
1279
1343
  persist(entity) {
1280
1344
  const em = this.getContext();
1281
- if (Utils_1.Utils.isEntity(entity)) {
1345
+ if (Utils.isEntity(entity)) {
1282
1346
  // do not cascade just yet, cascading of entities in persist stack is done when flushing
1283
1347
  em.unitOfWork.persist(entity, undefined, { cascade: false });
1284
1348
  return em;
1285
1349
  }
1286
- const entities = Utils_1.Utils.asArray(entity);
1350
+ const entities = Utils.asArray(entity);
1287
1351
  for (const ent of entities) {
1288
- if (!Utils_1.Utils.isEntity(ent, true)) {
1289
- /* istanbul ignore next */
1352
+ if (!Utils.isEntity(ent, true)) {
1353
+ /* v8 ignore next */
1290
1354
  const meta = typeof ent === 'object' ? em.metadata.find(ent.constructor.name) : undefined;
1291
- throw errors_1.ValidationError.notDiscoveredEntity(ent, meta);
1355
+ throw ValidationError.notDiscoveredEntity(ent, meta);
1292
1356
  }
1293
1357
  // do not cascade just yet, cascading of entities in persist stack is done when flushing
1294
- em.unitOfWork.persist(entity_1.Reference.unwrapReference(ent), undefined, { cascade: false });
1358
+ em.unitOfWork.persist(Reference.unwrapReference(ent), undefined, { cascade: false });
1295
1359
  }
1296
1360
  return this;
1297
1361
  }
1298
- /**
1299
- * Persists your entity immediately, flushing all not yet persisted changes to the database too.
1300
- * Equivalent to `em.persist(e).flush()`.
1301
- */
1302
- async persistAndFlush(entity) {
1303
- await this.persist(entity).flush();
1304
- }
1305
1362
  /**
1306
1363
  * Marks entity for removal.
1307
1364
  * A removed entity will be removed from the database at or before transaction commit or as a result of the flush operation.
@@ -1310,28 +1367,21 @@ class EntityManager {
1310
1367
  */
1311
1368
  remove(entity) {
1312
1369
  const em = this.getContext();
1313
- if (Utils_1.Utils.isEntity(entity)) {
1370
+ if (Utils.isEntity(entity)) {
1314
1371
  // do not cascade just yet, cascading of entities in persist stack is done when flushing
1315
1372
  em.unitOfWork.remove(entity, undefined, { cascade: false });
1316
1373
  return em;
1317
1374
  }
1318
- const entities = Utils_1.Utils.asArray(entity, true);
1375
+ const entities = Utils.asArray(entity, true);
1319
1376
  for (const ent of entities) {
1320
- if (!Utils_1.Utils.isEntity(ent, true)) {
1377
+ if (!Utils.isEntity(ent, true)) {
1321
1378
  throw new Error(`You need to pass entity instance or reference to 'em.remove()'. To remove entities by condition, use 'em.nativeDelete()'.`);
1322
1379
  }
1323
1380
  // do not cascade just yet, cascading of entities in remove stack is done when flushing
1324
- em.unitOfWork.remove(entity_1.Reference.unwrapReference(ent), undefined, { cascade: false });
1381
+ em.unitOfWork.remove(Reference.unwrapReference(ent), undefined, { cascade: false });
1325
1382
  }
1326
1383
  return em;
1327
1384
  }
1328
- /**
1329
- * Removes an entity instance immediately, flushing all not yet persisted changes to the database too.
1330
- * Equivalent to `em.remove(e).flush()`
1331
- */
1332
- async removeAndFlush(entity) {
1333
- await this.remove(entity).flush();
1334
- }
1335
1385
  /**
1336
1386
  * Flushes all changes to objects that have been queued up to now to the database.
1337
1387
  * This effectively synchronizes the in-memory state of managed objects with the database.
@@ -1345,12 +1395,12 @@ class EntityManager {
1345
1395
  async tryFlush(entityName, options) {
1346
1396
  const em = this.getContext();
1347
1397
  const flushMode = options.flushMode ?? em.flushMode ?? em.config.get('flushMode');
1348
- entityName = Utils_1.Utils.className(entityName);
1398
+ entityName = Utils.className(entityName);
1349
1399
  const meta = em.metadata.get(entityName);
1350
- if (flushMode === enums_1.FlushMode.COMMIT) {
1400
+ if (flushMode === FlushMode.COMMIT) {
1351
1401
  return;
1352
1402
  }
1353
- if (flushMode === enums_1.FlushMode.ALWAYS || em.getUnitOfWork().shouldAutoFlush(meta)) {
1403
+ if (flushMode === FlushMode.ALWAYS || em.getUnitOfWork().shouldAutoFlush(meta)) {
1354
1404
  await em.flush();
1355
1405
  }
1356
1406
  }
@@ -1364,7 +1414,7 @@ class EntityManager {
1364
1414
  * Checks whether given property can be populated on the entity.
1365
1415
  */
1366
1416
  canPopulate(entityName, property) {
1367
- entityName = Utils_1.Utils.className(entityName);
1417
+ entityName = Utils.className(entityName);
1368
1418
  // eslint-disable-next-line prefer-const
1369
1419
  let [p, ...parts] = property.split('.');
1370
1420
  const meta = this.metadata.find(entityName);
@@ -1387,14 +1437,14 @@ class EntityManager {
1387
1437
  * Loads specified relations in batch. This will execute one query for each relation, that will populate it on all the specified entities.
1388
1438
  */
1389
1439
  async populate(entities, populate, options = {}) {
1390
- const arr = Utils_1.Utils.asArray(entities);
1440
+ const arr = Utils.asArray(entities);
1391
1441
  if (arr.length === 0) {
1392
1442
  return entities;
1393
1443
  }
1394
1444
  const em = this.getContext();
1395
1445
  em.prepareOptions(options);
1396
1446
  const entityName = arr[0].constructor.name;
1397
- const preparedPopulate = await em.preparePopulate(entityName, { populate: populate }, options.validate);
1447
+ const preparedPopulate = await em.preparePopulate(entityName, { populate: populate, filters: options.filters }, options.validate);
1398
1448
  await em.entityLoader.populate(entityName, arr, preparedPopulate, options);
1399
1449
  return entities;
1400
1450
  }
@@ -1408,7 +1458,7 @@ class EntityManager {
1408
1458
  options.freshEventManager ??= false;
1409
1459
  options.cloneEventManager ??= false;
1410
1460
  const eventManager = options.freshEventManager
1411
- ? new events_1.EventManager(em.config.get('subscribers'))
1461
+ ? new EventManager(em.config.get('subscribers'))
1412
1462
  : options.cloneEventManager
1413
1463
  ? em.eventManager.clone()
1414
1464
  : em.eventManager;
@@ -1423,13 +1473,16 @@ class EntityManager {
1423
1473
  fork.transactionContext = em.transactionContext;
1424
1474
  }
1425
1475
  fork.filters = { ...em.filters };
1426
- fork.filterParams = Utils_1.Utils.copy(em.filterParams);
1427
- fork.loggerContext = Utils_1.Utils.merge({}, em.loggerContext, options.loggerContext);
1476
+ fork.filterParams = Utils.copy(em.filterParams);
1477
+ fork.loggerContext = Utils.merge({}, em.loggerContext, options.loggerContext);
1428
1478
  fork._schema = options.schema ?? em._schema;
1429
1479
  if (!options.clear) {
1430
1480
  for (const entity of em.unitOfWork.getIdentityMap()) {
1431
1481
  fork.unitOfWork.register(entity);
1432
1482
  }
1483
+ for (const entity of em.unitOfWork.getPersistStack()) {
1484
+ fork.unitOfWork.persist(entity);
1485
+ }
1433
1486
  for (const entity of em.unitOfWork.getOrphanRemoveStack()) {
1434
1487
  fork.unitOfWork.getOrphanRemoveStack().add(entity);
1435
1488
  }
@@ -1451,6 +1504,12 @@ class EntityManager {
1451
1504
  getEntityFactory() {
1452
1505
  return this.getContext().entityFactory;
1453
1506
  }
1507
+ /**
1508
+ * @internal use `em.populate()` as the user facing API, this is exposed only for internal usage
1509
+ */
1510
+ getEntityLoader() {
1511
+ return this.getContext().entityLoader;
1512
+ }
1454
1513
  /**
1455
1514
  * Gets the Hydrator used by the EntityManager.
1456
1515
  */
@@ -1465,14 +1524,14 @@ class EntityManager {
1465
1524
  if (!this.useContext) {
1466
1525
  return this;
1467
1526
  }
1468
- let em = TransactionContext_1.TransactionContext.getEntityManager(this.name); // prefer the tx context
1527
+ let em = TransactionContext.getEntityManager(this.name); // prefer the tx context
1469
1528
  if (em) {
1470
1529
  return em;
1471
1530
  }
1472
1531
  // no explicit tx started
1473
1532
  em = this.config.get('context')(this.name) ?? this;
1474
1533
  if (validate && !this.config.get('allowGlobalContext') && em.global) {
1475
- throw errors_1.ValidationError.cannotUseGlobalContext();
1534
+ throw ValidationError.cannotUseGlobalContext();
1476
1535
  }
1477
1536
  return em;
1478
1537
  }
@@ -1513,7 +1572,7 @@ class EntityManager {
1513
1572
  */
1514
1573
  getMetadata(entityName) {
1515
1574
  if (entityName) {
1516
- entityName = Utils_1.Utils.className(entityName);
1575
+ entityName = Utils.className(entityName);
1517
1576
  return this.metadata.get(entityName);
1518
1577
  }
1519
1578
  return this.metadata;
@@ -1528,15 +1587,15 @@ class EntityManager {
1528
1587
  if (!mode) {
1529
1588
  return;
1530
1589
  }
1531
- if (mode === enums_1.LockMode.OPTIMISTIC && !meta.versionProperty) {
1532
- throw errors_1.OptimisticLockError.notVersioned(meta);
1590
+ if (mode === LockMode.OPTIMISTIC && !meta.versionProperty) {
1591
+ throw OptimisticLockError.notVersioned(meta);
1533
1592
  }
1534
- if ([enums_1.LockMode.PESSIMISTIC_READ, enums_1.LockMode.PESSIMISTIC_WRITE].includes(mode) && !this.isInTransaction()) {
1535
- throw errors_1.ValidationError.transactionRequired();
1593
+ if ([LockMode.PESSIMISTIC_READ, LockMode.PESSIMISTIC_WRITE].includes(mode) && !this.isInTransaction()) {
1594
+ throw ValidationError.transactionRequired();
1536
1595
  }
1537
1596
  }
1538
1597
  async lockAndPopulate(meta, entity, where, options) {
1539
- if (!meta.virtual && options.lockMode === enums_1.LockMode.OPTIMISTIC) {
1598
+ if (!meta.virtual && options.lockMode === LockMode.OPTIMISTIC) {
1540
1599
  await this.lock(entity, options.lockMode, {
1541
1600
  lockVersion: options.lockVersion,
1542
1601
  lockTableAliases: options.lockTableAliases,
@@ -1547,7 +1606,6 @@ class EntityManager {
1547
1606
  ...options,
1548
1607
  ...this.getPopulateWhere(where, options),
1549
1608
  orderBy: options.populateOrderBy ?? options.orderBy,
1550
- convertCustomTypes: false,
1551
1609
  ignoreLazyScalarProperties: true,
1552
1610
  lookup: false,
1553
1611
  });
@@ -1555,8 +1613,8 @@ class EntityManager {
1555
1613
  }
1556
1614
  buildFields(fields) {
1557
1615
  return fields.reduce((ret, f) => {
1558
- if (Utils_1.Utils.isPlainObject(f)) {
1559
- Utils_1.Utils.keys(f).forEach(ff => ret.push(...this.buildFields(f[ff]).map(field => `${ff}.${field}`)));
1616
+ if (Utils.isPlainObject(f)) {
1617
+ Utils.keys(f).forEach(ff => ret.push(...this.buildFields(f[ff]).map(field => `${ff}.${field}`)));
1560
1618
  }
1561
1619
  else {
1562
1620
  ret.push(f);
@@ -1575,12 +1633,12 @@ class EntityManager {
1575
1633
  const pruneToOneRelations = (meta, fields) => {
1576
1634
  const ret = [];
1577
1635
  for (let field of fields) {
1578
- if (field === enums_1.PopulatePath.ALL || field.startsWith(`${enums_1.PopulatePath.ALL}.`)) {
1579
- ret.push(...meta.props.filter(prop => prop.lazy || [enums_1.ReferenceKind.SCALAR, enums_1.ReferenceKind.EMBEDDED].includes(prop.kind)).map(prop => prop.name));
1636
+ if (field === PopulatePath.ALL || field.startsWith(`${PopulatePath.ALL}.`)) {
1637
+ ret.push(...meta.props.filter(prop => prop.lazy || [ReferenceKind.SCALAR, ReferenceKind.EMBEDDED].includes(prop.kind)).map(prop => prop.name));
1580
1638
  continue;
1581
1639
  }
1582
1640
  field = field.split(':')[0];
1583
- if (!field.includes('.') && ![enums_1.ReferenceKind.MANY_TO_ONE, enums_1.ReferenceKind.ONE_TO_ONE].includes(meta.properties[field].kind)) {
1641
+ if (!field.includes('.') && ![ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(meta.properties[field].kind)) {
1584
1642
  ret.push(field);
1585
1643
  continue;
1586
1644
  }
@@ -1599,7 +1657,7 @@ class EntityManager {
1599
1657
  ret.push(...inner.map(c => `${key}.${c}`));
1600
1658
  }
1601
1659
  }
1602
- return Utils_1.Utils.unique(ret);
1660
+ return Utils.unique(ret);
1603
1661
  };
1604
1662
  options.populate = pruneToOneRelations(meta, this.buildFields(options.fields));
1605
1663
  }
@@ -1609,18 +1667,18 @@ class EntityManager {
1609
1667
  return populate;
1610
1668
  }
1611
1669
  if (typeof options.populate !== 'boolean') {
1612
- options.populate = Utils_1.Utils.asArray(options.populate).map(field => {
1613
- /* istanbul ignore next */
1614
- if (typeof field === 'boolean' || field === enums_1.PopulatePath.ALL) {
1670
+ options.populate = Utils.asArray(options.populate).map(field => {
1671
+ /* v8 ignore next */
1672
+ if (typeof field === 'boolean' || field === PopulatePath.ALL) {
1615
1673
  return [{ field: meta.primaryKeys[0], strategy: options.strategy, all: !!field }]; //
1616
1674
  }
1617
1675
  // will be handled in QueryBuilder when processing the where condition via CriteriaNode
1618
- if (field === enums_1.PopulatePath.INFER) {
1676
+ if (field === PopulatePath.INFER) {
1619
1677
  options.flags ??= [];
1620
- options.flags.push(enums_1.QueryFlag.INFER_POPULATE);
1678
+ options.flags.push(QueryFlag.INFER_POPULATE);
1621
1679
  return [];
1622
1680
  }
1623
- if (Utils_1.Utils.isString(field)) {
1681
+ if (typeof field === 'string') {
1624
1682
  return [{ field, strategy: options.strategy }];
1625
1683
  }
1626
1684
  return [field];
@@ -1629,13 +1687,13 @@ class EntityManager {
1629
1687
  const populate = this.entityLoader.normalizePopulate(entityName, options.populate, options.strategy);
1630
1688
  const invalid = populate.find(({ field }) => !this.canPopulate(entityName, field));
1631
1689
  if (validate && invalid) {
1632
- throw errors_1.ValidationError.invalidPropertyName(entityName, invalid.field);
1690
+ throw ValidationError.invalidPropertyName(entityName, invalid.field);
1633
1691
  }
1634
1692
  await this.autoJoinRefsForFilters(meta, { ...options, populate });
1635
1693
  return populate.map(field => {
1636
1694
  // force select-in strategy when populating all relations as otherwise we could cause infinite loops when self-referencing
1637
1695
  const all = field.all ?? (Array.isArray(options.populate) && options.populate.includes('*'));
1638
- field.strategy = all ? enums_1.LoadStrategy.SELECT_IN : (options.strategy ?? field.strategy);
1696
+ field.strategy = all ? LoadStrategy.SELECT_IN : (options.strategy ?? field.strategy);
1639
1697
  return field;
1640
1698
  });
1641
1699
  }
@@ -1644,33 +1702,33 @@ class EntityManager {
1644
1702
  * some additional lazy properties, if so, we reload and merge the data from database
1645
1703
  */
1646
1704
  shouldRefresh(meta, entity, options) {
1647
- if (!(0, entity_1.helper)(entity).__initialized || options.refresh) {
1705
+ if (!helper(entity).__initialized || options.refresh) {
1648
1706
  return true;
1649
1707
  }
1650
1708
  let autoRefresh;
1651
1709
  if (options.fields) {
1652
- autoRefresh = options.fields.some(field => !(0, entity_1.helper)(entity).__loadedProperties.has(field));
1710
+ autoRefresh = options.fields.some(field => !helper(entity).__loadedProperties.has(field));
1653
1711
  }
1654
1712
  else {
1655
1713
  autoRefresh = meta.comparableProps.some(prop => {
1656
- const inlineEmbedded = prop.kind === enums_1.ReferenceKind.EMBEDDED && !prop.object;
1657
- return !inlineEmbedded && !prop.lazy && !(0, entity_1.helper)(entity).__loadedProperties.has(prop.name);
1714
+ const inlineEmbedded = prop.kind === ReferenceKind.EMBEDDED && !prop.object;
1715
+ return !inlineEmbedded && !prop.lazy && !helper(entity).__loadedProperties.has(prop.name);
1658
1716
  });
1659
1717
  }
1660
1718
  if (autoRefresh) {
1661
1719
  return true;
1662
1720
  }
1663
1721
  if (Array.isArray(options.populate)) {
1664
- return options.populate.some(field => !(0, entity_1.helper)(entity).__loadedProperties.has(field));
1722
+ return options.populate.some(field => !helper(entity).__loadedProperties.has(field));
1665
1723
  }
1666
1724
  return !!options.populate;
1667
1725
  }
1668
1726
  prepareOptions(options) {
1669
- if (!Utils_1.Utils.isEmpty(options.fields) && !Utils_1.Utils.isEmpty(options.exclude)) {
1670
- throw new errors_1.ValidationError(`Cannot combine 'fields' and 'exclude' option.`);
1727
+ if (!Utils.isEmpty(options.fields) && !Utils.isEmpty(options.exclude)) {
1728
+ throw new ValidationError(`Cannot combine 'fields' and 'exclude' option.`);
1671
1729
  }
1672
1730
  options.schema ??= this._schema;
1673
- options.logging = Utils_1.Utils.merge({ id: this.id }, this.loggerContext, options.loggerContext, options.logging);
1731
+ options.logging = options.loggerContext = Utils.merge({ id: this.id }, this.loggerContext, options.loggerContext, options.logging);
1674
1732
  }
1675
1733
  /**
1676
1734
  * @internal
@@ -1694,31 +1752,31 @@ class EntityManager {
1694
1752
  const em = this.getContext();
1695
1753
  const cacheKey = Array.isArray(config) ? config[0] : JSON.stringify(key);
1696
1754
  const cached = await em.resultCache.get(cacheKey);
1697
- if (cached) {
1698
- let data;
1699
- if (Array.isArray(cached) && merge) {
1700
- data = cached.map(item => em.entityFactory.create(entityName, item, {
1701
- merge: true,
1702
- convertCustomTypes: true,
1703
- refresh,
1704
- recomputeSnapshot: true,
1705
- }));
1706
- }
1707
- else if (Utils_1.Utils.isObject(cached) && merge) {
1708
- data = em.entityFactory.create(entityName, cached, {
1709
- merge: true,
1710
- convertCustomTypes: true,
1711
- refresh,
1712
- recomputeSnapshot: true,
1713
- });
1714
- }
1715
- else {
1716
- data = cached;
1717
- }
1718
- await em.unitOfWork.dispatchOnLoadEvent();
1719
- return { key: cacheKey, data };
1755
+ if (!cached) {
1756
+ return { key: cacheKey, data: cached };
1720
1757
  }
1721
- return { key: cacheKey };
1758
+ let data;
1759
+ if (Array.isArray(cached) && merge) {
1760
+ data = cached.map(item => em.entityFactory.create(entityName, item, {
1761
+ merge: true,
1762
+ convertCustomTypes: true,
1763
+ refresh,
1764
+ recomputeSnapshot: true,
1765
+ }));
1766
+ }
1767
+ else if (Utils.isObject(cached) && merge) {
1768
+ data = em.entityFactory.create(entityName, cached, {
1769
+ merge: true,
1770
+ convertCustomTypes: true,
1771
+ refresh,
1772
+ recomputeSnapshot: true,
1773
+ });
1774
+ }
1775
+ else {
1776
+ data = cached;
1777
+ }
1778
+ await em.unitOfWork.dispatchOnLoadEvent();
1779
+ return { key: cacheKey, data };
1722
1780
  }
1723
1781
  /**
1724
1782
  * @internal
@@ -1727,7 +1785,7 @@ class EntityManager {
1727
1785
  config ??= this.config.get('resultCache').global;
1728
1786
  if (config) {
1729
1787
  const em = this.getContext();
1730
- const expiration = Array.isArray(config) ? config[1] : (Utils_1.Utils.isNumber(config) ? config : undefined);
1788
+ const expiration = Array.isArray(config) ? config[1] : (typeof config === 'number' ? config : undefined);
1731
1789
  await em.resultCache.set(key.key, data instanceof Function ? data() : data, '', expiration);
1732
1790
  }
1733
1791
  }
@@ -1760,6 +1818,19 @@ class EntityManager {
1760
1818
  set schema(schema) {
1761
1819
  this.getContext(false)._schema = schema ?? undefined;
1762
1820
  }
1821
+ /** @internal */
1822
+ async getDataLoader(type) {
1823
+ const em = this.getContext();
1824
+ if (em.loaders[type]) {
1825
+ return em.loaders[type];
1826
+ }
1827
+ const DataLoader = await DataloaderUtils.getDataLoader();
1828
+ switch (type) {
1829
+ case 'ref': return (em.loaders[type] ??= new DataLoader(DataloaderUtils.getRefBatchLoadFn(em)));
1830
+ case '1:m': return (em.loaders[type] ??= new DataLoader(DataloaderUtils.getColBatchLoadFn(em)));
1831
+ case 'm:n': return (em.loaders[type] ??= new DataLoader(DataloaderUtils.getManyToManyColBatchLoadFn(em)));
1832
+ }
1833
+ }
1763
1834
  /**
1764
1835
  * Returns the ID of this EntityManager. Respects the context, so global EM will give you the contextual ID
1765
1836
  * if executed inside request context handler.
@@ -1768,8 +1839,7 @@ class EntityManager {
1768
1839
  return this.getContext(false)._id;
1769
1840
  }
1770
1841
  /** @ignore */
1771
- [node_util_1.inspect.custom]() {
1842
+ [Symbol.for('nodejs.util.inspect.custom')]() {
1772
1843
  return `[EntityManager<${this.id}>]`;
1773
1844
  }
1774
1845
  }
1775
- exports.EntityManager = EntityManager;