@mikro-orm/core 7.0.0-dev.2 → 7.0.0-dev.200

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 (210) hide show
  1. package/EntityManager.d.ts +111 -61
  2. package/EntityManager.js +346 -300
  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 +47 -17
  17. package/entity/BaseEntity.d.ts +2 -2
  18. package/entity/BaseEntity.js +0 -3
  19. package/entity/Collection.d.ts +95 -31
  20. package/entity/Collection.js +444 -102
  21. package/entity/EntityAssigner.d.ts +1 -1
  22. package/entity/EntityAssigner.js +26 -18
  23. package/entity/EntityFactory.d.ts +13 -1
  24. package/entity/EntityFactory.js +88 -54
  25. package/entity/EntityHelper.d.ts +2 -2
  26. package/entity/EntityHelper.js +38 -15
  27. package/entity/EntityLoader.d.ts +8 -7
  28. package/entity/EntityLoader.js +134 -80
  29. package/entity/EntityRepository.d.ts +24 -4
  30. package/entity/EntityRepository.js +8 -2
  31. package/entity/Reference.d.ts +9 -12
  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 +585 -0
  36. package/entity/defineEntity.js +533 -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 +22 -6
  44. package/enums.js +15 -1
  45. package/errors.d.ts +23 -9
  46. package/errors.js +59 -21
  47. package/events/EventManager.d.ts +2 -1
  48. package/events/EventManager.js +19 -11
  49. package/events/EventSubscriber.d.ts +3 -1
  50. package/hydration/Hydrator.js +1 -2
  51. package/hydration/ObjectHydrator.d.ts +4 -4
  52. package/hydration/ObjectHydrator.js +53 -33
  53. package/index.d.ts +2 -2
  54. package/index.js +1 -2
  55. package/logging/DefaultLogger.d.ts +1 -1
  56. package/logging/DefaultLogger.js +1 -0
  57. package/logging/SimpleLogger.d.ts +1 -1
  58. package/logging/colors.d.ts +1 -1
  59. package/logging/colors.js +7 -6
  60. package/logging/index.d.ts +1 -0
  61. package/logging/index.js +1 -0
  62. package/logging/inspect.d.ts +2 -0
  63. package/logging/inspect.js +11 -0
  64. package/metadata/EntitySchema.d.ts +26 -26
  65. package/metadata/EntitySchema.js +82 -51
  66. package/metadata/MetadataDiscovery.d.ts +7 -10
  67. package/metadata/MetadataDiscovery.js +408 -335
  68. package/metadata/MetadataProvider.d.ts +11 -2
  69. package/metadata/MetadataProvider.js +46 -2
  70. package/metadata/MetadataStorage.d.ts +13 -11
  71. package/metadata/MetadataStorage.js +70 -37
  72. package/metadata/MetadataValidator.d.ts +17 -9
  73. package/metadata/MetadataValidator.js +100 -42
  74. package/metadata/discover-entities.d.ts +5 -0
  75. package/metadata/discover-entities.js +40 -0
  76. package/metadata/index.d.ts +1 -1
  77. package/metadata/index.js +1 -1
  78. package/metadata/types.d.ts +502 -0
  79. package/metadata/types.js +1 -0
  80. package/naming-strategy/AbstractNamingStrategy.d.ts +12 -4
  81. package/naming-strategy/AbstractNamingStrategy.js +14 -2
  82. package/naming-strategy/EntityCaseNamingStrategy.d.ts +3 -3
  83. package/naming-strategy/EntityCaseNamingStrategy.js +6 -5
  84. package/naming-strategy/MongoNamingStrategy.d.ts +3 -3
  85. package/naming-strategy/MongoNamingStrategy.js +6 -6
  86. package/naming-strategy/NamingStrategy.d.ts +24 -4
  87. package/naming-strategy/UnderscoreNamingStrategy.d.ts +3 -3
  88. package/naming-strategy/UnderscoreNamingStrategy.js +6 -6
  89. package/not-supported.d.ts +2 -0
  90. package/not-supported.js +4 -0
  91. package/package.json +19 -11
  92. package/platforms/ExceptionConverter.js +1 -1
  93. package/platforms/Platform.d.ts +7 -13
  94. package/platforms/Platform.js +20 -43
  95. package/serialization/EntitySerializer.d.ts +5 -0
  96. package/serialization/EntitySerializer.js +47 -27
  97. package/serialization/EntityTransformer.js +28 -18
  98. package/serialization/SerializationContext.d.ts +6 -6
  99. package/serialization/SerializationContext.js +16 -13
  100. package/types/ArrayType.d.ts +1 -1
  101. package/types/ArrayType.js +2 -3
  102. package/types/BigIntType.d.ts +9 -6
  103. package/types/BigIntType.js +4 -1
  104. package/types/BlobType.d.ts +0 -1
  105. package/types/BlobType.js +0 -3
  106. package/types/BooleanType.d.ts +2 -1
  107. package/types/BooleanType.js +3 -0
  108. package/types/DecimalType.d.ts +6 -4
  109. package/types/DecimalType.js +3 -3
  110. package/types/DoubleType.js +2 -2
  111. package/types/EnumArrayType.js +1 -2
  112. package/types/JsonType.d.ts +1 -1
  113. package/types/JsonType.js +7 -2
  114. package/types/TinyIntType.js +1 -1
  115. package/types/Type.d.ts +2 -4
  116. package/types/Type.js +3 -3
  117. package/types/Uint8ArrayType.d.ts +0 -1
  118. package/types/Uint8ArrayType.js +1 -4
  119. package/types/index.d.ts +1 -1
  120. package/typings.d.ts +300 -140
  121. package/typings.js +62 -44
  122. package/unit-of-work/ChangeSet.d.ts +2 -6
  123. package/unit-of-work/ChangeSet.js +4 -5
  124. package/unit-of-work/ChangeSetComputer.d.ts +1 -3
  125. package/unit-of-work/ChangeSetComputer.js +26 -13
  126. package/unit-of-work/ChangeSetPersister.d.ts +5 -4
  127. package/unit-of-work/ChangeSetPersister.js +77 -35
  128. package/unit-of-work/CommitOrderCalculator.d.ts +12 -10
  129. package/unit-of-work/CommitOrderCalculator.js +13 -13
  130. package/unit-of-work/IdentityMap.d.ts +12 -0
  131. package/unit-of-work/IdentityMap.js +39 -1
  132. package/unit-of-work/UnitOfWork.d.ts +23 -3
  133. package/unit-of-work/UnitOfWork.js +199 -106
  134. package/utils/AbstractSchemaGenerator.d.ts +5 -5
  135. package/utils/AbstractSchemaGenerator.js +22 -17
  136. package/utils/AsyncContext.d.ts +6 -0
  137. package/utils/AsyncContext.js +42 -0
  138. package/utils/Configuration.d.ts +779 -207
  139. package/utils/Configuration.js +146 -190
  140. package/utils/ConfigurationLoader.d.ts +1 -54
  141. package/utils/ConfigurationLoader.js +1 -352
  142. package/utils/Cursor.d.ts +3 -6
  143. package/utils/Cursor.js +27 -11
  144. package/utils/DataloaderUtils.d.ts +15 -5
  145. package/utils/DataloaderUtils.js +65 -17
  146. package/utils/EntityComparator.d.ts +13 -9
  147. package/utils/EntityComparator.js +164 -89
  148. package/utils/QueryHelper.d.ts +14 -6
  149. package/utils/QueryHelper.js +88 -26
  150. package/utils/RawQueryFragment.d.ts +48 -25
  151. package/utils/RawQueryFragment.js +67 -66
  152. package/utils/RequestContext.js +2 -2
  153. package/utils/TransactionContext.js +2 -2
  154. package/utils/TransactionManager.d.ts +65 -0
  155. package/utils/TransactionManager.js +223 -0
  156. package/utils/Utils.d.ts +13 -120
  157. package/utils/Utils.js +104 -375
  158. package/utils/clone.js +8 -23
  159. package/utils/env-vars.d.ts +7 -0
  160. package/utils/env-vars.js +97 -0
  161. package/utils/fs-utils.d.ts +32 -0
  162. package/utils/fs-utils.js +178 -0
  163. package/utils/index.d.ts +2 -1
  164. package/utils/index.js +2 -1
  165. package/utils/upsert-utils.d.ts +9 -4
  166. package/utils/upsert-utils.js +55 -4
  167. package/decorators/Check.d.ts +0 -3
  168. package/decorators/Check.js +0 -13
  169. package/decorators/CreateRequestContext.d.ts +0 -3
  170. package/decorators/CreateRequestContext.js +0 -29
  171. package/decorators/Embeddable.d.ts +0 -8
  172. package/decorators/Embeddable.js +0 -11
  173. package/decorators/Embedded.d.ts +0 -18
  174. package/decorators/Embedded.js +0 -18
  175. package/decorators/Entity.d.ts +0 -18
  176. package/decorators/Entity.js +0 -13
  177. package/decorators/Enum.d.ts +0 -9
  178. package/decorators/Enum.js +0 -16
  179. package/decorators/Filter.d.ts +0 -2
  180. package/decorators/Filter.js +0 -8
  181. package/decorators/Formula.d.ts +0 -5
  182. package/decorators/Formula.js +0 -15
  183. package/decorators/Indexed.d.ts +0 -17
  184. package/decorators/Indexed.js +0 -20
  185. package/decorators/ManyToMany.d.ts +0 -40
  186. package/decorators/ManyToMany.js +0 -14
  187. package/decorators/ManyToOne.d.ts +0 -30
  188. package/decorators/ManyToOne.js +0 -14
  189. package/decorators/OneToMany.d.ts +0 -28
  190. package/decorators/OneToMany.js +0 -17
  191. package/decorators/OneToOne.d.ts +0 -24
  192. package/decorators/OneToOne.js +0 -7
  193. package/decorators/PrimaryKey.d.ts +0 -9
  194. package/decorators/PrimaryKey.js +0 -20
  195. package/decorators/Property.d.ts +0 -250
  196. package/decorators/Property.js +0 -32
  197. package/decorators/Transactional.d.ts +0 -13
  198. package/decorators/Transactional.js +0 -28
  199. package/decorators/hooks.d.ts +0 -16
  200. package/decorators/hooks.js +0 -47
  201. package/decorators/index.d.ts +0 -17
  202. package/decorators/index.js +0 -17
  203. package/entity/ArrayCollection.d.ts +0 -116
  204. package/entity/ArrayCollection.js +0 -395
  205. package/entity/EntityValidator.d.ts +0 -19
  206. package/entity/EntityValidator.js +0 -150
  207. package/metadata/ReflectMetadataProvider.d.ts +0 -8
  208. package/metadata/ReflectMetadataProvider.js +0 -44
  209. package/utils/resolveContextProvider.d.ts +0 -10
  210. package/utils/resolveContextProvider.js +0 -28
@@ -1,7 +1,7 @@
1
- import type { ConnectionType, Dictionary, FilterQuery, PopulateOptions } from '../typings.js';
1
+ import type { AnyEntity, ConnectionType, EntityName, EntityProperty, FilterQuery, PopulateOptions } from '../typings.js';
2
2
  import type { EntityManager } from '../EntityManager.js';
3
3
  import { LoadStrategy, type LockMode, type PopulateHint, PopulatePath, type QueryOrderMap } from '../enums.js';
4
- import type { EntityField } from '../drivers/IDatabaseDriver.js';
4
+ import type { EntityField, FilterOptions } from '../drivers/IDatabaseDriver.js';
5
5
  import type { LoggingOptions } from '../logging/Logger.js';
6
6
  export type EntityLoaderOptions<Entity, Fields extends string = PopulatePath.ALL, Excludes extends string = never> = {
7
7
  where?: FilterQuery<Entity>;
@@ -14,8 +14,8 @@ export type EntityLoaderOptions<Entity, Fields extends string = PopulatePath.ALL
14
14
  lookup?: boolean;
15
15
  convertCustomTypes?: boolean;
16
16
  ignoreLazyScalarProperties?: boolean;
17
- filters?: Dictionary<boolean | Dictionary> | string[] | boolean;
18
- strategy?: LoadStrategy;
17
+ filters?: FilterOptions;
18
+ strategy?: LoadStrategy | `${LoadStrategy}`;
19
19
  lockMode?: Exclude<LockMode, LockMode.OPTIMISTIC>;
20
20
  schema?: string;
21
21
  connectionType?: ConnectionType;
@@ -30,8 +30,8 @@ export declare class EntityLoader {
30
30
  * Loads specified relations in batch.
31
31
  * This will execute one query for each relation, that will populate it on all the specified entities.
32
32
  */
33
- populate<Entity extends object, Fields extends string = PopulatePath.ALL>(entityName: string, entities: Entity[], populate: PopulateOptions<Entity>[] | boolean, options: EntityLoaderOptions<Entity, Fields>): Promise<void>;
34
- normalizePopulate<Entity>(entityName: string, populate: (PopulateOptions<Entity> | boolean)[] | PopulateOptions<Entity> | boolean, strategy?: LoadStrategy, lookup?: boolean): PopulateOptions<Entity>[];
33
+ populate<Entity extends object, Fields extends string = PopulatePath.ALL>(entityName: EntityName<Entity>, entities: Entity[], populate: PopulateOptions<Entity>[] | boolean, options: EntityLoaderOptions<Entity, Fields>): Promise<void>;
34
+ normalizePopulate<Entity>(entityName: EntityName<Entity>, populate: (PopulateOptions<Entity> | boolean)[] | PopulateOptions<Entity> | boolean, strategy?: LoadStrategy, lookup?: boolean, exclude?: string[]): PopulateOptions<Entity>[];
35
35
  private setSerializationContext;
36
36
  /**
37
37
  * Merge multiple populates for the same entity with different children. Also skips `*` fields, those can come from
@@ -49,7 +49,8 @@ export declare class EntityLoader {
49
49
  private findChildren;
50
50
  private mergePrimaryCondition;
51
51
  private populateField;
52
- private findChildrenFromPivotTable;
52
+ /** @internal */
53
+ findChildrenFromPivotTable<Entity extends object>(filtered: Entity[], prop: EntityProperty<Entity>, options: Required<EntityLoaderOptions<Entity>>, orderBy?: QueryOrderMap<Entity>[], populate?: PopulateOptions<Entity>, pivotJoin?: boolean): Promise<AnyEntity[][]>;
53
54
  private extractChildCondition;
54
55
  private buildFields;
55
56
  private getChildReferences;
@@ -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
- populate = this.normalizePopulate(entityName, populate, options.strategy, options.lookup);
42
+ populate = this.normalizePopulate(entityName, populate, options.strategy, options.lookup, options.exclude);
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
  }
@@ -57,7 +56,7 @@ export class EntityLoader {
57
56
  visited.delete(entity);
58
57
  }
59
58
  }
60
- normalizePopulate(entityName, populate, strategy, lookup = true) {
59
+ normalizePopulate(entityName, populate, strategy, lookup = true, exclude) {
61
60
  const meta = this.metadata.find(entityName);
62
61
  let normalized = Utils.asArray(populate).map(field => {
63
62
  return typeof field === 'boolean' || field.field === PopulatePath.ALL ? { all: !!field, field: meta.primaryKeys[0] } : field;
@@ -68,7 +67,7 @@ export class EntityLoader {
68
67
  // convert nested `field` with dot syntax to PopulateOptions with `children` array
69
68
  expandDotPaths(meta, normalized, true);
70
69
  if (lookup && populate !== false) {
71
- normalized = this.lookupEagerLoadedRelationships(entityName, normalized, strategy);
70
+ normalized = this.lookupEagerLoadedRelationships(entityName, normalized, strategy, '', [], exclude);
72
71
  // convert nested `field` with dot syntax produced by eager relations
73
72
  expandDotPaths(meta, normalized, true);
74
73
  }
@@ -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,17 @@ 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
- let fk = Utils.getPrimaryKeyHash(meta.primaryKeys);
214
+ // When targetKey is set, use it for FK lookup instead of the PK
215
+ let fk = prop.targetKey ?? Utils.getPrimaryKeyHash(meta.primaryKeys);
211
216
  let schema = options.schema;
217
+ const partial = !Utils.isEmpty(prop.where) || !Utils.isEmpty(options.where);
212
218
  if (prop.kind === ReferenceKind.ONE_TO_MANY || (prop.kind === ReferenceKind.MANY_TO_MANY && !prop.owner)) {
213
219
  fk = meta.properties[prop.mappedBy].name;
214
220
  }
@@ -218,40 +224,31 @@ export class EntityLoader {
218
224
  children.push(...this.filterByReferences(entities, prop.name, options.refresh));
219
225
  }
220
226
  if (children.length === 0) {
221
- return [];
227
+ return { items: [], partial };
222
228
  }
223
229
  if (!schema && [ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(prop.kind)) {
224
230
  schema = children.find(e => e.__helper.__schema)?.__helper.__schema;
225
231
  }
226
- const ids = Utils.unique(children.map(e => e.__helper.getPrimaryKey()));
232
+ // When targetKey is set, get the targetKey value instead of PK
233
+ const ids = Utils.unique(children.map(e => prop.targetKey ? e[prop.targetKey] : e.__helper.getPrimaryKey()));
227
234
  let where = this.mergePrimaryCondition(ids, fk, options, meta, this.metadata, this.driver.getPlatform());
228
235
  const fields = this.buildFields(options.fields, prop, ref);
229
236
  /* eslint-disable prefer-const */
230
- let { refresh, filters, convertCustomTypes, lockMode, strategy, populateWhere, connectionType, logging, } = options;
237
+ let { refresh, filters, convertCustomTypes, lockMode, strategy, populateWhere = 'infer', connectionType, logging, } = options;
231
238
  /* eslint-enable prefer-const */
232
239
  if (typeof populateWhere === 'object') {
233
240
  populateWhere = await this.extractChildCondition({ where: populateWhere }, prop);
234
241
  }
235
- if (!Utils.isEmpty(prop.where)) {
242
+ if (!Utils.isEmpty(prop.where) || Raw.hasObjectFragments(prop.where)) {
236
243
  where = { $and: [where, prop.where] };
237
244
  }
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 items = await this.em.find(prop.type, where, {
245
+ const orderBy = [...Utils.asArray(options.orderBy), ...Utils.asArray(prop.orderBy)].filter((order, idx, array) => {
246
+ // skip consecutive ordering with the same key to get around mongo issues
247
+ return idx === 0 || !Utils.equals(Utils.getObjectQueryKeys(array[idx - 1]), Utils.getObjectQueryKeys(order));
248
+ });
249
+ const items = await this.em.find(meta.class, where, {
253
250
  filters, convertCustomTypes, lockMode, populateWhere, logging,
254
- orderBy: [...Utils.asArray(options.orderBy), ...propOrderBy],
251
+ orderBy,
255
252
  populate: populate.children ?? populate.all ?? [],
256
253
  exclude: Array.isArray(options.exclude) ? Utils.extractChildElements(options.exclude, prop.name) : options.exclude,
257
254
  strategy, fields, schema, connectionType,
@@ -260,6 +257,49 @@ export class EntityLoader {
260
257
  // @ts-ignore not a public option, will be propagated to the populate call
261
258
  visited: options.visited,
262
259
  });
260
+ // For targetKey relations, wire up loaded entities to parent references
261
+ // This is needed because the references were created under alternate key,
262
+ // but loaded entities are stored under PK, so they don't automatically merge
263
+ if (prop.targetKey && [ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(prop.kind)) {
264
+ const itemsByKey = new Map();
265
+ for (const item of items) {
266
+ itemsByKey.set('' + item[prop.targetKey], item);
267
+ }
268
+ for (const entity of entities) {
269
+ const ref = entity[prop.name];
270
+ /* v8 ignore next */
271
+ if (!ref) {
272
+ continue;
273
+ }
274
+ const keyValue = '' + (Reference.isReference(ref) ? ref.unwrap()[prop.targetKey] : ref[prop.targetKey]);
275
+ const loadedItem = itemsByKey.get(keyValue);
276
+ if (loadedItem) {
277
+ entity[prop.name] = (Reference.isReference(ref) ? Reference.create(loadedItem) : loadedItem);
278
+ }
279
+ }
280
+ }
281
+ if ([ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(prop.kind) && items.length !== children.length) {
282
+ const nullVal = this.em.config.get('forceUndefined') ? undefined : null;
283
+ const itemsMap = new Set();
284
+ const childrenMap = new Set();
285
+ // Use targetKey value if set, otherwise use serialized PK
286
+ const getKey = (e) => prop.targetKey ? '' + e[prop.targetKey] : helper(e).getSerializedPrimaryKey();
287
+ for (const item of items) {
288
+ /* v8 ignore next */
289
+ itemsMap.add(getKey(item));
290
+ }
291
+ for (const child of children) {
292
+ childrenMap.add(getKey(child));
293
+ }
294
+ for (const entity of entities) {
295
+ const ref = entity[prop.name] ?? {};
296
+ const key = helper(ref) ? getKey(ref) : undefined;
297
+ if (key && childrenMap.has(key) && !itemsMap.has(key)) {
298
+ entity[prop.name] = nullVal;
299
+ helper(entity).__originalEntityData[prop.name] = null;
300
+ }
301
+ }
302
+ }
263
303
  for (const item of items) {
264
304
  if (ref && !helper(item).__onLoadFired) {
265
305
  helper(item).__initialized = false;
@@ -267,10 +307,10 @@ export class EntityLoader {
267
307
  this.em.getUnitOfWork()['loadedEntities'].delete(item);
268
308
  }
269
309
  }
270
- return items;
310
+ return { items, partial };
271
311
  }
272
312
  mergePrimaryCondition(ids, pk, options, meta, metadata, platform) {
273
- const cond1 = QueryHelper.processWhere({ where: { [pk]: { $in: ids } }, entityName: meta.className, metadata, platform, convertCustomTypes: !options.convertCustomTypes });
313
+ const cond1 = QueryHelper.processWhere({ where: { [pk]: { $in: ids } }, entityName: meta.class, metadata, platform, convertCustomTypes: !options.convertCustomTypes });
274
314
  const where = { ...options.where };
275
315
  Utils.dropUndefinedProperties(where);
276
316
  return where[pk]
@@ -283,6 +323,7 @@ export class EntityLoader {
283
323
  if (prop.kind === ReferenceKind.SCALAR && !prop.lazy) {
284
324
  return;
285
325
  }
326
+ options = { ...options, filters: QueryHelper.mergePropertyFilters(prop.filters, options.filters) };
286
327
  const populated = await this.populateMany(entityName, entities, populate, options);
287
328
  if (!populate.children && !populate.all) {
288
329
  return;
@@ -310,10 +351,22 @@ export class EntityLoader {
310
351
  const innerOrderBy = Utils.asArray(options.orderBy)
311
352
  .filter(orderBy => Utils.isObject(orderBy[prop.name]))
312
353
  .map(orderBy => orderBy[prop.name]);
313
- const { refresh, filters, ignoreLazyScalarProperties, populateWhere, connectionType, logging } = options;
354
+ const { refresh, filters, ignoreLazyScalarProperties, populateWhere, connectionType, logging, schema } = options;
314
355
  const exclude = Array.isArray(options.exclude) ? Utils.extractChildElements(options.exclude, prop.name) : options.exclude;
315
- const filtered = Utils.unique(children.filter(e => !options.visited.has(e)));
316
- await this.populate(prop.type, filtered, populate.children ?? populate.all, {
356
+ const visited = options.visited;
357
+ for (const entity of entities) {
358
+ visited.delete(entity);
359
+ }
360
+ const unique = Utils.unique(children);
361
+ const filtered = unique.filter(e => !visited.has(e));
362
+ for (const entity of entities) {
363
+ visited.add(entity);
364
+ }
365
+ // skip lazy scalar properties
366
+ if (!prop.targetMeta) {
367
+ return;
368
+ }
369
+ await this.populate(prop.targetMeta.class, unique, populate.children ?? populate.all, {
317
370
  where: await this.extractChildCondition(options, prop, false),
318
371
  orderBy: innerOrderBy,
319
372
  fields,
@@ -325,12 +378,16 @@ export class EntityLoader {
325
378
  populateWhere,
326
379
  connectionType,
327
380
  logging,
381
+ schema,
328
382
  // @ts-ignore not a public option, will be propagated to the populate call
329
383
  refresh: refresh && !filtered.every(item => options.visited.has(item)),
330
384
  // @ts-ignore not a public option, will be propagated to the populate call
331
385
  visited: options.visited,
386
+ // @ts-ignore not a public option
387
+ filtered,
332
388
  });
333
389
  }
390
+ /** @internal */
334
391
  async findChildrenFromPivotTable(filtered, prop, options, orderBy, populate, pivotJoin) {
335
392
  const ids = filtered.map(e => e.__helper.__primaryKeys);
336
393
  const refresh = options.refresh;
@@ -354,12 +411,12 @@ export class EntityLoader {
354
411
  for (const entity of filtered) {
355
412
  const items = map[entity.__helper.getSerializedPrimaryKey()].map(item => {
356
413
  if (pivotJoin) {
357
- return this.em.getReference(prop.type, item, {
414
+ return this.em.getReference(prop.targetMeta.class, item, {
358
415
  convertCustomTypes: true,
359
416
  schema: options.schema ?? this.em.config.get('schema'),
360
417
  });
361
418
  }
362
- const entity = this.em.getEntityFactory().create(prop.type, item, {
419
+ const entity = this.em.getEntityFactory().create(prop.targetMeta.class, item, {
363
420
  refresh,
364
421
  merge: true,
365
422
  convertCustomTypes: true,
@@ -368,23 +425,20 @@ export class EntityLoader {
368
425
  return this.em.getUnitOfWork().register(entity, item, { refresh, loaded: true });
369
426
  });
370
427
  entity[prop.name].hydrate(items, true);
371
- children.push(...items);
428
+ children.push(items);
372
429
  }
373
430
  return children;
374
431
  }
375
432
  async extractChildCondition(options, prop, filters = false) {
376
433
  const where = options.where;
377
434
  const subCond = Utils.isPlainObject(where[prop.name]) ? where[prop.name] : {};
378
- const meta2 = this.metadata.find(prop.type);
379
- if (!meta2) {
380
- return {};
381
- }
435
+ const meta2 = prop.targetMeta;
382
436
  const pk = Utils.getPrimaryKeyHash(meta2.primaryKeys);
383
437
  ['$and', '$or'].forEach(op => {
384
438
  if (where[op]) {
385
439
  const child = where[op]
386
440
  .map((cond) => cond[prop.name])
387
- .filter((sub) => sub != null && !(Utils.isPlainObject(sub) && Object.keys(sub).every(key => Utils.isOperator(key, false))))
441
+ .filter((sub) => sub != null && !(Utils.isPlainObject(sub) && Utils.getObjectQueryKeys(sub).every(key => Utils.isOperator(key, false))))
388
442
  .map((cond) => {
389
443
  if (Utils.isPrimaryKey(cond)) {
390
444
  return { [pk]: cond };
@@ -405,7 +459,7 @@ export class EntityLoader {
405
459
  });
406
460
  }
407
461
  if (filters) {
408
- return this.em.applyFilters(prop.type, subCond, options.filters, 'read', options);
462
+ return this.em.applyFilters(meta2.class, subCond, options.filters, 'read', options);
409
463
  }
410
464
  return subCond;
411
465
  }
@@ -423,7 +477,7 @@ export class EntityLoader {
423
477
  const parts = f.toString().split('.');
424
478
  const propName = parts.shift();
425
479
  const childPropName = parts.join('.');
426
- /* v8 ignore next 3 */
480
+ /* v8 ignore next */
427
481
  if (propName === prop.name) {
428
482
  ret.push(childPropName);
429
483
  }
@@ -444,23 +498,20 @@ export class EntityLoader {
444
498
  }
445
499
  getChildReferences(entities, prop, options, ref) {
446
500
  const filtered = this.filterCollections(entities, prop.name, options, ref);
447
- const children = [];
448
501
  if (prop.kind === ReferenceKind.ONE_TO_MANY) {
449
- children.push(...filtered.map(e => e[prop.name].owner));
502
+ return filtered.map(e => e[prop.name].owner);
450
503
  }
451
- else if (prop.kind === ReferenceKind.MANY_TO_MANY && prop.owner) {
452
- children.push(...filtered.reduce((a, b) => {
504
+ if (prop.kind === ReferenceKind.MANY_TO_MANY && prop.owner) {
505
+ return filtered.reduce((a, b) => {
453
506
  a.push(...b[prop.name].getItems());
454
507
  return a;
455
- }, []));
508
+ }, []);
456
509
  }
457
- else if (prop.kind === ReferenceKind.MANY_TO_MANY) { // inverse side
458
- children.push(...filtered);
510
+ if (prop.kind === ReferenceKind.MANY_TO_MANY) { // inverse side
511
+ return filtered;
459
512
  }
460
- else { // MANY_TO_ONE or ONE_TO_ONE
461
- children.push(...this.filterReferences(entities, prop.name, options, ref));
462
- }
463
- return children;
513
+ // MANY_TO_ONE or ONE_TO_ONE
514
+ return this.filterReferences(entities, prop.name, options, ref);
464
515
  }
465
516
  filterCollections(entities, field, options, ref) {
466
517
  if (options.refresh) {
@@ -477,7 +528,7 @@ export class EntityLoader {
477
528
  return wrapped.__loadedProperties.has(field);
478
529
  }
479
530
  const [f, ...r] = field.split('.');
480
- /* v8 ignore next 3 */
531
+ /* v8 ignore next */
481
532
  if (!wrapped.__loadedProperties.has(f) || !wrapped.__meta.properties[f]?.targetMeta) {
482
533
  return false;
483
534
  }
@@ -510,11 +561,11 @@ export class EntityLoader {
510
561
  .map(e => Reference.unwrapReference(e[field]));
511
562
  }
512
563
  filterByReferences(entities, field, refresh) {
513
- /* v8 ignore next 3 */
564
+ /* v8 ignore next */
514
565
  if (refresh) {
515
566
  return entities;
516
567
  }
517
- return entities.filter(e => !e[field]?.__helper?.__initialized);
568
+ return entities.filter(e => e[field] !== null && !e[field]?.__helper?.__initialized);
518
569
  }
519
570
  lookupAllRelationships(entityName) {
520
571
  const ret = [];
@@ -536,33 +587,36 @@ export class EntityLoader {
536
587
  }
537
588
  return `${this.getRelationName(meta, meta.properties[prop.embedded[0]])}.${prop.embedded[1]}`;
538
589
  }
539
- lookupEagerLoadedRelationships(entityName, populate, strategy, prefix = '', visited = []) {
590
+ lookupEagerLoadedRelationships(entityName, populate, strategy, prefix = '', visited = [], exclude) {
540
591
  const meta = this.metadata.find(entityName);
541
592
  if (!meta && !prefix) {
542
593
  return populate;
543
594
  }
544
- if (visited.includes(entityName) || !meta) {
595
+ if (!meta || visited.includes(meta)) {
545
596
  return [];
546
597
  }
547
- visited.push(entityName);
598
+ visited.push(meta);
548
599
  const ret = prefix === '' ? [...populate] : [];
549
600
  meta.relations
550
601
  .filter(prop => {
602
+ const field = this.getRelationName(meta, prop);
603
+ const prefixed = prefix ? `${prefix}.${field}` : field;
604
+ const isExcluded = exclude?.includes(prefixed);
551
605
  const eager = prop.eager && !populate.some(p => p.field === `${prop.name}:ref`);
552
606
  const populated = populate.some(p => p.field === prop.name);
553
607
  const disabled = populate.some(p => p.field === prop.name && p.all === false);
554
- return !disabled && (eager || populated);
608
+ return !disabled && !isExcluded && (eager || populated);
555
609
  })
556
610
  .forEach(prop => {
557
611
  const field = this.getRelationName(meta, prop);
558
612
  const prefixed = prefix ? `${prefix}.${field}` : field;
559
613
  const nestedPopulate = populate.filter(p => p.field === prop.name).flatMap(p => p.children).filter(Boolean);
560
- const nested = this.lookupEagerLoadedRelationships(prop.type, nestedPopulate, strategy, prefixed, visited.slice());
614
+ const nested = this.lookupEagerLoadedRelationships(prop.targetMeta.class, nestedPopulate, strategy, prefixed, visited.slice(), exclude);
561
615
  if (nested.length > 0) {
562
616
  ret.push(...nested);
563
617
  }
564
618
  else {
565
- const selfReferencing = [meta.className, meta.root.className, ...visited].includes(prop.type) && prop.eager;
619
+ const selfReferencing = [meta.tableName, ...visited.map(m => m.tableName)].includes(prop.targetMeta.tableName) && prop.eager;
566
620
  ret.push({
567
621
  field: prefixed,
568
622
  // 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
  */
@@ -107,10 +111,26 @@ export declare class EntityRepository<Entity extends object> {
107
111
  map(result: EntityDictionary<Entity>, options?: {
108
112
  schema?: string;
109
113
  }): Entity;
114
+ /**
115
+ * Gets a reference to the entity identified by the given type and alternate key property without actually loading it.
116
+ * The key option specifies which property to use for identity map lookup instead of the primary key.
117
+ */
118
+ getReference<K extends string & keyof Entity>(id: Entity[K], options: Omit<GetReferenceOptions, 'key' | 'wrapped'> & {
119
+ key: K;
120
+ wrapped: true;
121
+ }): Ref<Entity>;
122
+ /**
123
+ * Gets a reference to the entity identified by the given type and alternate key property without actually loading it.
124
+ * The key option specifies which property to use for identity map lookup instead of the primary key.
125
+ */
126
+ getReference<K extends string & keyof Entity>(id: Entity[K], options: Omit<GetReferenceOptions, 'key'> & {
127
+ key: K;
128
+ wrapped?: false;
129
+ }): Entity;
110
130
  /**
111
131
  * Gets a reference to the entity identified by the given type and identifier without actually loading it, if the entity is not yet loaded
112
132
  */
113
- getReference(id: Primary<Entity>, options: Omit<GetReferenceOptions, 'wrapped'> & {
133
+ getReference(id: Primary<Entity>, options: Omit<GetReferenceOptions, 'wrapped' | 'key'> & {
114
134
  wrapped: true;
115
135
  }): Ref<Entity>;
116
136
  /**
@@ -120,7 +140,7 @@ export declare class EntityRepository<Entity extends object> {
120
140
  /**
121
141
  * Gets a reference to the entity identified by the given type and identifier without actually loading it, if the entity is not yet loaded
122
142
  */
123
- getReference(id: Primary<Entity>, options: Omit<GetReferenceOptions, 'wrapped'> & {
143
+ getReference(id: Primary<Entity>, options: Omit<GetReferenceOptions, 'wrapped' | 'key'> & {
124
144
  wrapped: false;
125
145
  }): Entity;
126
146
  /**
@@ -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
- import type { AddEager, Dictionary, EntityClass, EntityKey, EntityProperty, Loaded, LoadedReference, Primary, Ref } from '../typings.js';
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;
@@ -72,15 +73,11 @@ export interface LoadReferenceOrFailOptions<T extends object, P extends string =
72
73
  /**
73
74
  * shortcut for `wrap(entity).toReference()`
74
75
  */
75
- export declare function ref<T>(entity: T | Ref<T>): Ref<T> & LoadedReference<Loaded<T, AddEager<T>>>;
76
+ export declare function ref<I extends unknown | Ref<unknown> | undefined | null, T extends I & {}>(entity: I): Ref<T> & LoadedReference<Loaded<T, AddEager<T>>> | AddOptional<typeof entity>;
76
77
  /**
77
78
  * shortcut for `Reference.createFromPK(entityType, pk)`
78
79
  */
79
- export declare function ref<T, PKV extends Primary<T> = Primary<T>>(entityType: EntityClass<T>, pk?: T | PKV): Ref<T>;
80
- /**
81
- * shortcut for `wrap(entity).toReference()`
82
- */
83
- export declare function ref<T>(value: T | Ref<T>): Ref<T> & LoadedReference<Loaded<T, AddEager<T>>>;
80
+ export declare function ref<I extends unknown | undefined | null, T, PKV extends Primary<T> = Primary<T>>(entityType: EntityClass<T>, pk: I): Ref<T> | AddOptional<typeof pk>;
84
81
  /**
85
82
  * shortcut for `Reference.createNakedFromPK(entityType, pk)`
86
83
  */