@mikro-orm/core 6.4.17-dev.9 → 6.4.17-dev.91

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 (56) hide show
  1. package/EntityManager.d.ts +11 -2
  2. package/EntityManager.js +37 -22
  3. package/README.md +1 -2
  4. package/connections/Connection.d.ts +4 -2
  5. package/connections/Connection.js +2 -2
  6. package/decorators/Entity.d.ts +14 -0
  7. package/decorators/Indexed.d.ts +2 -2
  8. package/decorators/Transactional.d.ts +1 -0
  9. package/decorators/Transactional.js +3 -3
  10. package/drivers/IDatabaseDriver.d.ts +4 -0
  11. package/entity/ArrayCollection.d.ts +3 -1
  12. package/entity/ArrayCollection.js +7 -2
  13. package/entity/EntityFactory.d.ts +6 -0
  14. package/entity/EntityFactory.js +17 -6
  15. package/entity/EntityHelper.js +4 -1
  16. package/entity/EntityLoader.js +26 -18
  17. package/entity/Reference.d.ts +5 -0
  18. package/entity/Reference.js +16 -0
  19. package/entity/WrappedEntity.js +1 -1
  20. package/entity/defineEntity.d.ts +528 -0
  21. package/entity/defineEntity.js +684 -0
  22. package/entity/index.d.ts +2 -0
  23. package/entity/index.js +2 -0
  24. package/entity/utils.d.ts +7 -0
  25. package/entity/utils.js +16 -3
  26. package/enums.d.ts +3 -1
  27. package/enums.js +2 -0
  28. package/hydration/ObjectHydrator.js +1 -1
  29. package/index.d.ts +1 -1
  30. package/index.mjs +4 -0
  31. package/metadata/MetadataDiscovery.d.ts +0 -1
  32. package/metadata/MetadataDiscovery.js +16 -13
  33. package/package.json +4 -4
  34. package/platforms/Platform.d.ts +3 -1
  35. package/types/BooleanType.d.ts +1 -1
  36. package/types/DecimalType.js +1 -1
  37. package/types/DoubleType.js +1 -1
  38. package/typings.d.ts +18 -9
  39. package/typings.js +21 -4
  40. package/unit-of-work/ChangeSetPersister.d.ts +4 -2
  41. package/unit-of-work/ChangeSetPersister.js +14 -10
  42. package/unit-of-work/UnitOfWork.d.ts +1 -1
  43. package/unit-of-work/UnitOfWork.js +22 -6
  44. package/utils/Configuration.d.ts +7 -1
  45. package/utils/Configuration.js +1 -0
  46. package/utils/ConfigurationLoader.js +2 -2
  47. package/utils/Cursor.js +3 -0
  48. package/utils/EntityComparator.d.ts +6 -2
  49. package/utils/EntityComparator.js +29 -8
  50. package/utils/QueryHelper.d.ts +6 -0
  51. package/utils/QueryHelper.js +47 -4
  52. package/utils/RawQueryFragment.d.ts +34 -0
  53. package/utils/RawQueryFragment.js +35 -0
  54. package/utils/Utils.d.ts +2 -2
  55. package/utils/Utils.js +32 -8
  56. package/utils/upsert-utils.js +9 -1
@@ -41,7 +41,7 @@ class EntityLoader {
41
41
  options.refresh ??= false;
42
42
  options.convertCustomTypes ??= true;
43
43
  if (references.length > 0) {
44
- await this.populateScalar(meta, references, options);
44
+ await this.populateScalar(meta, references, { ...options, populateWhere: undefined });
45
45
  }
46
46
  populate = this.normalizePopulate(entityName, populate, options.strategy, options.lookup);
47
47
  const invalid = populate.find(({ field }) => !this.em.canPopulate(entityName, field));
@@ -143,18 +143,22 @@ class EntityLoader {
143
143
  const innerOrderBy = Utils_1.Utils.asArray(options.orderBy)
144
144
  .filter(orderBy => (Array.isArray(orderBy[prop.name]) && orderBy[prop.name].length > 0) || Utils_1.Utils.isObject(orderBy[prop.name]))
145
145
  .flatMap(orderBy => orderBy[prop.name]);
146
+ const where = await this.extractChildCondition(options, prop);
146
147
  if (prop.kind === enums_1.ReferenceKind.MANY_TO_MANY && this.driver.getPlatform().usesPivotTable()) {
147
148
  const res = await this.findChildrenFromPivotTable(filtered, prop, options, innerOrderBy, populate, !!ref);
148
149
  return Utils_1.Utils.flatten(res);
149
150
  }
150
- const where = await this.extractChildCondition(options, prop);
151
- const data = await this.findChildren(entities, prop, populate, { ...options, where, orderBy: innerOrderBy }, !!(ref || prop.mapToPk));
152
- this.initializeCollections(filtered, prop, field, data, innerOrderBy.length > 0);
153
- return data;
151
+ const { items, partial } = await this.findChildren(options.filtered ?? entities, prop, populate, {
152
+ ...options,
153
+ where,
154
+ orderBy: innerOrderBy,
155
+ }, !!(ref || prop.mapToPk));
156
+ this.initializeCollections(filtered, prop, field, items, innerOrderBy.length > 0, partial);
157
+ return items;
154
158
  }
155
159
  async populateScalar(meta, filtered, options) {
156
160
  const pk = Utils_1.Utils.getPrimaryKeyHash(meta.primaryKeys);
157
- const ids = Utils_1.Utils.unique(filtered.map(e => Utils_1.Utils.getPrimaryKeyValues(e, meta.primaryKeys, true)));
161
+ const ids = Utils_1.Utils.unique(filtered.map(e => Utils_1.Utils.getPrimaryKeyValues(e, meta, true)));
158
162
  const where = this.mergePrimaryCondition(ids, pk, options, meta, this.metadata, this.driver.getPlatform());
159
163
  const { filters, convertCustomTypes, lockMode, strategy, populateWhere, connectionType, logging, fields } = options;
160
164
  await this.em.find(meta.className, where, {
@@ -163,15 +167,15 @@ class EntityLoader {
163
167
  populate: [],
164
168
  });
165
169
  }
166
- initializeCollections(filtered, prop, field, children, customOrder) {
170
+ initializeCollections(filtered, prop, field, children, customOrder, partial) {
167
171
  if (prop.kind === enums_1.ReferenceKind.ONE_TO_MANY) {
168
- this.initializeOneToMany(filtered, children, prop, field);
172
+ this.initializeOneToMany(filtered, children, prop, field, partial);
169
173
  }
170
174
  if (prop.kind === enums_1.ReferenceKind.MANY_TO_MANY && !this.driver.getPlatform().usesPivotTable()) {
171
- this.initializeManyToMany(filtered, children, prop, field, customOrder);
175
+ this.initializeManyToMany(filtered, children, prop, field, customOrder, partial);
172
176
  }
173
177
  }
174
- initializeOneToMany(filtered, children, prop, field) {
178
+ initializeOneToMany(filtered, children, prop, field, partial) {
175
179
  const mapToPk = prop.targetMeta.properties[prop.mappedBy].mapToPk;
176
180
  const map = {};
177
181
  for (const entity of filtered) {
@@ -187,14 +191,14 @@ class EntityLoader {
187
191
  }
188
192
  for (const entity of filtered) {
189
193
  const key = (0, wrap_1.helper)(entity).getSerializedPrimaryKey();
190
- entity[field].hydrate(map[key]);
194
+ entity[field].hydrate(map[key], undefined, partial);
191
195
  }
192
196
  }
193
- initializeManyToMany(filtered, children, prop, field, customOrder) {
197
+ initializeManyToMany(filtered, children, prop, field, customOrder, partial) {
194
198
  if (prop.mappedBy) {
195
199
  for (const entity of filtered) {
196
200
  const items = children.filter(child => child[prop.mappedBy].contains(entity, false));
197
- entity[field].hydrate(items, true);
201
+ entity[field].hydrate(items, true, partial);
198
202
  }
199
203
  }
200
204
  else { // owning side of M:N without pivot table needs to be reordered
@@ -204,7 +208,7 @@ class EntityLoader {
204
208
  if (!customOrder) {
205
209
  items.sort((a, b) => order.indexOf(a) - order.indexOf(b));
206
210
  }
207
- entity[field].hydrate(items, true);
211
+ entity[field].hydrate(items, true, partial);
208
212
  }
209
213
  }
210
214
  }
@@ -213,6 +217,7 @@ class EntityLoader {
213
217
  const meta = prop.targetMeta;
214
218
  let fk = Utils_1.Utils.getPrimaryKeyHash(meta.primaryKeys);
215
219
  let schema = options.schema;
220
+ const partial = !Utils_1.Utils.isEmpty(prop.where) || !Utils_1.Utils.isEmpty(options.where);
216
221
  if (prop.kind === enums_1.ReferenceKind.ONE_TO_MANY || (prop.kind === enums_1.ReferenceKind.MANY_TO_MANY && !prop.owner)) {
217
222
  fk = meta.properties[prop.mappedBy].name;
218
223
  }
@@ -222,7 +227,7 @@ class EntityLoader {
222
227
  children.push(...this.filterByReferences(entities, prop.name, options.refresh));
223
228
  }
224
229
  if (children.length === 0) {
225
- return [];
230
+ return { items: [], partial };
226
231
  }
227
232
  if (!schema && [enums_1.ReferenceKind.ONE_TO_ONE, enums_1.ReferenceKind.MANY_TO_ONE].includes(prop.kind)) {
228
233
  schema = children.find(e => e.__helper.__schema)?.__helper.__schema;
@@ -271,7 +276,7 @@ class EntityLoader {
271
276
  this.em.getUnitOfWork()['loadedEntities'].delete(item);
272
277
  }
273
278
  }
274
- return items;
279
+ return { items, partial };
275
280
  }
276
281
  mergePrimaryCondition(ids, pk, options, meta, metadata, platform) {
277
282
  const cond1 = QueryHelper_1.QueryHelper.processWhere({ where: { [pk]: { $in: ids } }, entityName: meta.className, metadata, platform, convertCustomTypes: !options.convertCustomTypes });
@@ -320,11 +325,12 @@ class EntityLoader {
320
325
  for (const entity of entities) {
321
326
  visited.delete(entity);
322
327
  }
323
- const filtered = Utils_1.Utils.unique(children.filter(e => !visited.has(e)));
328
+ const unique = Utils_1.Utils.unique(children);
329
+ const filtered = unique.filter(e => !visited.has(e));
324
330
  for (const entity of entities) {
325
331
  visited.add(entity);
326
332
  }
327
- await this.populate(prop.type, filtered, populate.children ?? populate.all, {
333
+ await this.populate(prop.type, unique, populate.children ?? populate.all, {
328
334
  where: await this.extractChildCondition(options, prop, false),
329
335
  orderBy: innerOrderBy,
330
336
  fields,
@@ -341,6 +347,8 @@ class EntityLoader {
341
347
  refresh: refresh && !filtered.every(item => options.visited.has(item)),
342
348
  // @ts-ignore not a public option, will be propagated to the populate call
343
349
  visited: options.visited,
350
+ // @ts-ignore not a public option
351
+ filtered,
344
352
  });
345
353
  }
346
354
  /** @internal */
@@ -56,6 +56,11 @@ export declare class ScalarReference<Value> {
56
56
  * Returns either the whole entity, or the requested property.
57
57
  */
58
58
  load(options?: Omit<LoadReferenceOptions<any, any>, 'populate' | 'fields' | 'exclude'>): Promise<Value | undefined>;
59
+ /**
60
+ * Ensures the underlying entity is loaded first (without reloading it if it already is loaded).
61
+ * Returns the entity or throws an error just like `em.findOneOrFail()` (and respects the same config options).
62
+ */
63
+ loadOrFail(options?: Omit<LoadReferenceOrFailOptions<any, any>, 'populate' | 'fields' | 'exclude'>): Promise<Value>;
59
64
  set(value: Value): void;
60
65
  bind<Entity extends object>(entity: Entity, property: EntityKey<Entity>): void;
61
66
  unwrap(): Value | undefined;
@@ -7,6 +7,7 @@ const node_util_1 = require("node:util");
7
7
  const enums_1 = require("../enums");
8
8
  const wrap_1 = require("./wrap");
9
9
  const utils_1 = require("../utils");
10
+ const errors_1 = require("../errors");
10
11
  class Reference {
11
12
  entity;
12
13
  constructor(entity) {
@@ -178,6 +179,21 @@ class ScalarReference {
178
179
  }
179
180
  return this.value;
180
181
  }
182
+ /**
183
+ * Ensures the underlying entity is loaded first (without reloading it if it already is loaded).
184
+ * Returns the entity or throws an error just like `em.findOneOrFail()` (and respects the same config options).
185
+ */
186
+ async loadOrFail(options = {}) {
187
+ const ret = await this.load(options);
188
+ if (!ret) {
189
+ const wrapped = (0, wrap_1.helper)(this.entity);
190
+ options.failHandler ??= wrapped.__em.config.get('findOneOrFailHandler');
191
+ const entityName = this.entity.constructor.name;
192
+ const where = wrapped.getPrimaryKey();
193
+ throw new errors_1.NotFoundError(`${entityName} (${where}) failed to load property '${this.property}'`);
194
+ }
195
+ return ret;
196
+ }
181
197
  set(value) {
182
198
  this.value = value;
183
199
  this.initialized = true;
@@ -153,7 +153,7 @@ class WrappedEntity {
153
153
  return this.__em?.config ?? this.entity.__config;
154
154
  }
155
155
  get __primaryKeys() {
156
- return Utils_1.Utils.getPrimaryKeyValues(this.entity, this.__meta.primaryKeys);
156
+ return Utils_1.Utils.getPrimaryKeyValues(this.entity, this.__meta);
157
157
  }
158
158
  /** @ignore */
159
159
  [node_util_1.inspect.custom]() {