@mikro-orm/core 7.0.0-dev.12 → 7.0.0-dev.120

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 (207) hide show
  1. package/EntityManager.d.ts +85 -56
  2. package/EntityManager.js +332 -293
  3. package/MikroORM.d.ts +41 -32
  4. package/MikroORM.js +100 -140
  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 +35 -19
  16. package/drivers/IDatabaseDriver.d.ts +38 -17
  17. package/entity/BaseEntity.d.ts +0 -1
  18. package/entity/BaseEntity.js +0 -3
  19. package/entity/Collection.d.ts +95 -30
  20. package/entity/Collection.js +439 -99
  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 +30 -15
  27. package/entity/EntityLoader.d.ts +7 -6
  28. package/entity/EntityLoader.js +84 -72
  29. package/entity/EntityRepository.d.ts +1 -1
  30. package/entity/EntityRepository.js +2 -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 +568 -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 -6
  44. package/enums.js +14 -1
  45. package/errors.d.ts +17 -9
  46. package/errors.js +41 -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 +13 -17
  64. package/metadata/EntitySchema.js +67 -51
  65. package/metadata/MetadataDiscovery.d.ts +6 -10
  66. package/metadata/MetadataDiscovery.js +289 -298
  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 +2 -9
  72. package/metadata/MetadataValidator.js +22 -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 +19 -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 +124 -86
  120. package/typings.js +50 -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 +65 -33
  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 +139 -96
  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 +753 -207
  136. package/utils/Configuration.js +145 -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 +9 -6
  141. package/utils/DataloaderUtils.d.ts +15 -5
  142. package/utils/DataloaderUtils.js +65 -17
  143. package/utils/EntityComparator.d.ts +13 -9
  144. package/utils/EntityComparator.js +85 -43
  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 +12 -119
  154. package/utils/Utils.js +97 -373
  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 -18
  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 -30
  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 -24
  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/metadata/ReflectMetadataProvider.d.ts +0 -8
  205. package/metadata/ReflectMetadataProvider.js +0 -44
  206. package/utils/resolveContextProvider.d.ts +0 -10
  207. 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,34 +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
- return this.findChildrenFromPivotTable(filtered, prop, options, innerOrderBy, populate, !!ref);
144
+ const res = await this.findChildrenFromPivotTable(filtered, prop, options, innerOrderBy, populate, !!ref);
145
+ return Utils.flatten(res);
145
146
  }
146
- const where = await this.extractChildCondition(options, prop);
147
- const data = await this.findChildren(entities, prop, populate, { ...options, where, orderBy: innerOrderBy }, !!(ref || prop.mapToPk));
148
- this.initializeCollections(filtered, prop, field, data, innerOrderBy.length > 0);
149
- 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;
150
154
  }
151
155
  async populateScalar(meta, filtered, options) {
152
156
  const pk = Utils.getPrimaryKeyHash(meta.primaryKeys);
153
- 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)));
154
158
  const where = this.mergePrimaryCondition(ids, pk, options, meta, this.metadata, this.driver.getPlatform());
155
159
  const { filters, convertCustomTypes, lockMode, strategy, populateWhere, connectionType, logging, fields } = options;
156
- await this.em.find(meta.className, where, {
160
+ await this.em.find(meta.class, where, {
157
161
  filters, convertCustomTypes, lockMode, strategy, populateWhere, connectionType, logging,
158
162
  fields: fields,
159
163
  populate: [],
160
164
  });
161
165
  }
162
- initializeCollections(filtered, prop, field, children, customOrder) {
166
+ initializeCollections(filtered, prop, field, children, customOrder, partial) {
163
167
  if (prop.kind === ReferenceKind.ONE_TO_MANY) {
164
- this.initializeOneToMany(filtered, children, prop, field);
168
+ this.initializeOneToMany(filtered, children, prop, field, partial);
165
169
  }
166
170
  if (prop.kind === ReferenceKind.MANY_TO_MANY && !this.driver.getPlatform().usesPivotTable()) {
167
- this.initializeManyToMany(filtered, children, prop, field, customOrder);
171
+ this.initializeManyToMany(filtered, children, prop, field, customOrder, partial);
168
172
  }
169
173
  }
170
- initializeOneToMany(filtered, children, prop, field) {
174
+ initializeOneToMany(filtered, children, prop, field, partial) {
171
175
  const mapToPk = prop.targetMeta.properties[prop.mappedBy].mapToPk;
172
176
  const map = {};
173
177
  for (const entity of filtered) {
@@ -177,20 +181,20 @@ export class EntityLoader {
177
181
  for (const child of children) {
178
182
  const pk = child.__helper.__data[prop.mappedBy] ?? child[prop.mappedBy];
179
183
  if (pk) {
180
- 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();
181
185
  map[key]?.push(child);
182
186
  }
183
187
  }
184
188
  for (const entity of filtered) {
185
189
  const key = helper(entity).getSerializedPrimaryKey();
186
- entity[field].hydrate(map[key]);
190
+ entity[field].hydrate(map[key], undefined, partial);
187
191
  }
188
192
  }
189
- initializeManyToMany(filtered, children, prop, field, customOrder) {
193
+ initializeManyToMany(filtered, children, prop, field, customOrder, partial) {
190
194
  if (prop.mappedBy) {
191
195
  for (const entity of filtered) {
192
196
  const items = children.filter(child => child[prop.mappedBy].contains(entity, false));
193
- entity[field].hydrate(items, true);
197
+ entity[field].hydrate(items, true, partial);
194
198
  }
195
199
  }
196
200
  else { // owning side of M:N without pivot table needs to be reordered
@@ -200,15 +204,16 @@ export class EntityLoader {
200
204
  if (!customOrder) {
201
205
  items.sort((a, b) => order.indexOf(a) - order.indexOf(b));
202
206
  }
203
- entity[field].hydrate(items, true);
207
+ entity[field].hydrate(items, true, partial);
204
208
  }
205
209
  }
206
210
  }
207
211
  async findChildren(entities, prop, populate, options, ref) {
208
- const children = this.getChildReferences(entities, prop, options, ref);
212
+ const children = Utils.unique(this.getChildReferences(entities, prop, options, ref));
209
213
  const meta = prop.targetMeta;
210
214
  let fk = Utils.getPrimaryKeyHash(meta.primaryKeys);
211
215
  let schema = options.schema;
216
+ const partial = !Utils.isEmpty(prop.where) || !Utils.isEmpty(options.where);
212
217
  if (prop.kind === ReferenceKind.ONE_TO_MANY || (prop.kind === ReferenceKind.MANY_TO_MANY && !prop.owner)) {
213
218
  fk = meta.properties[prop.mappedBy].name;
214
219
  }
@@ -218,7 +223,7 @@ export class EntityLoader {
218
223
  children.push(...this.filterByReferences(entities, prop.name, options.refresh));
219
224
  }
220
225
  if (children.length === 0) {
221
- return [];
226
+ return { items: [], partial };
222
227
  }
223
228
  if (!schema && [ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(prop.kind)) {
224
229
  schema = children.find(e => e.__helper.__schema)?.__helper.__schema;
@@ -227,33 +232,19 @@ export class EntityLoader {
227
232
  let where = this.mergePrimaryCondition(ids, fk, options, meta, this.metadata, this.driver.getPlatform());
228
233
  const fields = this.buildFields(options.fields, prop, ref);
229
234
  /* eslint-disable prefer-const */
230
- let { refresh, filters, convertCustomTypes, lockMode, strategy, populateWhere, connectionType, logging, } = options;
235
+ let { refresh, filters, convertCustomTypes, lockMode, strategy, populateWhere = 'infer', connectionType, logging, } = options;
231
236
  /* eslint-enable prefer-const */
232
237
  if (typeof populateWhere === 'object') {
233
238
  populateWhere = await this.extractChildCondition({ where: populateWhere }, prop);
234
239
  }
235
- if (!Utils.isEmpty(prop.where)) {
240
+ if (!Utils.isEmpty(prop.where) || Raw.hasObjectFragments(prop.where)) {
236
241
  where = { $and: [where, prop.where] };
237
242
  }
238
- const propOrderBy = [];
239
- if (prop.orderBy) {
240
- for (const item of Utils.asArray(prop.orderBy)) {
241
- for (const field of Utils.keys(item)) {
242
- const rawField = RawQueryFragment.getKnownFragment(field, false);
243
- if (rawField) {
244
- const raw2 = raw(rawField.sql, rawField.params);
245
- propOrderBy.push({ [raw2.toString()]: item[field] });
246
- continue;
247
- }
248
- propOrderBy.push({ [field]: item[field] });
249
- }
250
- }
251
- }
252
- 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) => {
253
244
  // skip consecutive ordering with the same key to get around mongo issues
254
- 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));
255
246
  });
256
- const items = await this.em.find(prop.type, where, {
247
+ const items = await this.em.find(meta.class, where, {
257
248
  filters, convertCustomTypes, lockMode, populateWhere, logging,
258
249
  orderBy,
259
250
  populate: populate.children ?? populate.all ?? [],
@@ -264,6 +255,24 @@ export class EntityLoader {
264
255
  // @ts-ignore not a public option, will be propagated to the populate call
265
256
  visited: options.visited,
266
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
+ }
267
276
  for (const item of items) {
268
277
  if (ref && !helper(item).__onLoadFired) {
269
278
  helper(item).__initialized = false;
@@ -271,10 +280,10 @@ export class EntityLoader {
271
280
  this.em.getUnitOfWork()['loadedEntities'].delete(item);
272
281
  }
273
282
  }
274
- return items;
283
+ return { items, partial };
275
284
  }
276
285
  mergePrimaryCondition(ids, pk, options, meta, metadata, platform) {
277
- 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 });
278
287
  const where = { ...options.where };
279
288
  Utils.dropUndefinedProperties(where);
280
289
  return where[pk]
@@ -287,6 +296,7 @@ export class EntityLoader {
287
296
  if (prop.kind === ReferenceKind.SCALAR && !prop.lazy) {
288
297
  return;
289
298
  }
299
+ options = { ...options, filters: QueryHelper.mergePropertyFilters(prop.filters, options.filters) };
290
300
  const populated = await this.populateMany(entityName, entities, populate, options);
291
301
  if (!populate.children && !populate.all) {
292
302
  return;
@@ -320,11 +330,16 @@ export class EntityLoader {
320
330
  for (const entity of entities) {
321
331
  visited.delete(entity);
322
332
  }
323
- 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));
324
335
  for (const entity of entities) {
325
336
  visited.add(entity);
326
337
  }
327
- 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, {
328
343
  where: await this.extractChildCondition(options, prop, false),
329
344
  orderBy: innerOrderBy,
330
345
  fields,
@@ -341,8 +356,11 @@ export class EntityLoader {
341
356
  refresh: refresh && !filtered.every(item => options.visited.has(item)),
342
357
  // @ts-ignore not a public option, will be propagated to the populate call
343
358
  visited: options.visited,
359
+ // @ts-ignore not a public option
360
+ filtered,
344
361
  });
345
362
  }
363
+ /** @internal */
346
364
  async findChildrenFromPivotTable(filtered, prop, options, orderBy, populate, pivotJoin) {
347
365
  const ids = filtered.map(e => e.__helper.__primaryKeys);
348
366
  const refresh = options.refresh;
@@ -366,12 +384,12 @@ export class EntityLoader {
366
384
  for (const entity of filtered) {
367
385
  const items = map[entity.__helper.getSerializedPrimaryKey()].map(item => {
368
386
  if (pivotJoin) {
369
- return this.em.getReference(prop.type, item, {
387
+ return this.em.getReference(prop.targetMeta.class, item, {
370
388
  convertCustomTypes: true,
371
389
  schema: options.schema ?? this.em.config.get('schema'),
372
390
  });
373
391
  }
374
- const entity = this.em.getEntityFactory().create(prop.type, item, {
392
+ const entity = this.em.getEntityFactory().create(prop.targetMeta.class, item, {
375
393
  refresh,
376
394
  merge: true,
377
395
  convertCustomTypes: true,
@@ -380,23 +398,20 @@ export class EntityLoader {
380
398
  return this.em.getUnitOfWork().register(entity, item, { refresh, loaded: true });
381
399
  });
382
400
  entity[prop.name].hydrate(items, true);
383
- children.push(...items);
401
+ children.push(items);
384
402
  }
385
403
  return children;
386
404
  }
387
405
  async extractChildCondition(options, prop, filters = false) {
388
406
  const where = options.where;
389
407
  const subCond = Utils.isPlainObject(where[prop.name]) ? where[prop.name] : {};
390
- const meta2 = this.metadata.find(prop.type);
391
- if (!meta2) {
392
- return {};
393
- }
408
+ const meta2 = prop.targetMeta;
394
409
  const pk = Utils.getPrimaryKeyHash(meta2.primaryKeys);
395
410
  ['$and', '$or'].forEach(op => {
396
411
  if (where[op]) {
397
412
  const child = where[op]
398
413
  .map((cond) => cond[prop.name])
399
- .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))))
400
415
  .map((cond) => {
401
416
  if (Utils.isPrimaryKey(cond)) {
402
417
  return { [pk]: cond };
@@ -417,7 +432,7 @@ export class EntityLoader {
417
432
  });
418
433
  }
419
434
  if (filters) {
420
- return this.em.applyFilters(prop.type, subCond, options.filters, 'read', options);
435
+ return this.em.applyFilters(meta2.class, subCond, options.filters, 'read', options);
421
436
  }
422
437
  return subCond;
423
438
  }
@@ -435,7 +450,7 @@ export class EntityLoader {
435
450
  const parts = f.toString().split('.');
436
451
  const propName = parts.shift();
437
452
  const childPropName = parts.join('.');
438
- /* v8 ignore next 3 */
453
+ /* v8 ignore next */
439
454
  if (propName === prop.name) {
440
455
  ret.push(childPropName);
441
456
  }
@@ -456,23 +471,20 @@ export class EntityLoader {
456
471
  }
457
472
  getChildReferences(entities, prop, options, ref) {
458
473
  const filtered = this.filterCollections(entities, prop.name, options, ref);
459
- const children = [];
460
474
  if (prop.kind === ReferenceKind.ONE_TO_MANY) {
461
- children.push(...filtered.map(e => e[prop.name].owner));
475
+ return filtered.map(e => e[prop.name].owner);
462
476
  }
463
- else if (prop.kind === ReferenceKind.MANY_TO_MANY && prop.owner) {
464
- children.push(...filtered.reduce((a, b) => {
477
+ if (prop.kind === ReferenceKind.MANY_TO_MANY && prop.owner) {
478
+ return filtered.reduce((a, b) => {
465
479
  a.push(...b[prop.name].getItems());
466
480
  return a;
467
- }, []));
481
+ }, []);
468
482
  }
469
- else if (prop.kind === ReferenceKind.MANY_TO_MANY) { // inverse side
470
- children.push(...filtered);
483
+ if (prop.kind === ReferenceKind.MANY_TO_MANY) { // inverse side
484
+ return filtered;
471
485
  }
472
- else { // MANY_TO_ONE or ONE_TO_ONE
473
- children.push(...this.filterReferences(entities, prop.name, options, ref));
474
- }
475
- return children;
486
+ // MANY_TO_ONE or ONE_TO_ONE
487
+ return this.filterReferences(entities, prop.name, options, ref);
476
488
  }
477
489
  filterCollections(entities, field, options, ref) {
478
490
  if (options.refresh) {
@@ -489,7 +501,7 @@ export class EntityLoader {
489
501
  return wrapped.__loadedProperties.has(field);
490
502
  }
491
503
  const [f, ...r] = field.split('.');
492
- /* v8 ignore next 3 */
504
+ /* v8 ignore next */
493
505
  if (!wrapped.__loadedProperties.has(f) || !wrapped.__meta.properties[f]?.targetMeta) {
494
506
  return false;
495
507
  }
@@ -522,7 +534,7 @@ export class EntityLoader {
522
534
  .map(e => Reference.unwrapReference(e[field]));
523
535
  }
524
536
  filterByReferences(entities, field, refresh) {
525
- /* v8 ignore next 3 */
537
+ /* v8 ignore next */
526
538
  if (refresh) {
527
539
  return entities;
528
540
  }
@@ -553,10 +565,10 @@ export class EntityLoader {
553
565
  if (!meta && !prefix) {
554
566
  return populate;
555
567
  }
556
- if (visited.includes(entityName) || !meta) {
568
+ if (!meta || visited.includes(meta)) {
557
569
  return [];
558
570
  }
559
- visited.push(entityName);
571
+ visited.push(meta);
560
572
  const ret = prefix === '' ? [...populate] : [];
561
573
  meta.relations
562
574
  .filter(prop => {
@@ -569,12 +581,12 @@ export class EntityLoader {
569
581
  const field = this.getRelationName(meta, prop);
570
582
  const prefixed = prefix ? `${prefix}.${field}` : field;
571
583
  const nestedPopulate = populate.filter(p => p.field === prop.name).flatMap(p => p.children).filter(Boolean);
572
- const nested = this.lookupEagerLoadedRelationships(prop.type, nestedPopulate, strategy, prefixed, visited.slice());
584
+ const nested = this.lookupEagerLoadedRelationships(prop.targetMeta.class, nestedPopulate, strategy, prefixed, visited.slice());
573
585
  if (nested.length > 0) {
574
586
  ret.push(...nested);
575
587
  }
576
588
  else {
577
- 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;
578
590
  ret.push({
579
591
  field: prefixed,
580
592
  // enforce select-in strategy for self-referencing relations
@@ -80,7 +80,7 @@ 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
  */
@@ -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.
@@ -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
  }