@mikro-orm/core 7.0.0-dev.15 → 7.0.0-dev.150

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 (209) hide show
  1. package/EntityManager.d.ts +81 -55
  2. package/EntityManager.js +292 -262
  3. package/MikroORM.d.ts +44 -35
  4. package/MikroORM.js +103 -143
  5. package/README.md +3 -2
  6. package/cache/FileCacheAdapter.d.ts +1 -1
  7. package/cache/FileCacheAdapter.js +8 -7
  8. package/cache/GeneratedCacheAdapter.d.ts +0 -1
  9. package/cache/GeneratedCacheAdapter.js +0 -2
  10. package/cache/index.d.ts +0 -1
  11. package/cache/index.js +0 -1
  12. package/connections/Connection.d.ts +16 -7
  13. package/connections/Connection.js +23 -14
  14. package/drivers/DatabaseDriver.d.ts +25 -16
  15. package/drivers/DatabaseDriver.js +80 -35
  16. package/drivers/IDatabaseDriver.d.ts +38 -17
  17. package/entity/BaseEntity.d.ts +2 -2
  18. package/entity/BaseEntity.js +0 -3
  19. package/entity/Collection.d.ts +94 -29
  20. package/entity/Collection.js +434 -97
  21. package/entity/EntityAssigner.d.ts +1 -1
  22. package/entity/EntityAssigner.js +26 -18
  23. package/entity/EntityFactory.d.ts +7 -0
  24. package/entity/EntityFactory.js +72 -53
  25. package/entity/EntityHelper.d.ts +2 -2
  26. package/entity/EntityHelper.js +35 -15
  27. package/entity/EntityLoader.d.ts +5 -5
  28. package/entity/EntityLoader.js +80 -70
  29. package/entity/EntityRepository.d.ts +6 -2
  30. package/entity/EntityRepository.js +8 -2
  31. package/entity/Reference.d.ts +6 -5
  32. package/entity/Reference.js +34 -9
  33. package/entity/WrappedEntity.d.ts +2 -7
  34. package/entity/WrappedEntity.js +3 -8
  35. package/entity/defineEntity.d.ts +575 -0
  36. package/entity/defineEntity.js +529 -0
  37. package/entity/index.d.ts +3 -2
  38. package/entity/index.js +3 -2
  39. package/entity/utils.d.ts +7 -0
  40. package/entity/utils.js +16 -4
  41. package/entity/validators.d.ts +11 -0
  42. package/entity/validators.js +65 -0
  43. package/enums.d.ts +21 -5
  44. package/enums.js +15 -1
  45. package/errors.d.ts +18 -9
  46. package/errors.js +44 -21
  47. package/events/EventManager.d.ts +2 -1
  48. package/events/EventManager.js +19 -11
  49. package/hydration/Hydrator.js +1 -2
  50. package/hydration/ObjectHydrator.d.ts +4 -4
  51. package/hydration/ObjectHydrator.js +50 -33
  52. package/index.d.ts +2 -2
  53. package/index.js +1 -2
  54. package/logging/DefaultLogger.d.ts +1 -1
  55. package/logging/DefaultLogger.js +1 -0
  56. package/logging/SimpleLogger.d.ts +1 -1
  57. package/logging/colors.d.ts +1 -1
  58. package/logging/colors.js +7 -6
  59. package/logging/index.d.ts +1 -0
  60. package/logging/index.js +1 -0
  61. package/logging/inspect.d.ts +2 -0
  62. package/logging/inspect.js +11 -0
  63. package/metadata/EntitySchema.d.ts +18 -22
  64. package/metadata/EntitySchema.js +50 -34
  65. package/metadata/MetadataDiscovery.d.ts +6 -10
  66. package/metadata/MetadataDiscovery.js +315 -304
  67. package/metadata/MetadataProvider.d.ts +11 -2
  68. package/metadata/MetadataProvider.js +46 -2
  69. package/metadata/MetadataStorage.d.ts +13 -11
  70. package/metadata/MetadataStorage.js +70 -37
  71. package/metadata/MetadataValidator.d.ts +11 -9
  72. package/metadata/MetadataValidator.js +50 -38
  73. package/metadata/discover-entities.d.ts +5 -0
  74. package/metadata/discover-entities.js +40 -0
  75. package/metadata/index.d.ts +1 -1
  76. package/metadata/index.js +1 -1
  77. package/metadata/types.d.ts +480 -0
  78. package/metadata/types.js +1 -0
  79. package/naming-strategy/AbstractNamingStrategy.d.ts +8 -4
  80. package/naming-strategy/AbstractNamingStrategy.js +8 -2
  81. package/naming-strategy/EntityCaseNamingStrategy.d.ts +3 -3
  82. package/naming-strategy/EntityCaseNamingStrategy.js +6 -5
  83. package/naming-strategy/MongoNamingStrategy.d.ts +3 -3
  84. package/naming-strategy/MongoNamingStrategy.js +6 -6
  85. package/naming-strategy/NamingStrategy.d.ts +14 -4
  86. package/naming-strategy/UnderscoreNamingStrategy.d.ts +3 -3
  87. package/naming-strategy/UnderscoreNamingStrategy.js +6 -6
  88. package/not-supported.d.ts +2 -0
  89. package/not-supported.js +4 -0
  90. package/package.json +18 -11
  91. package/platforms/ExceptionConverter.js +1 -1
  92. package/platforms/Platform.d.ts +6 -13
  93. package/platforms/Platform.js +17 -43
  94. package/serialization/EntitySerializer.d.ts +5 -0
  95. package/serialization/EntitySerializer.js +47 -27
  96. package/serialization/EntityTransformer.js +28 -18
  97. package/serialization/SerializationContext.d.ts +6 -6
  98. package/serialization/SerializationContext.js +16 -13
  99. package/types/ArrayType.d.ts +1 -1
  100. package/types/ArrayType.js +2 -3
  101. package/types/BigIntType.d.ts +8 -6
  102. package/types/BigIntType.js +1 -1
  103. package/types/BlobType.d.ts +0 -1
  104. package/types/BlobType.js +0 -3
  105. package/types/BooleanType.d.ts +2 -1
  106. package/types/BooleanType.js +3 -0
  107. package/types/DecimalType.d.ts +6 -4
  108. package/types/DecimalType.js +3 -3
  109. package/types/DoubleType.js +2 -2
  110. package/types/EnumArrayType.js +1 -2
  111. package/types/JsonType.d.ts +1 -1
  112. package/types/JsonType.js +7 -2
  113. package/types/TinyIntType.js +1 -1
  114. package/types/Type.d.ts +2 -4
  115. package/types/Type.js +3 -3
  116. package/types/Uint8ArrayType.d.ts +0 -1
  117. package/types/Uint8ArrayType.js +1 -4
  118. package/types/index.d.ts +1 -1
  119. package/typings.d.ts +158 -113
  120. package/typings.js +55 -42
  121. package/unit-of-work/ChangeSet.d.ts +2 -6
  122. package/unit-of-work/ChangeSet.js +4 -5
  123. package/unit-of-work/ChangeSetComputer.d.ts +1 -3
  124. package/unit-of-work/ChangeSetComputer.js +14 -12
  125. package/unit-of-work/ChangeSetPersister.d.ts +5 -4
  126. package/unit-of-work/ChangeSetPersister.js +70 -34
  127. package/unit-of-work/CommitOrderCalculator.d.ts +12 -10
  128. package/unit-of-work/CommitOrderCalculator.js +13 -13
  129. package/unit-of-work/UnitOfWork.d.ts +10 -3
  130. package/unit-of-work/UnitOfWork.js +141 -98
  131. package/utils/AbstractSchemaGenerator.d.ts +5 -5
  132. package/utils/AbstractSchemaGenerator.js +18 -16
  133. package/utils/AsyncContext.d.ts +6 -0
  134. package/utils/AsyncContext.js +42 -0
  135. package/utils/Configuration.d.ts +754 -207
  136. package/utils/Configuration.js +146 -190
  137. package/utils/ConfigurationLoader.d.ts +1 -54
  138. package/utils/ConfigurationLoader.js +1 -352
  139. package/utils/Cursor.d.ts +0 -3
  140. package/utils/Cursor.js +27 -11
  141. package/utils/DataloaderUtils.d.ts +15 -5
  142. package/utils/DataloaderUtils.js +64 -30
  143. package/utils/EntityComparator.d.ts +13 -9
  144. package/utils/EntityComparator.js +84 -42
  145. package/utils/QueryHelper.d.ts +14 -6
  146. package/utils/QueryHelper.js +87 -25
  147. package/utils/RawQueryFragment.d.ts +48 -25
  148. package/utils/RawQueryFragment.js +66 -70
  149. package/utils/RequestContext.js +2 -2
  150. package/utils/TransactionContext.js +2 -2
  151. package/utils/TransactionManager.d.ts +65 -0
  152. package/utils/TransactionManager.js +223 -0
  153. package/utils/Utils.d.ts +13 -120
  154. package/utils/Utils.js +99 -375
  155. package/utils/clone.js +8 -23
  156. package/utils/env-vars.d.ts +7 -0
  157. package/utils/env-vars.js +97 -0
  158. package/utils/fs-utils.d.ts +32 -0
  159. package/utils/fs-utils.js +178 -0
  160. package/utils/index.d.ts +2 -1
  161. package/utils/index.js +2 -1
  162. package/utils/upsert-utils.d.ts +9 -4
  163. package/utils/upsert-utils.js +55 -4
  164. package/decorators/Check.d.ts +0 -3
  165. package/decorators/Check.js +0 -13
  166. package/decorators/CreateRequestContext.d.ts +0 -3
  167. package/decorators/CreateRequestContext.js +0 -32
  168. package/decorators/Embeddable.d.ts +0 -8
  169. package/decorators/Embeddable.js +0 -11
  170. package/decorators/Embedded.d.ts +0 -12
  171. package/decorators/Embedded.js +0 -18
  172. package/decorators/Entity.d.ts +0 -18
  173. package/decorators/Entity.js +0 -12
  174. package/decorators/Enum.d.ts +0 -9
  175. package/decorators/Enum.js +0 -16
  176. package/decorators/Filter.d.ts +0 -2
  177. package/decorators/Filter.js +0 -8
  178. package/decorators/Formula.d.ts +0 -4
  179. package/decorators/Formula.js +0 -15
  180. package/decorators/Indexed.d.ts +0 -19
  181. package/decorators/Indexed.js +0 -20
  182. package/decorators/ManyToMany.d.ts +0 -40
  183. package/decorators/ManyToMany.js +0 -14
  184. package/decorators/ManyToOne.d.ts +0 -32
  185. package/decorators/ManyToOne.js +0 -14
  186. package/decorators/OneToMany.d.ts +0 -28
  187. package/decorators/OneToMany.js +0 -17
  188. package/decorators/OneToOne.d.ts +0 -26
  189. package/decorators/OneToOne.js +0 -7
  190. package/decorators/PrimaryKey.d.ts +0 -8
  191. package/decorators/PrimaryKey.js +0 -20
  192. package/decorators/Property.d.ts +0 -250
  193. package/decorators/Property.js +0 -32
  194. package/decorators/Transactional.d.ts +0 -13
  195. package/decorators/Transactional.js +0 -28
  196. package/decorators/hooks.d.ts +0 -16
  197. package/decorators/hooks.js +0 -47
  198. package/decorators/index.d.ts +0 -17
  199. package/decorators/index.js +0 -17
  200. package/entity/ArrayCollection.d.ts +0 -116
  201. package/entity/ArrayCollection.js +0 -402
  202. package/entity/EntityValidator.d.ts +0 -19
  203. package/entity/EntityValidator.js +0 -150
  204. package/exports.d.ts +0 -24
  205. package/exports.js +0 -23
  206. package/metadata/ReflectMetadataProvider.d.ts +0 -8
  207. package/metadata/ReflectMetadataProvider.js +0 -44
  208. package/utils/resolveContextProvider.d.ts +0 -10
  209. package/utils/resolveContextProvider.js +0 -28
@@ -4,8 +4,8 @@ import { ValidationError } from '../errors.js';
4
4
  import { LoadStrategy, PopulatePath, ReferenceKind, } from '../enums.js';
5
5
  import { Reference } from './Reference.js';
6
6
  import { helper } from './wrap.js';
7
- import { raw, RawQueryFragment } from '../utils/RawQueryFragment.js';
8
7
  import { expandDotPaths } from './utils.js';
8
+ import { Raw } from '../utils/RawQueryFragment.js';
9
9
  export class EntityLoader {
10
10
  em;
11
11
  metadata;
@@ -32,17 +32,16 @@ export class EntityLoader {
32
32
  const visited = options.visited ??= new Set();
33
33
  options.where ??= {};
34
34
  options.orderBy ??= {};
35
- options.filters ??= {};
36
35
  options.lookup ??= true;
37
36
  options.validate ??= true;
38
37
  options.refresh ??= false;
39
38
  options.convertCustomTypes ??= true;
40
39
  if (references.length > 0) {
41
- await this.populateScalar(meta, references, options);
40
+ await this.populateScalar(meta, references, { ...options, populateWhere: undefined });
42
41
  }
43
42
  populate = this.normalizePopulate(entityName, populate, options.strategy, options.lookup);
44
43
  const invalid = populate.find(({ field }) => !this.em.canPopulate(entityName, field));
45
- /* v8 ignore next 3 */
44
+ /* v8 ignore next */
46
45
  if (options.validate && invalid) {
47
46
  throw ValidationError.invalidPropertyName(entityName, invalid.field);
48
47
  }
@@ -140,35 +139,39 @@ export class EntityLoader {
140
139
  const innerOrderBy = Utils.asArray(options.orderBy)
141
140
  .filter(orderBy => (Array.isArray(orderBy[prop.name]) && orderBy[prop.name].length > 0) || Utils.isObject(orderBy[prop.name]))
142
141
  .flatMap(orderBy => orderBy[prop.name]);
142
+ const where = await this.extractChildCondition(options, prop);
143
143
  if (prop.kind === ReferenceKind.MANY_TO_MANY && this.driver.getPlatform().usesPivotTable()) {
144
144
  const res = await this.findChildrenFromPivotTable(filtered, prop, options, innerOrderBy, populate, !!ref);
145
145
  return Utils.flatten(res);
146
146
  }
147
- const where = await this.extractChildCondition(options, prop);
148
- const data = await this.findChildren(entities, prop, populate, { ...options, where, orderBy: innerOrderBy }, !!(ref || prop.mapToPk));
149
- this.initializeCollections(filtered, prop, field, data, innerOrderBy.length > 0);
150
- return data;
147
+ const { items, partial } = await this.findChildren(options.filtered ?? entities, prop, populate, {
148
+ ...options,
149
+ where,
150
+ orderBy: innerOrderBy,
151
+ }, !!(ref || prop.mapToPk));
152
+ this.initializeCollections(filtered, prop, field, items, innerOrderBy.length > 0, partial);
153
+ return items;
151
154
  }
152
155
  async populateScalar(meta, filtered, options) {
153
156
  const pk = Utils.getPrimaryKeyHash(meta.primaryKeys);
154
- const ids = Utils.unique(filtered.map(e => Utils.getPrimaryKeyValues(e, meta.primaryKeys, true)));
157
+ const ids = Utils.unique(filtered.map(e => Utils.getPrimaryKeyValues(e, meta, true)));
155
158
  const where = this.mergePrimaryCondition(ids, pk, options, meta, this.metadata, this.driver.getPlatform());
156
159
  const { filters, convertCustomTypes, lockMode, strategy, populateWhere, connectionType, logging, fields } = options;
157
- await this.em.find(meta.className, where, {
160
+ await this.em.find(meta.class, where, {
158
161
  filters, convertCustomTypes, lockMode, strategy, populateWhere, connectionType, logging,
159
162
  fields: fields,
160
163
  populate: [],
161
164
  });
162
165
  }
163
- initializeCollections(filtered, prop, field, children, customOrder) {
166
+ initializeCollections(filtered, prop, field, children, customOrder, partial) {
164
167
  if (prop.kind === ReferenceKind.ONE_TO_MANY) {
165
- this.initializeOneToMany(filtered, children, prop, field);
168
+ this.initializeOneToMany(filtered, children, prop, field, partial);
166
169
  }
167
170
  if (prop.kind === ReferenceKind.MANY_TO_MANY && !this.driver.getPlatform().usesPivotTable()) {
168
- this.initializeManyToMany(filtered, children, prop, field, customOrder);
171
+ this.initializeManyToMany(filtered, children, prop, field, customOrder, partial);
169
172
  }
170
173
  }
171
- initializeOneToMany(filtered, children, prop, field) {
174
+ initializeOneToMany(filtered, children, prop, field, partial) {
172
175
  const mapToPk = prop.targetMeta.properties[prop.mappedBy].mapToPk;
173
176
  const map = {};
174
177
  for (const entity of filtered) {
@@ -178,20 +181,20 @@ export class EntityLoader {
178
181
  for (const child of children) {
179
182
  const pk = child.__helper.__data[prop.mappedBy] ?? child[prop.mappedBy];
180
183
  if (pk) {
181
- const key = helper(mapToPk ? this.em.getReference(prop.type, pk) : pk).getSerializedPrimaryKey();
184
+ const key = helper(mapToPk ? this.em.getReference(prop.targetMeta.class, pk) : pk).getSerializedPrimaryKey();
182
185
  map[key]?.push(child);
183
186
  }
184
187
  }
185
188
  for (const entity of filtered) {
186
189
  const key = helper(entity).getSerializedPrimaryKey();
187
- entity[field].hydrate(map[key]);
190
+ entity[field].hydrate(map[key], undefined, partial);
188
191
  }
189
192
  }
190
- initializeManyToMany(filtered, children, prop, field, customOrder) {
193
+ initializeManyToMany(filtered, children, prop, field, customOrder, partial) {
191
194
  if (prop.mappedBy) {
192
195
  for (const entity of filtered) {
193
196
  const items = children.filter(child => child[prop.mappedBy].contains(entity, false));
194
- entity[field].hydrate(items, true);
197
+ entity[field].hydrate(items, true, partial);
195
198
  }
196
199
  }
197
200
  else { // owning side of M:N without pivot table needs to be reordered
@@ -201,15 +204,16 @@ export class EntityLoader {
201
204
  if (!customOrder) {
202
205
  items.sort((a, b) => order.indexOf(a) - order.indexOf(b));
203
206
  }
204
- entity[field].hydrate(items, true);
207
+ entity[field].hydrate(items, true, partial);
205
208
  }
206
209
  }
207
210
  }
208
211
  async findChildren(entities, prop, populate, options, ref) {
209
- const children = this.getChildReferences(entities, prop, options, ref);
212
+ const children = Utils.unique(this.getChildReferences(entities, prop, options, ref));
210
213
  const meta = prop.targetMeta;
211
214
  let fk = Utils.getPrimaryKeyHash(meta.primaryKeys);
212
215
  let schema = options.schema;
216
+ const partial = !Utils.isEmpty(prop.where) || !Utils.isEmpty(options.where);
213
217
  if (prop.kind === ReferenceKind.ONE_TO_MANY || (prop.kind === ReferenceKind.MANY_TO_MANY && !prop.owner)) {
214
218
  fk = meta.properties[prop.mappedBy].name;
215
219
  }
@@ -219,7 +223,7 @@ export class EntityLoader {
219
223
  children.push(...this.filterByReferences(entities, prop.name, options.refresh));
220
224
  }
221
225
  if (children.length === 0) {
222
- return [];
226
+ return { items: [], partial };
223
227
  }
224
228
  if (!schema && [ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(prop.kind)) {
225
229
  schema = children.find(e => e.__helper.__schema)?.__helper.__schema;
@@ -228,33 +232,19 @@ export class EntityLoader {
228
232
  let where = this.mergePrimaryCondition(ids, fk, options, meta, this.metadata, this.driver.getPlatform());
229
233
  const fields = this.buildFields(options.fields, prop, ref);
230
234
  /* eslint-disable prefer-const */
231
- let { refresh, filters, convertCustomTypes, lockMode, strategy, populateWhere, connectionType, logging, } = options;
235
+ let { refresh, filters, convertCustomTypes, lockMode, strategy, populateWhere = 'infer', connectionType, logging, } = options;
232
236
  /* eslint-enable prefer-const */
233
237
  if (typeof populateWhere === 'object') {
234
238
  populateWhere = await this.extractChildCondition({ where: populateWhere }, prop);
235
239
  }
236
- if (!Utils.isEmpty(prop.where)) {
240
+ if (!Utils.isEmpty(prop.where) || Raw.hasObjectFragments(prop.where)) {
237
241
  where = { $and: [where, prop.where] };
238
242
  }
239
- const propOrderBy = [];
240
- if (prop.orderBy) {
241
- for (const item of Utils.asArray(prop.orderBy)) {
242
- for (const field of Utils.keys(item)) {
243
- const rawField = RawQueryFragment.getKnownFragment(field, false);
244
- if (rawField) {
245
- const raw2 = raw(rawField.sql, rawField.params);
246
- propOrderBy.push({ [raw2.toString()]: item[field] });
247
- continue;
248
- }
249
- propOrderBy.push({ [field]: item[field] });
250
- }
251
- }
252
- }
253
- const orderBy = [...Utils.asArray(options.orderBy), ...propOrderBy].filter((order, idx, array) => {
243
+ const orderBy = [...Utils.asArray(options.orderBy), ...Utils.asArray(prop.orderBy)].filter((order, idx, array) => {
254
244
  // skip consecutive ordering with the same key to get around mongo issues
255
- return idx === 0 || !Utils.equals(Object.keys(array[idx - 1]), Object.keys(order));
245
+ return idx === 0 || !Utils.equals(Utils.getObjectQueryKeys(array[idx - 1]), Utils.getObjectQueryKeys(order));
256
246
  });
257
- const items = await this.em.find(prop.type, where, {
247
+ const items = await this.em.find(meta.class, where, {
258
248
  filters, convertCustomTypes, lockMode, populateWhere, logging,
259
249
  orderBy,
260
250
  populate: populate.children ?? populate.all ?? [],
@@ -265,6 +255,24 @@ export class EntityLoader {
265
255
  // @ts-ignore not a public option, will be propagated to the populate call
266
256
  visited: options.visited,
267
257
  });
258
+ if ([ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(prop.kind) && items.length !== children.length) {
259
+ const nullVal = this.em.config.get('forceUndefined') ? undefined : null;
260
+ const itemsMap = new Set();
261
+ const childrenMap = new Set();
262
+ for (const item of items) {
263
+ itemsMap.add(helper(item).getSerializedPrimaryKey());
264
+ }
265
+ for (const child of children) {
266
+ childrenMap.add(helper(child).getSerializedPrimaryKey());
267
+ }
268
+ for (const entity of entities) {
269
+ const key = helper(entity[prop.name] ?? {})?.getSerializedPrimaryKey();
270
+ if (childrenMap.has(key) && !itemsMap.has(key)) {
271
+ entity[prop.name] = nullVal;
272
+ helper(entity).__originalEntityData[prop.name] = null;
273
+ }
274
+ }
275
+ }
268
276
  for (const item of items) {
269
277
  if (ref && !helper(item).__onLoadFired) {
270
278
  helper(item).__initialized = false;
@@ -272,10 +280,10 @@ export class EntityLoader {
272
280
  this.em.getUnitOfWork()['loadedEntities'].delete(item);
273
281
  }
274
282
  }
275
- return items;
283
+ return { items, partial };
276
284
  }
277
285
  mergePrimaryCondition(ids, pk, options, meta, metadata, platform) {
278
- const cond1 = QueryHelper.processWhere({ where: { [pk]: { $in: ids } }, entityName: meta.className, metadata, platform, convertCustomTypes: !options.convertCustomTypes });
286
+ const cond1 = QueryHelper.processWhere({ where: { [pk]: { $in: ids } }, entityName: meta.class, metadata, platform, convertCustomTypes: !options.convertCustomTypes });
279
287
  const where = { ...options.where };
280
288
  Utils.dropUndefinedProperties(where);
281
289
  return where[pk]
@@ -288,6 +296,7 @@ export class EntityLoader {
288
296
  if (prop.kind === ReferenceKind.SCALAR && !prop.lazy) {
289
297
  return;
290
298
  }
299
+ options = { ...options, filters: QueryHelper.mergePropertyFilters(prop.filters, options.filters) };
291
300
  const populated = await this.populateMany(entityName, entities, populate, options);
292
301
  if (!populate.children && !populate.all) {
293
302
  return;
@@ -321,11 +330,16 @@ export class EntityLoader {
321
330
  for (const entity of entities) {
322
331
  visited.delete(entity);
323
332
  }
324
- const filtered = Utils.unique(children.filter(e => !visited.has(e)));
333
+ const unique = Utils.unique(children);
334
+ const filtered = unique.filter(e => !visited.has(e));
325
335
  for (const entity of entities) {
326
336
  visited.add(entity);
327
337
  }
328
- await this.populate(prop.type, filtered, populate.children ?? populate.all, {
338
+ // skip lazy scalar properties
339
+ if (!prop.targetMeta) {
340
+ return;
341
+ }
342
+ await this.populate(prop.targetMeta.class, unique, populate.children ?? populate.all, {
329
343
  where: await this.extractChildCondition(options, prop, false),
330
344
  orderBy: innerOrderBy,
331
345
  fields,
@@ -342,6 +356,8 @@ export class EntityLoader {
342
356
  refresh: refresh && !filtered.every(item => options.visited.has(item)),
343
357
  // @ts-ignore not a public option, will be propagated to the populate call
344
358
  visited: options.visited,
359
+ // @ts-ignore not a public option
360
+ filtered,
345
361
  });
346
362
  }
347
363
  /** @internal */
@@ -368,12 +384,12 @@ export class EntityLoader {
368
384
  for (const entity of filtered) {
369
385
  const items = map[entity.__helper.getSerializedPrimaryKey()].map(item => {
370
386
  if (pivotJoin) {
371
- return this.em.getReference(prop.type, item, {
387
+ return this.em.getReference(prop.targetMeta.class, item, {
372
388
  convertCustomTypes: true,
373
389
  schema: options.schema ?? this.em.config.get('schema'),
374
390
  });
375
391
  }
376
- const entity = this.em.getEntityFactory().create(prop.type, item, {
392
+ const entity = this.em.getEntityFactory().create(prop.targetMeta.class, item, {
377
393
  refresh,
378
394
  merge: true,
379
395
  convertCustomTypes: true,
@@ -389,16 +405,13 @@ export class EntityLoader {
389
405
  async extractChildCondition(options, prop, filters = false) {
390
406
  const where = options.where;
391
407
  const subCond = Utils.isPlainObject(where[prop.name]) ? where[prop.name] : {};
392
- const meta2 = this.metadata.find(prop.type);
393
- if (!meta2) {
394
- return {};
395
- }
408
+ const meta2 = prop.targetMeta;
396
409
  const pk = Utils.getPrimaryKeyHash(meta2.primaryKeys);
397
410
  ['$and', '$or'].forEach(op => {
398
411
  if (where[op]) {
399
412
  const child = where[op]
400
413
  .map((cond) => cond[prop.name])
401
- .filter((sub) => sub != null && !(Utils.isPlainObject(sub) && Object.keys(sub).every(key => Utils.isOperator(key, false))))
414
+ .filter((sub) => sub != null && !(Utils.isPlainObject(sub) && Utils.getObjectQueryKeys(sub).every(key => Utils.isOperator(key, false))))
402
415
  .map((cond) => {
403
416
  if (Utils.isPrimaryKey(cond)) {
404
417
  return { [pk]: cond };
@@ -419,7 +432,7 @@ export class EntityLoader {
419
432
  });
420
433
  }
421
434
  if (filters) {
422
- return this.em.applyFilters(prop.type, subCond, options.filters, 'read', options);
435
+ return this.em.applyFilters(meta2.class, subCond, options.filters, 'read', options);
423
436
  }
424
437
  return subCond;
425
438
  }
@@ -437,7 +450,7 @@ export class EntityLoader {
437
450
  const parts = f.toString().split('.');
438
451
  const propName = parts.shift();
439
452
  const childPropName = parts.join('.');
440
- /* v8 ignore next 3 */
453
+ /* v8 ignore next */
441
454
  if (propName === prop.name) {
442
455
  ret.push(childPropName);
443
456
  }
@@ -458,23 +471,20 @@ export class EntityLoader {
458
471
  }
459
472
  getChildReferences(entities, prop, options, ref) {
460
473
  const filtered = this.filterCollections(entities, prop.name, options, ref);
461
- const children = [];
462
474
  if (prop.kind === ReferenceKind.ONE_TO_MANY) {
463
- children.push(...filtered.map(e => e[prop.name].owner));
475
+ return filtered.map(e => e[prop.name].owner);
464
476
  }
465
- else if (prop.kind === ReferenceKind.MANY_TO_MANY && prop.owner) {
466
- children.push(...filtered.reduce((a, b) => {
477
+ if (prop.kind === ReferenceKind.MANY_TO_MANY && prop.owner) {
478
+ return filtered.reduce((a, b) => {
467
479
  a.push(...b[prop.name].getItems());
468
480
  return a;
469
- }, []));
481
+ }, []);
470
482
  }
471
- else if (prop.kind === ReferenceKind.MANY_TO_MANY) { // inverse side
472
- children.push(...filtered);
483
+ if (prop.kind === ReferenceKind.MANY_TO_MANY) { // inverse side
484
+ return filtered;
473
485
  }
474
- else { // MANY_TO_ONE or ONE_TO_ONE
475
- children.push(...this.filterReferences(entities, prop.name, options, ref));
476
- }
477
- return children;
486
+ // MANY_TO_ONE or ONE_TO_ONE
487
+ return this.filterReferences(entities, prop.name, options, ref);
478
488
  }
479
489
  filterCollections(entities, field, options, ref) {
480
490
  if (options.refresh) {
@@ -491,7 +501,7 @@ export class EntityLoader {
491
501
  return wrapped.__loadedProperties.has(field);
492
502
  }
493
503
  const [f, ...r] = field.split('.');
494
- /* v8 ignore next 3 */
504
+ /* v8 ignore next */
495
505
  if (!wrapped.__loadedProperties.has(f) || !wrapped.__meta.properties[f]?.targetMeta) {
496
506
  return false;
497
507
  }
@@ -524,7 +534,7 @@ export class EntityLoader {
524
534
  .map(e => Reference.unwrapReference(e[field]));
525
535
  }
526
536
  filterByReferences(entities, field, refresh) {
527
- /* v8 ignore next 3 */
537
+ /* v8 ignore next */
528
538
  if (refresh) {
529
539
  return entities;
530
540
  }
@@ -555,10 +565,10 @@ export class EntityLoader {
555
565
  if (!meta && !prefix) {
556
566
  return populate;
557
567
  }
558
- if (visited.includes(entityName) || !meta) {
568
+ if (!meta || visited.includes(meta)) {
559
569
  return [];
560
570
  }
561
- visited.push(entityName);
571
+ visited.push(meta);
562
572
  const ret = prefix === '' ? [...populate] : [];
563
573
  meta.relations
564
574
  .filter(prop => {
@@ -571,12 +581,12 @@ export class EntityLoader {
571
581
  const field = this.getRelationName(meta, prop);
572
582
  const prefixed = prefix ? `${prefix}.${field}` : field;
573
583
  const nestedPopulate = populate.filter(p => p.field === prop.name).flatMap(p => p.children).filter(Boolean);
574
- const nested = this.lookupEagerLoadedRelationships(prop.type, nestedPopulate, strategy, prefixed, visited.slice());
584
+ const nested = this.lookupEagerLoadedRelationships(prop.targetMeta.class, nestedPopulate, strategy, prefixed, visited.slice());
575
585
  if (nested.length > 0) {
576
586
  ret.push(...nested);
577
587
  }
578
588
  else {
579
- const selfReferencing = [meta.className, meta.root.className, ...visited].includes(prop.type) && prop.eager;
589
+ const selfReferencing = [meta.tableName, ...visited.map(m => m.tableName)].includes(prop.targetMeta.tableName) && prop.eager;
580
590
  ret.push({
581
591
  field: prefixed,
582
592
  // enforce select-in strategy for self-referencing relations
@@ -2,7 +2,7 @@ import type { PopulatePath } from '../enums.js';
2
2
  import type { CreateOptions, EntityManager, MergeOptions } from '../EntityManager.js';
3
3
  import type { AssignOptions } from './EntityAssigner.js';
4
4
  import type { EntityData, EntityName, Primary, Loaded, FilterQuery, EntityDictionary, AutoPath, RequiredEntityData, Ref, EntityType, EntityDTO, MergeSelected, FromEntityType, IsSubset, MergeLoaded, ArrayElement } from '../typings.js';
5
- import type { CountOptions, DeleteOptions, FindAllOptions, FindByCursorOptions, FindOneOptions, FindOneOrFailOptions, FindOptions, GetReferenceOptions, NativeInsertUpdateOptions, UpdateOptions, UpsertManyOptions, UpsertOptions } from '../drivers/IDatabaseDriver.js';
5
+ import type { CountOptions, DeleteOptions, FindAllOptions, FindByCursorOptions, FindOneOptions, FindOneOrFailOptions, FindOptions, GetReferenceOptions, NativeInsertUpdateOptions, StreamOptions, UpdateOptions, UpsertManyOptions, UpsertOptions } from '../drivers/IDatabaseDriver.js';
6
6
  import type { EntityLoaderOptions } from './EntityLoader.js';
7
7
  import type { Cursor } from '../utils/Cursor.js';
8
8
  export declare class EntityRepository<Entity extends object> {
@@ -80,11 +80,15 @@ export declare class EntityRepository<Entity extends object> {
80
80
  /**
81
81
  * @inheritDoc EntityManager.findByCursor
82
82
  */
83
- findByCursor<Hint extends string = never, Fields extends string = '*', Excludes extends string = never>(where: FilterQuery<Entity>, options: FindByCursorOptions<Entity, Hint, Fields, Excludes>): Promise<Cursor<Entity, Hint, Fields, Excludes>>;
83
+ findByCursor<Hint extends string = never, Fields extends string = '*', Excludes extends string = never, IncludeCount extends boolean = true>(options: FindByCursorOptions<Entity, Hint, Fields, Excludes, IncludeCount>): Promise<Cursor<Entity, Hint, Fields, Excludes, IncludeCount>>;
84
84
  /**
85
85
  * Finds all entities of given type. You can pass additional options via the `options` parameter.
86
86
  */
87
87
  findAll<Hint extends string = never, Fields extends string = '*', Excludes extends string = never>(options?: FindAllOptions<Entity, Hint, Fields, Excludes>): Promise<Loaded<Entity, Hint, Fields, Excludes>[]>;
88
+ /**
89
+ * @inheritDoc EntityManager.stream
90
+ */
91
+ stream<Hint extends string = never, Fields extends string = '*', Excludes extends string = never>(options?: StreamOptions<Entity, Hint, Fields, Excludes>): AsyncIterableIterator<Loaded<Entity, Hint, Fields, Excludes>>;
88
92
  /**
89
93
  * @inheritDoc EntityManager.insert
90
94
  */
@@ -90,8 +90,8 @@ export class EntityRepository {
90
90
  /**
91
91
  * @inheritDoc EntityManager.findByCursor
92
92
  */
93
- async findByCursor(where, options) {
94
- return this.getEntityManager().findByCursor(this.entityName, where, options);
93
+ async findByCursor(options) {
94
+ return this.getEntityManager().findByCursor(this.entityName, options);
95
95
  }
96
96
  /**
97
97
  * Finds all entities of given type. You can pass additional options via the `options` parameter.
@@ -99,6 +99,12 @@ export class EntityRepository {
99
99
  async findAll(options) {
100
100
  return this.getEntityManager().findAll(this.entityName, options);
101
101
  }
102
+ /**
103
+ * @inheritDoc EntityManager.stream
104
+ */
105
+ async *stream(options) {
106
+ yield* this.getEntityManager().stream(this.entityName, options);
107
+ }
102
108
  /**
103
109
  * @inheritDoc EntityManager.insert
104
110
  */
@@ -1,8 +1,8 @@
1
- import { inspect } from 'node:util';
2
1
  import type { AddEager, AddOptional, Dictionary, EntityClass, EntityKey, EntityProperty, Loaded, LoadedReference, Primary, Ref } from '../typings.js';
3
2
  import type { FindOneOptions, FindOneOrFailOptions } from '../drivers/IDatabaseDriver.js';
4
3
  export declare class Reference<T extends object> {
5
4
  private entity;
5
+ private property?;
6
6
  constructor(entity: T);
7
7
  static create<T extends object>(entity: T | Ref<T>): Ref<T>;
8
8
  static createFromPK<T extends object>(entityType: EntityClass<T>, pk: Primary<T>, options?: {
@@ -42,8 +42,6 @@ export declare class Reference<T extends object> {
42
42
  isInitialized(): boolean;
43
43
  populated(populated?: boolean): void;
44
44
  toJSON(...args: any[]): Dictionary;
45
- /** @ignore */
46
- [inspect.custom](depth?: number): string;
47
45
  }
48
46
  export declare class ScalarReference<Value> {
49
47
  private value?;
@@ -56,12 +54,15 @@ export declare class ScalarReference<Value> {
56
54
  * Returns either the whole entity, or the requested property.
57
55
  */
58
56
  load(options?: Omit<LoadReferenceOptions<any, any>, 'populate' | 'fields' | 'exclude'>): Promise<Value | undefined>;
57
+ /**
58
+ * Ensures the underlying entity is loaded first (without reloading it if it already is loaded).
59
+ * Returns the entity or throws an error just like `em.findOneOrFail()` (and respects the same config options).
60
+ */
61
+ loadOrFail(options?: Omit<LoadReferenceOrFailOptions<any, any>, 'populate' | 'fields' | 'exclude'>): Promise<Value>;
59
62
  set(value: Value): void;
60
63
  bind<Entity extends object>(entity: Entity, property: EntityKey<Entity>): void;
61
64
  unwrap(): Value | undefined;
62
65
  isInitialized(): boolean;
63
- /** @ignore */
64
- [inspect.custom](): string;
65
66
  }
66
67
  export interface LoadReferenceOptions<T extends object, P extends string = never, F extends string = '*', E extends string = never> extends FindOneOptions<T, P, F, E> {
67
68
  dataloader?: boolean;
@@ -1,9 +1,12 @@
1
- import { inspect } from 'node:util';
2
1
  import { DataloaderType } from '../enums.js';
3
2
  import { helper, wrap } from './wrap.js';
4
3
  import { Utils } from '../utils/Utils.js';
4
+ import { QueryHelper } from '../utils/QueryHelper.js';
5
+ import { NotFoundError } from '../errors.js';
6
+ import { inspect } from '../logging/inspect.js';
5
7
  export class Reference {
6
8
  entity;
9
+ property;
7
10
  constructor(entity) {
8
11
  this.entity = entity;
9
12
  this.set(entity);
@@ -33,10 +36,15 @@ export class Reference {
33
36
  }
34
37
  static createFromPK(entityType, pk, options) {
35
38
  const ref = this.createNakedFromPK(entityType, pk, options);
36
- return helper(ref).toReference();
39
+ return helper(ref)?.toReference() ?? ref;
37
40
  }
38
41
  static createNakedFromPK(entityType, pk, options) {
39
42
  const factory = entityType.prototype.__factory;
43
+ if (!factory) {
44
+ // this can happen only if `ref()` is used as a property initializer, and the value is important only for the
45
+ // inference of defaults, so it's fine to return it directly without wrapping with `Reference` class
46
+ return pk;
47
+ }
40
48
  const entity = factory.createReference(entityType, pk, {
41
49
  merge: false,
42
50
  convertCustomTypes: false,
@@ -58,7 +66,9 @@ export class Reference {
58
66
  */
59
67
  static wrapReference(entity, prop) {
60
68
  if (entity && prop.ref && !Reference.isReference(entity)) {
61
- return Reference.create(entity);
69
+ const ref = Reference.create(entity);
70
+ ref.property = prop;
71
+ return ref;
62
72
  }
63
73
  return entity;
64
74
  }
@@ -78,13 +88,14 @@ export class Reference {
78
88
  if (!wrapped.__em) {
79
89
  return this.entity;
80
90
  }
91
+ options = { ...options, filters: QueryHelper.mergePropertyFilters(this.property?.filters, options.filters) };
81
92
  if (this.isInitialized() && !options.refresh && options.populate) {
82
93
  await wrapped.__em.populate(this.entity, options.populate, options);
83
94
  }
84
95
  if (!this.isInitialized() || options.refresh) {
85
96
  if (options.dataloader ?? [DataloaderType.ALL, DataloaderType.REFERENCE].includes(wrapped.__em.config.getDataloaderType())) {
86
- // eslint-disable-next-line dot-notation
87
- return wrapped.__em['refLoader'].load([this, options]);
97
+ const dataLoader = await wrapped.__em.getDataLoader('ref');
98
+ return dataLoader.load([this, options]);
88
99
  }
89
100
  return wrapped.init(options);
90
101
  }
@@ -135,9 +146,9 @@ export class Reference {
135
146
  return wrap(this.entity).toJSON(...args);
136
147
  }
137
148
  /** @ignore */
138
- [inspect.custom](depth = 2) {
149
+ [Symbol.for('nodejs.util.inspect.custom')](depth = 2) {
139
150
  const object = { ...this };
140
- const hidden = ['meta'];
151
+ const hidden = ['meta', 'property'];
141
152
  hidden.forEach(k => delete object[k]);
142
153
  const ret = inspect(object, { depth });
143
154
  const wrapped = helper(this.entity);
@@ -171,6 +182,20 @@ export class ScalarReference {
171
182
  }
172
183
  return this.value;
173
184
  }
185
+ /**
186
+ * Ensures the underlying entity is loaded first (without reloading it if it already is loaded).
187
+ * Returns the entity or throws an error just like `em.findOneOrFail()` (and respects the same config options).
188
+ */
189
+ async loadOrFail(options = {}) {
190
+ const ret = await this.load(options);
191
+ if (ret == null) {
192
+ const wrapped = helper(this.entity);
193
+ options.failHandler ??= wrapped.__em.config.get('findOneOrFailHandler');
194
+ const entityName = this.entity.constructor.name;
195
+ throw NotFoundError.failedToLoadProperty(entityName, this.property, wrapped.getPrimaryKey());
196
+ }
197
+ return ret;
198
+ }
174
199
  set(value) {
175
200
  this.value = value;
176
201
  this.initialized = true;
@@ -186,9 +211,9 @@ export class ScalarReference {
186
211
  isInitialized() {
187
212
  return this.initialized;
188
213
  }
189
- /* v8 ignore next 4 */
190
214
  /** @ignore */
191
- [inspect.custom]() {
215
+ /* v8 ignore next */
216
+ [Symbol.for('nodejs.util.inspect.custom')]() {
192
217
  return this.initialized ? `Ref<${inspect(this.value)}>` : `Ref<?>`;
193
218
  }
194
219
  }
@@ -1,5 +1,4 @@
1
1
  import type { PopulatePath } from '../enums.js';
2
- import { inspect } from 'node:util';
3
2
  import type { EntityManager } from '../EntityManager.js';
4
3
  import type { Dictionary, EntityData, EntityDictionary, EntityMetadata, IHydrator, EntityKey, PopulateOptions, Primary, AutoPath, Ref, AddEager, LoadedReference, EntityDTO, Loaded, FromEntityType, IsSubset, MergeSelected } from '../typings.js';
5
4
  import { Reference } from './Reference.js';
@@ -11,7 +10,6 @@ import { type SerializeOptions } from '../serialization/EntitySerializer.js';
11
10
  import type { FindOneOptions, LoadHint } from '../drivers/IDatabaseDriver.js';
12
11
  export declare class WrappedEntity<Entity extends object> {
13
12
  __initialized: boolean;
14
- __touched: boolean;
15
13
  __populated?: boolean;
16
14
  __managed?: boolean;
17
15
  __onLoadFired?: boolean;
@@ -41,7 +39,6 @@ export declare class WrappedEntity<Entity extends object> {
41
39
  private readonly pkGetterConverted?;
42
40
  constructor(entity: Entity, hydrator: IHydrator, pkGetter?: (e: Entity) => Primary<Entity>, pkSerializer?: (e: Entity) => string, pkGetterConverted?: (e: Entity) => Primary<Entity>);
43
41
  isInitialized(): boolean;
44
- isTouched(): boolean;
45
42
  isManaged(): boolean;
46
43
  populated(populated?: boolean | undefined): void;
47
44
  setSerializationContext<Hint extends string = never, Fields extends string = '*', Exclude extends string = never>(options: LoadHint<Entity, Hint, Fields, Exclude>): void;
@@ -61,9 +58,7 @@ export declare class WrappedEntity<Entity extends object> {
61
58
  setPrimaryKey(id: Primary<Entity> | null): void;
62
59
  getSerializedPrimaryKey(): string;
63
60
  get __meta(): EntityMetadata<Entity>;
64
- get __platform(): import("../index.js").Platform;
65
- get __config(): import("../index.js").Configuration<import("../drivers/IDatabaseDriver.js").IDatabaseDriver<import("../index.js").Connection>, EntityManager<import("../drivers/IDatabaseDriver.js").IDatabaseDriver<import("../index.js").Connection>>>;
61
+ get __platform(): import("@mikro-orm/sql").Platform;
62
+ get __config(): import("@mikro-orm/sql").Configuration<import("../drivers/IDatabaseDriver.js").IDatabaseDriver<import("@mikro-orm/sql").Connection>, EntityManager<import("../drivers/IDatabaseDriver.js").IDatabaseDriver<import("@mikro-orm/sql").Connection>>>;
66
63
  get __primaryKeys(): Primary<Entity>[];
67
- /** @ignore */
68
- [inspect.custom](): string;
69
64
  }
@@ -1,4 +1,3 @@
1
- import { inspect } from 'node:util';
2
1
  import { Reference } from './Reference.js';
3
2
  import { EntityTransformer } from '../serialization/EntityTransformer.js';
4
3
  import { EntityAssigner } from './EntityAssigner.js';
@@ -15,7 +14,6 @@ export class WrappedEntity {
15
14
  this.pkSerializer = pkSerializer;
16
15
  this.pkGetterConverted = pkGetterConverted;
17
16
  this.__initialized = true;
18
- this.__touched = false;
19
17
  this.__serializationContext = {};
20
18
  this.__loadedProperties = new Set();
21
19
  this.__data = {};
@@ -24,9 +22,6 @@ export class WrappedEntity {
24
22
  isInitialized() {
25
23
  return this.__initialized;
26
24
  }
27
- isTouched() {
28
- return this.__touched;
29
- }
30
25
  isManaged() {
31
26
  return !!this.__managed;
32
27
  }
@@ -76,7 +71,7 @@ export class WrappedEntity {
76
71
  if (!this.__em) {
77
72
  throw ValidationError.entityNotManaged(this.entity);
78
73
  }
79
- return this.__em.findOne(this.entity.constructor.name, this.entity, { ...options, refresh: true, schema: this.__schema });
74
+ return this.__em.findOne(this.entity.constructor, this.entity, { ...options, refresh: true, schema: this.__schema });
80
75
  }
81
76
  async populate(populate, options = {}) {
82
77
  if (!this.__em) {
@@ -150,10 +145,10 @@ export class WrappedEntity {
150
145
  return this.__em?.config ?? this.entity.__config;
151
146
  }
152
147
  get __primaryKeys() {
153
- return Utils.getPrimaryKeyValues(this.entity, this.__meta.primaryKeys);
148
+ return Utils.getPrimaryKeyValues(this.entity, this.__meta);
154
149
  }
155
150
  /** @ignore */
156
- [inspect.custom]() {
151
+ [Symbol.for('nodejs.util.inspect.custom')]() {
157
152
  return `[WrappedEntity<${this.__meta.className}>]`;
158
153
  }
159
154
  }