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

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 (59) hide show
  1. package/EntityManager.d.ts +13 -5
  2. package/EntityManager.js +60 -40
  3. package/MikroORM.js +2 -2
  4. package/cache/FileCacheAdapter.js +2 -2
  5. package/decorators/Check.d.ts +2 -2
  6. package/decorators/CreateRequestContext.js +4 -1
  7. package/decorators/Embeddable.d.ts +5 -5
  8. package/decorators/Embeddable.js +1 -1
  9. package/decorators/Embedded.d.ts +6 -12
  10. package/decorators/Entity.d.ts +5 -5
  11. package/decorators/Entity.js +0 -1
  12. package/decorators/Enum.d.ts +1 -1
  13. package/decorators/Formula.d.ts +1 -2
  14. package/decorators/Indexed.d.ts +9 -7
  15. package/decorators/Indexed.js +1 -1
  16. package/decorators/ManyToMany.d.ts +2 -2
  17. package/decorators/ManyToOne.d.ts +4 -2
  18. package/decorators/OneToMany.d.ts +4 -4
  19. package/decorators/OneToOne.d.ts +3 -1
  20. package/decorators/PrimaryKey.d.ts +2 -3
  21. package/decorators/Property.d.ts +1 -1
  22. package/drivers/IDatabaseDriver.d.ts +4 -1
  23. package/entity/ArrayCollection.d.ts +1 -1
  24. package/entity/ArrayCollection.js +11 -4
  25. package/entity/Collection.d.ts +1 -2
  26. package/entity/Collection.js +14 -9
  27. package/entity/EntityFactory.js +4 -1
  28. package/entity/EntityHelper.js +3 -0
  29. package/entity/EntityLoader.d.ts +3 -2
  30. package/entity/EntityLoader.js +20 -6
  31. package/entity/Reference.d.ts +3 -7
  32. package/enums.d.ts +1 -1
  33. package/events/EventSubscriber.d.ts +3 -1
  34. package/exports.d.ts +24 -0
  35. package/exports.js +23 -0
  36. package/hydration/ObjectHydrator.js +1 -0
  37. package/index.d.ts +1 -1
  38. package/metadata/EntitySchema.d.ts +6 -4
  39. package/metadata/EntitySchema.js +23 -17
  40. package/metadata/MetadataDiscovery.js +25 -12
  41. package/metadata/MetadataValidator.js +4 -3
  42. package/package.json +7 -6
  43. package/types/BigIntType.d.ts +1 -0
  44. package/types/BigIntType.js +3 -0
  45. package/typings.d.ts +17 -10
  46. package/typings.js +3 -0
  47. package/unit-of-work/ChangeSetPersister.js +7 -1
  48. package/unit-of-work/UnitOfWork.js +25 -9
  49. package/utils/AbstractSchemaGenerator.js +5 -2
  50. package/utils/Configuration.d.ts +1 -1
  51. package/utils/Configuration.js +1 -1
  52. package/utils/Cursor.d.ts +3 -3
  53. package/utils/DataloaderUtils.d.ts +1 -1
  54. package/utils/DataloaderUtils.js +19 -5
  55. package/utils/EntityComparator.js +65 -49
  56. package/utils/QueryHelper.js +1 -1
  57. package/utils/RawQueryFragment.js +6 -1
  58. package/utils/Utils.d.ts +8 -2
  59. package/utils/Utils.js +26 -6
@@ -6,7 +6,7 @@ import { EntityFactory } from './entity/EntityFactory.js';
6
6
  import { type AssignOptions } from './entity/EntityAssigner.js';
7
7
  import { EntityValidator } from './entity/EntityValidator.js';
8
8
  import { type EntityRepository } from './entity/EntityRepository.js';
9
- import { type EntityLoaderOptions } from './entity/EntityLoader.js';
9
+ import { EntityLoader, type EntityLoaderOptions } from './entity/EntityLoader.js';
10
10
  import { Reference } from './entity/Reference.js';
11
11
  import { UnitOfWork } from './unit-of-work/UnitOfWork.js';
12
12
  import type { CountOptions, DeleteOptions, FindAllOptions, FindByCursorOptions, FindOneOptions, FindOneOrFailOptions, FindOptions, GetReferenceOptions, IDatabaseDriver, LockOptions, NativeInsertUpdateOptions, UpdateOptions, UpsertManyOptions, UpsertOptions } from './drivers/IDatabaseDriver.js';
@@ -171,6 +171,10 @@ export declare class EntityManager<Driver extends IDatabaseDriver = IDatabaseDri
171
171
  * });
172
172
  * ```
173
173
  *
174
+ * The options also support an `includeCount` (true by default) option. If set to false, the `totalCount` is not
175
+ * returned as part of the cursor. This is useful for performance reason, when you don't care about the total number
176
+ * of pages.
177
+ *
174
178
  * The `Cursor` object provides the following interface:
175
179
  *
176
180
  * ```ts
@@ -180,7 +184,7 @@ export declare class EntityManager<Driver extends IDatabaseDriver = IDatabaseDri
180
184
  * User { ... },
181
185
  * User { ... },
182
186
  * ],
183
- * totalCount: 50,
187
+ * totalCount: 50, // not included if `includeCount: false`
184
188
  * startCursor: 'WzRd',
185
189
  * endCursor: 'WzZd',
186
190
  * hasPrevPage: true,
@@ -188,7 +192,7 @@ export declare class EntityManager<Driver extends IDatabaseDriver = IDatabaseDri
188
192
  * }
189
193
  * ```
190
194
  */
191
- findByCursor<Entity extends object, Hint extends string = never, Fields extends string = '*', Excludes extends string = never>(entityName: EntityName<Entity>, where: FilterQuery<NoInfer<Entity>>, options: FindByCursorOptions<Entity, Hint, Fields, Excludes>): Promise<Cursor<Entity, Hint, Fields, Excludes>>;
195
+ findByCursor<Entity extends object, Hint extends string = never, Fields extends string = '*', Excludes extends string = never, IncludeCount extends boolean = true>(entityName: EntityName<Entity>, where: FilterQuery<NoInfer<Entity>>, options: FindByCursorOptions<Entity, Hint, Fields, Excludes, IncludeCount>): Promise<Cursor<Entity, Hint, Fields, Excludes, IncludeCount>>;
192
196
  /**
193
197
  * Refreshes the persistent state of an entity from the database, overriding any local changes that have not yet been
194
198
  * persisted. Returns the same entity instance (same object reference), but re-hydrated. If the entity is no longer
@@ -419,7 +423,7 @@ export declare class EntityManager<Driver extends IDatabaseDriver = IDatabaseDri
419
423
  /**
420
424
  * Loads specified relations in batch. This will execute one query for each relation, that will populate it on all the specified entities.
421
425
  */
422
- populate<Entity extends object, Naked extends FromEntityType<UnboxArray<Entity>> = FromEntityType<UnboxArray<Entity>>, Hint extends string = never, Fields extends string = '*', Excludes extends string = never>(entities: Entity, populate: AutoPath<Naked, Hint, PopulatePath.ALL>[] | false, options?: EntityLoaderOptions<Naked, Fields, Excludes>): Promise<Entity extends object[] ? MergeLoaded<ArrayElement<Entity>, Naked, Hint, Fields, Excludes>[] : MergeLoaded<Entity, Naked, Hint, Fields, Excludes>>;
426
+ populate<Entity extends object, Naked extends FromEntityType<UnboxArray<Entity>> = FromEntityType<UnboxArray<Entity>>, Hint extends string = never, Fields extends string = '*', Excludes extends string = never>(entities: Entity, populate: readonly AutoPath<Naked, Hint, PopulatePath.ALL>[] | false, options?: EntityLoaderOptions<Naked, Fields, Excludes>): Promise<Entity extends object[] ? MergeLoaded<ArrayElement<Entity>, Naked, Hint, Fields, Excludes>[] : MergeLoaded<Entity, Naked, Hint, Fields, Excludes>>;
423
427
  /**
424
428
  * Returns new EntityManager instance with its own identity map
425
429
  */
@@ -432,6 +436,10 @@ export declare class EntityManager<Driver extends IDatabaseDriver = IDatabaseDri
432
436
  * Gets the EntityFactory used by the EntityManager.
433
437
  */
434
438
  getEntityFactory(): EntityFactory;
439
+ /**
440
+ * @internal use `em.populate()` as the user facing API, this is exposed only for internal usage
441
+ */
442
+ getEntityLoader(): EntityLoader;
435
443
  /**
436
444
  * Gets the Hydrator used by the EntityManager.
437
445
  */
@@ -488,7 +496,7 @@ export declare class EntityManager<Driver extends IDatabaseDriver = IDatabaseDri
488
496
  * @internal
489
497
  */
490
498
  tryCache<T extends object, R>(entityName: string, config: boolean | number | [string, number] | undefined, key: unknown, refresh?: boolean, merge?: boolean): Promise<{
491
- data?: R;
499
+ data?: R | null;
492
500
  key: string;
493
501
  } | undefined>;
494
502
  /**
package/EntityManager.js CHANGED
@@ -149,7 +149,7 @@ export class EntityManager {
149
149
  options._populateWhere = options.populateWhere ?? this.config.get('populateWhere');
150
150
  options.populateWhere = this.createPopulateWhere({ ...where }, options);
151
151
  options.populateFilter = await this.getJoinedFilters(meta, { ...where }, options);
152
- const results = await em.driver.find(entityName, where, { ctx: em.transactionContext, ...options });
152
+ const results = await em.driver.find(entityName, where, { ctx: em.transactionContext, em, ...options });
153
153
  if (results.length === 0) {
154
154
  await em.storeCache(options.cache, cached, []);
155
155
  return [];
@@ -250,7 +250,7 @@ export class EntityManager {
250
250
  aliased: type === 'read',
251
251
  });
252
252
  where = (await this.applyFilters(entityName, where, options.filters ?? {}, type, options));
253
- where = await this.applyDiscriminatorCondition(entityName, where);
253
+ where = this.applyDiscriminatorCondition(entityName, where);
254
254
  return where;
255
255
  }
256
256
  // this method only handles the problem for mongo driver, SQL drivers have their implementation inside QueryBuilder
@@ -367,7 +367,7 @@ export class EntityManager {
367
367
  if (!args && filter.cond.length > 0 && filter.args !== false) {
368
368
  throw new Error(`No arguments provided for filter '${filter.name}'`);
369
369
  }
370
- cond = await filter.cond(args, type, this, findOptions);
370
+ cond = await filter.cond(args, type, this, findOptions, entityName);
371
371
  }
372
372
  else {
373
373
  cond = filter.cond;
@@ -433,6 +433,10 @@ export class EntityManager {
433
433
  * });
434
434
  * ```
435
435
  *
436
+ * The options also support an `includeCount` (true by default) option. If set to false, the `totalCount` is not
437
+ * returned as part of the cursor. This is useful for performance reason, when you don't care about the total number
438
+ * of pages.
439
+ *
436
440
  * The `Cursor` object provides the following interface:
437
441
  *
438
442
  * ```ts
@@ -442,7 +446,7 @@ export class EntityManager {
442
446
  * User { ... },
443
447
  * User { ... },
444
448
  * ],
445
- * totalCount: 50,
449
+ * totalCount: 50, // not included if `includeCount: false`
446
450
  * startCursor: 'WzRd',
447
451
  * endCursor: 'WzZd',
448
452
  * hasPrevPage: true,
@@ -457,7 +461,9 @@ export class EntityManager {
457
461
  if (Utils.isEmpty(options.orderBy)) {
458
462
  throw new Error('Explicit `orderBy` option required');
459
463
  }
460
- const [entities, count] = await em.findAndCount(entityName, where, options);
464
+ const [entities, count] = options.includeCount !== false
465
+ ? await em.findAndCount(entityName, where, options)
466
+ : [await em.find(entityName, where, options)];
461
467
  return new Cursor(entities, count, options, this.metadata.get(entityName));
462
468
  }
463
469
  /**
@@ -530,14 +536,16 @@ export class EntityManager {
530
536
  options.populate = await em.preparePopulate(entityName, options);
531
537
  const cacheKey = em.cacheKey(entityName, options, 'em.findOne', where);
532
538
  const cached = await em.tryCache(entityName, options.cache, cacheKey, options.refresh, true);
533
- if (cached?.data) {
534
- await em.entityLoader.populate(entityName, [cached.data], options.populate, {
535
- ...options,
536
- ...em.getPopulateWhere(where, options),
537
- convertCustomTypes: false,
538
- ignoreLazyScalarProperties: true,
539
- lookup: false,
540
- });
539
+ if (cached?.data !== undefined) {
540
+ if (cached.data) {
541
+ await em.entityLoader.populate(entityName, [cached.data], options.populate, {
542
+ ...options,
543
+ ...em.getPopulateWhere(where, options),
544
+ convertCustomTypes: false,
545
+ ignoreLazyScalarProperties: true,
546
+ lookup: false,
547
+ });
548
+ }
541
549
  return cached.data;
542
550
  }
543
551
  options = { ...options };
@@ -547,6 +555,7 @@ export class EntityManager {
547
555
  options.populateFilter = await this.getJoinedFilters(meta, { ...where }, options);
548
556
  const data = await em.driver.findOne(entityName, where, {
549
557
  ctx: em.transactionContext,
558
+ em,
550
559
  ...options,
551
560
  });
552
561
  if (!data) {
@@ -716,8 +725,9 @@ export class EntityManager {
716
725
  ctx: em.transactionContext,
717
726
  convertCustomTypes: true,
718
727
  connectionType: 'write',
728
+ schema: options.schema,
719
729
  });
720
- em.getHydrator().hydrate(entity, meta, data2, em.entityFactory, 'full');
730
+ em.getHydrator().hydrate(entity, meta, data2, em.entityFactory, 'full', false, true);
721
731
  }
722
732
  // recompute the data as there might be some values missing (e.g. those with db column defaults)
723
733
  const snapshot = this.comparator.prepareEntity(entity);
@@ -896,6 +906,7 @@ export class EntityManager {
896
906
  ctx: em.transactionContext,
897
907
  convertCustomTypes: true,
898
908
  connectionType: 'write',
909
+ schema: options.schema,
899
910
  });
900
911
  for (const [entity, cond] of loadPK.entries()) {
901
912
  const row = data2.find(row => {
@@ -911,7 +922,7 @@ export class EntityManager {
911
922
  if (!row) {
912
923
  throw new Error(`Cannot find matching entity for condition ${JSON.stringify(cond)}`);
913
924
  }
914
- em.getHydrator().hydrate(entity, meta, row, em.entityFactory, 'full');
925
+ em.getHydrator().hydrate(entity, meta, row, em.entityFactory, 'full', false, true);
915
926
  }
916
927
  if (loadPK.size !== data2.length && Array.isArray(uniqueFields)) {
917
928
  for (let i = 0; i < allData.length; i++) {
@@ -1266,7 +1277,7 @@ export class EntityManager {
1266
1277
  delete options.orderBy;
1267
1278
  const cacheKey = em.cacheKey(entityName, options, 'em.count', where);
1268
1279
  const cached = await em.tryCache(entityName, options.cache, cacheKey);
1269
- if (cached?.data) {
1280
+ if (cached?.data !== undefined) {
1270
1281
  return cached.data;
1271
1282
  }
1272
1283
  const count = await em.driver.count(entityName, where, { ctx: em.transactionContext, ...options });
@@ -1431,6 +1442,9 @@ export class EntityManager {
1431
1442
  for (const entity of em.unitOfWork.getIdentityMap()) {
1432
1443
  fork.unitOfWork.register(entity);
1433
1444
  }
1445
+ for (const entity of em.unitOfWork.getPersistStack()) {
1446
+ fork.unitOfWork.persist(entity);
1447
+ }
1434
1448
  for (const entity of em.unitOfWork.getOrphanRemoveStack()) {
1435
1449
  fork.unitOfWork.getOrphanRemoveStack().add(entity);
1436
1450
  }
@@ -1452,6 +1466,12 @@ export class EntityManager {
1452
1466
  getEntityFactory() {
1453
1467
  return this.getContext().entityFactory;
1454
1468
  }
1469
+ /**
1470
+ * @internal use `em.populate()` as the user facing API, this is exposed only for internal usage
1471
+ */
1472
+ getEntityLoader() {
1473
+ return this.getContext().entityLoader;
1474
+ }
1455
1475
  /**
1456
1476
  * Gets the Hydrator used by the EntityManager.
1457
1477
  */
@@ -1695,31 +1715,31 @@ export class EntityManager {
1695
1715
  const em = this.getContext();
1696
1716
  const cacheKey = Array.isArray(config) ? config[0] : JSON.stringify(key);
1697
1717
  const cached = await em.resultCache.get(cacheKey);
1698
- if (cached) {
1699
- let data;
1700
- if (Array.isArray(cached) && merge) {
1701
- data = cached.map(item => em.entityFactory.create(entityName, item, {
1702
- merge: true,
1703
- convertCustomTypes: true,
1704
- refresh,
1705
- recomputeSnapshot: true,
1706
- }));
1707
- }
1708
- else if (Utils.isObject(cached) && merge) {
1709
- data = em.entityFactory.create(entityName, cached, {
1710
- merge: true,
1711
- convertCustomTypes: true,
1712
- refresh,
1713
- recomputeSnapshot: true,
1714
- });
1715
- }
1716
- else {
1717
- data = cached;
1718
- }
1719
- await em.unitOfWork.dispatchOnLoadEvent();
1720
- return { key: cacheKey, data };
1718
+ if (!cached) {
1719
+ return { key: cacheKey, data: cached };
1720
+ }
1721
+ let data;
1722
+ if (Array.isArray(cached) && merge) {
1723
+ data = cached.map(item => em.entityFactory.create(entityName, item, {
1724
+ merge: true,
1725
+ convertCustomTypes: true,
1726
+ refresh,
1727
+ recomputeSnapshot: true,
1728
+ }));
1729
+ }
1730
+ else if (Utils.isObject(cached) && merge) {
1731
+ data = em.entityFactory.create(entityName, cached, {
1732
+ merge: true,
1733
+ convertCustomTypes: true,
1734
+ refresh,
1735
+ recomputeSnapshot: true,
1736
+ });
1737
+ }
1738
+ else {
1739
+ data = cached;
1721
1740
  }
1722
- return { key: cacheKey };
1741
+ await em.unitOfWork.dispatchOnLoadEvent();
1742
+ return { key: cacheKey, data };
1723
1743
  }
1724
1744
  /**
1725
1745
  * @internal
package/MikroORM.js CHANGED
@@ -24,7 +24,7 @@ export class MikroORM {
24
24
  */
25
25
  static async init(options) {
26
26
  ConfigurationLoader.registerDotenv(options);
27
- const coreVersion = await ConfigurationLoader.checkPackageVersion();
27
+ const coreVersion = ConfigurationLoader.checkPackageVersion();
28
28
  const env = await ConfigurationLoader.loadEnvironmentVars();
29
29
  if (!options) {
30
30
  const configPathFromArg = ConfigurationLoader.configPathsFromArg();
@@ -35,7 +35,7 @@ export class MikroORM {
35
35
  }
36
36
  }
37
37
  options = Utils.mergeConfig(options, env);
38
- await ConfigurationLoader.commonJSCompat(options);
38
+ ConfigurationLoader.commonJSCompat(options);
39
39
  if ('DRIVER' in this && !options.driver) {
40
40
  options.driver = this.DRIVER;
41
41
  }
@@ -1,4 +1,4 @@
1
- import globby from 'globby';
1
+ import { globSync } from 'tinyglobby';
2
2
  import { existsSync, readFileSync, writeFileSync, unlinkSync } from 'node:fs';
3
3
  import { Utils } from '../utils/Utils.js';
4
4
  export class FileCacheAdapter {
@@ -51,7 +51,7 @@ export class FileCacheAdapter {
51
51
  */
52
52
  clear() {
53
53
  const path = this.path('*');
54
- const files = globby.sync(path);
54
+ const files = globSync(path);
55
55
  files.forEach(file => unlinkSync(file));
56
56
  this.cache = {};
57
57
  }
@@ -1,3 +1,3 @@
1
- import type { CheckConstraint } from '../typings.js';
2
- export declare function Check<T>(options: CheckOptions<T>): (target: any, propertyName?: string) => any;
1
+ import type { CheckConstraint, EntityClass } from '../typings.js';
2
+ export declare function Check<T>(options: CheckOptions<T>): (target: T, propertyName?: T extends EntityClass<unknown> ? undefined : keyof T) => any;
3
3
  export type CheckOptions<T = any> = CheckConstraint<T>;
@@ -4,10 +4,13 @@ import { TransactionContext } from '../utils/TransactionContext.js';
4
4
  export function CreateRequestContext(context, respectExistingContext = false) {
5
5
  return function (target, propertyKey, descriptor) {
6
6
  const originalMethod = descriptor.value;
7
+ const name = respectExistingContext ? 'EnsureRequestContext' : 'CreateRequestContext';
8
+ if (originalMethod.constructor.name !== 'AsyncFunction') {
9
+ throw new Error(`@${name}() should be use with async functions`);
10
+ }
7
11
  descriptor.value = async function (...args) {
8
12
  const em = await resolveContextProvider(this, context);
9
13
  if (!em) {
10
- const name = respectExistingContext ? 'EnsureRequestContext' : 'CreateRequestContext';
11
14
  throw new Error(`@${name}() decorator can only be applied to methods of classes with \`orm: MikroORM\` property, \`em: EntityManager\` property, or with a callback parameter like \`@${name}(() => orm)\` that returns one of those types. The parameter will contain a reference to current \`this\`. Returning an EntityRepository from it is also supported.`);
12
15
  }
13
16
  // reuse existing context if available for given respect `contextName`
@@ -1,8 +1,8 @@
1
- import type { Dictionary } from '../typings.js';
2
- export declare function Embeddable(options?: EmbeddableOptions): <T>(target: T & Dictionary) => T & Dictionary;
3
- export type EmbeddableOptions = {
4
- discriminatorColumn?: string;
1
+ import type { AnyString, Dictionary, EntityClass } from '../typings.js';
2
+ export declare function Embeddable<T>(options?: EmbeddableOptions<T>): (target: T) => T;
3
+ export interface EmbeddableOptions<T> {
4
+ discriminatorColumn?: (T extends EntityClass<infer P> ? keyof P : string) | AnyString;
5
5
  discriminatorMap?: Dictionary<string>;
6
6
  discriminatorValue?: number | string;
7
7
  abstract?: boolean;
8
- };
8
+ }
@@ -3,7 +3,7 @@ export function Embeddable(options = {}) {
3
3
  return function (target) {
4
4
  const meta = MetadataStorage.getMetadataFromDecorator(target);
5
5
  meta.class = target;
6
- meta.name = target.name;
6
+ meta.name = meta.class.name;
7
7
  meta.embeddable = true;
8
8
  Object.assign(meta, options);
9
9
  return target;
@@ -1,18 +1,12 @@
1
- import type { AnyEntity } from '../typings.js';
2
- export declare function Embedded<T extends object>(type?: EmbeddedOptions | (() => AnyEntity), options?: EmbeddedOptions): (target: AnyEntity, propertyName: string) => any;
1
+ import type { AnyEntity, EntityName } from '../typings.js';
2
+ import type { PropertyOptions } from './Property.js';
3
+ export declare function Embedded<Owner extends object, Target>(type?: EmbeddedOptions<Owner, Target> | (() => EntityName<Target> | EntityName<Target>[]), options?: EmbeddedOptions<Owner, Target>): (target: AnyEntity, propertyName: string) => any;
3
4
  /** With `absolute` the prefix is set at the root of the entity (regardless of the nesting level) */
4
5
  export type EmbeddedPrefixMode = 'absolute' | 'relative';
5
- export type EmbeddedOptions = {
6
- entity?: string | (() => AnyEntity | AnyEntity[]);
7
- type?: string;
6
+ export interface EmbeddedOptions<Owner, Target> extends PropertyOptions<Owner> {
7
+ entity?: string | (() => EntityName<Target> | EntityName<Target>[]);
8
8
  prefix?: string | boolean;
9
9
  prefixMode?: EmbeddedPrefixMode;
10
- nullable?: boolean;
11
10
  object?: boolean;
12
11
  array?: boolean;
13
- hidden?: boolean;
14
- serializer?: (value: any) => any;
15
- serializedName?: string;
16
- groups?: string[];
17
- persist?: boolean;
18
- };
12
+ }
@@ -1,11 +1,11 @@
1
- import type { Constructor, Dictionary, FilterQuery } from '../typings.js';
1
+ import type { AnyString, Constructor, Dictionary, EntityClass, ObjectQuery } from '../typings.js';
2
2
  import type { FindOptions } from '../drivers/IDatabaseDriver.js';
3
- export declare function Entity(options?: EntityOptions<any>): <T>(target: T & Dictionary) => T & Dictionary;
4
- export type EntityOptions<T> = {
3
+ export declare function Entity<T extends EntityClass<unknown>>(options?: EntityOptions<T>): (target: T) => void;
4
+ export type EntityOptions<T, E = T extends EntityClass<infer P> ? P : T> = {
5
5
  tableName?: string;
6
6
  schema?: string;
7
7
  collection?: string;
8
- discriminatorColumn?: string;
8
+ discriminatorColumn?: (T extends EntityClass<infer P> ? keyof P : string) | AnyString;
9
9
  discriminatorMap?: Dictionary<string>;
10
10
  discriminatorValue?: number | string;
11
11
  forceConstructor?: boolean;
@@ -13,6 +13,6 @@ export type EntityOptions<T> = {
13
13
  abstract?: boolean;
14
14
  readonly?: boolean;
15
15
  virtual?: boolean;
16
- expression?: string | ((em: any, where: FilterQuery<T>, options: FindOptions<T, any, any, any>) => object);
16
+ expression?: string | ((em: any, where: ObjectQuery<E>, options: FindOptions<E, any, any, any>) => object);
17
17
  repository?: () => Constructor;
18
18
  };
@@ -8,6 +8,5 @@ export function Entity(options = {}) {
8
8
  if (!options.abstract || meta.discriminatorColumn) {
9
9
  meta.name = target.name;
10
10
  }
11
- return target;
12
11
  };
13
12
  }
@@ -1,6 +1,6 @@
1
1
  import type { PropertyOptions } from './Property.js';
2
2
  import type { AnyEntity, Dictionary } from '../typings.js';
3
- export declare function Enum<T extends object>(options?: EnumOptions<AnyEntity> | (() => Dictionary)): (target: AnyEntity, propertyName: string) => any;
3
+ export declare function Enum<T extends object>(options?: EnumOptions<AnyEntity> | (() => Dictionary)): (target: T, propertyName: string) => any;
4
4
  export interface EnumOptions<T> extends PropertyOptions<T> {
5
5
  items?: (number | string)[] | (() => Dictionary);
6
6
  array?: boolean;
@@ -1,5 +1,4 @@
1
- import type { AnyEntity } from '../typings.js';
2
1
  import type { PropertyOptions } from './Property.js';
3
- export declare function Formula<T extends object>(formula: string | ((alias: string) => string), options?: FormulaOptions<T>): (target: AnyEntity, propertyName: string) => any;
2
+ export declare function Formula<T extends object>(formula: string | ((alias: string) => string), options?: FormulaOptions<T>): (target: T, propertyName: string) => any;
4
3
  export interface FormulaOptions<T> extends PropertyOptions<T> {
5
4
  }
@@ -1,17 +1,19 @@
1
- import type { AnyEntity, Dictionary } from '../typings.js';
1
+ import type { EntityClass, Dictionary, AutoPath } from '../typings.js';
2
2
  import type { DeferMode } from '../enums.js';
3
- export declare function Index<T>(options?: IndexOptions<T>): (target: AnyEntity, propertyName?: string) => any;
4
- export declare function Unique<T>(options?: UniqueOptions<T>): (target: AnyEntity, propertyName?: string) => any;
5
- interface BaseOptions<T> {
3
+ export declare function Index<T extends object, H extends string>(options?: IndexOptions<T, H>): (target: T, propertyName?: (T extends EntityClass<unknown> ? undefined : keyof T) | undefined) => any;
4
+ export declare function Unique<T extends object, H extends string>(options?: UniqueOptions<T, H>): (target: T, propertyName?: (T extends EntityClass<unknown> ? undefined : keyof T) | undefined) => any;
5
+ type MaybeArray<T> = T | T[];
6
+ type Properties<T, H extends string> = MaybeArray<AutoPath<T, H>>;
7
+ interface BaseOptions<T, H extends string> {
6
8
  name?: string;
7
- properties?: keyof T | (keyof T)[];
9
+ properties?: (T extends EntityClass<infer P> ? Properties<P, H> : Properties<T, H>);
8
10
  options?: Dictionary;
9
11
  expression?: string;
10
12
  }
11
- export interface UniqueOptions<T> extends BaseOptions<T> {
13
+ export interface UniqueOptions<T, H extends string = string> extends BaseOptions<T, H> {
12
14
  deferMode?: DeferMode | `${DeferMode}`;
13
15
  }
14
- export interface IndexOptions<T> extends BaseOptions<T> {
16
+ export interface IndexOptions<T, H extends string = string> extends BaseOptions<T, H> {
15
17
  type?: string;
16
18
  }
17
19
  export {};
@@ -3,7 +3,7 @@ import { Utils } from '../utils/Utils.js';
3
3
  function createDecorator(options, unique) {
4
4
  return function (target, propertyName) {
5
5
  const meta = MetadataStorage.getMetadataFromDecorator(propertyName ? target.constructor : target);
6
- options.properties = options.properties || propertyName;
6
+ options.properties ??= propertyName;
7
7
  const key = unique ? 'uniques' : 'indexes';
8
8
  meta[key].push(options);
9
9
  if (!propertyName) {
@@ -1,7 +1,7 @@
1
1
  import type { ReferenceOptions } from './Property.js';
2
- import type { EntityName, AnyEntity, FilterQuery, AnyString } from '../typings.js';
2
+ import type { EntityName, FilterQuery, AnyString } from '../typings.js';
3
3
  import { type QueryOrderMap } from '../enums.js';
4
- export declare function ManyToMany<T extends object, O>(entity?: ManyToManyOptions<T, O> | string | (() => EntityName<T>), mappedBy?: (string & keyof T) | ((e: T) => any), options?: Partial<ManyToManyOptions<T, O>>): (target: AnyEntity, propertyName: string) => any;
4
+ export declare function ManyToMany<Target extends object, Owner extends object>(entity?: ManyToManyOptions<Owner, Target> | string | (() => EntityName<Target>), mappedBy?: (string & keyof Target) | ((e: Target) => any), options?: Partial<ManyToManyOptions<Owner, Target>>): (target: Owner, propertyName: keyof Owner) => any;
5
5
  export interface ManyToManyOptions<Owner, Target> extends ReferenceOptions<Owner, Target> {
6
6
  /** Set this side as owning. Owning side is where the foreign key is defined. This option is not required if you use `inversedBy` or `mappedBy` to distinguish owning and inverse side. */
7
7
  owner?: boolean;
@@ -1,7 +1,7 @@
1
1
  import type { ReferenceOptions } from './Property.js';
2
2
  import { type DeferMode } from '../enums.js';
3
- import type { AnyEntity, AnyString, EntityName } from '../typings.js';
4
- export declare function ManyToOne<T extends object, O>(entity?: ManyToOneOptions<T, O> | string | ((e?: any) => EntityName<T>), options?: Partial<ManyToOneOptions<T, O>>): (target: AnyEntity, propertyName: string) => any;
3
+ import type { AnyString, EntityName } from '../typings.js';
4
+ export declare function ManyToOne<Target extends object, Owner extends object>(entity?: ManyToOneOptions<Owner, Target> | string | ((e?: any) => EntityName<Target>), options?: Partial<ManyToOneOptions<Owner, Target>>): (target: Owner, propertyName: keyof Owner) => any;
5
5
  export interface ManyToOneOptions<Owner, Target> extends ReferenceOptions<Owner, Target> {
6
6
  /** Point to the inverse side property name. */
7
7
  inversedBy?: (string & keyof Target) | ((e: Target) => any);
@@ -27,4 +27,6 @@ export interface ManyToOneOptions<Owner, Target> extends ReferenceOptions<Owner,
27
27
  updateRule?: 'cascade' | 'no action' | 'set null' | 'set default' | AnyString;
28
28
  /** Set the constraint type. Immediate constraints are checked for each statement, while deferred ones are only checked at the end of the transaction. Only for postgres unique constraints. */
29
29
  deferMode?: DeferMode | `${DeferMode}`;
30
+ /** Set a custom foreign key constraint name, overriding NamingStrategy.indexName(). */
31
+ foreignKeyName?: string;
30
32
  }
@@ -1,9 +1,9 @@
1
1
  import type { ReferenceOptions } from './Property.js';
2
2
  import { ReferenceKind, type QueryOrderMap } from '../enums.js';
3
- import type { EntityName, AnyEntity, FilterQuery } from '../typings.js';
4
- export declare function createOneToDecorator<Target, Owner>(entity: OneToManyOptions<Owner, Target> | string | ((e?: any) => EntityName<Target>), mappedBy: (string & keyof Target) | ((e: Target) => any) | undefined, options: Partial<OneToManyOptions<Owner, Target>>, kind: ReferenceKind): (target: AnyEntity, propertyName: string) => any;
5
- export declare function OneToMany<Target, Owner>(entity: string | ((e?: any) => EntityName<Target>), mappedBy: (string & keyof Target) | ((e: Target) => any), options?: Partial<OneToManyOptions<Owner, Target>>): (target: AnyEntity, propertyName: string) => void;
6
- export declare function OneToMany<Target, Owner>(options: OneToManyOptions<Owner, Target>): (target: AnyEntity, propertyName: string) => void;
3
+ import type { EntityName, FilterQuery } from '../typings.js';
4
+ export declare function createOneToDecorator<Target, Owner>(entity: OneToManyOptions<Owner, Target> | string | ((e?: any) => EntityName<Target>), mappedBy: (string & keyof Target) | ((e: Target) => any) | undefined, options: Partial<OneToManyOptions<Owner, Target>>, kind: ReferenceKind): (target: Owner, propertyName: string) => any;
5
+ export declare function OneToMany<Target, Owner>(entity: string | ((e?: any) => EntityName<Target>), mappedBy: (string & keyof Target) | ((e: Target) => any), options?: Partial<OneToManyOptions<Owner, Target>>): (target: Owner, propertyName: string) => void;
6
+ export declare function OneToMany<Target, Owner>(options: OneToManyOptions<Owner, Target>): (target: Owner, propertyName: string) => void;
7
7
  export interface OneToManyOptions<Owner, Target> extends ReferenceOptions<Owner, Target> {
8
8
  /** Remove the entity when it gets disconnected from the relationship (see {@doclink cascading | Cascading}). */
9
9
  orphanRemoval?: boolean;
@@ -1,7 +1,7 @@
1
1
  import { type DeferMode } from '../enums.js';
2
2
  import { type OneToManyOptions } from './OneToMany.js';
3
3
  import type { AnyString, EntityName } from '../typings.js';
4
- export declare function OneToOne<Target, Owner>(entity?: OneToOneOptions<Owner, Target> | string | ((e: Owner) => EntityName<Target>), mappedByOrOptions?: (string & keyof Target) | ((e: Target) => any) | Partial<OneToOneOptions<Owner, Target>>, options?: Partial<OneToOneOptions<Owner, Target>>): (target: import("../typings.js").AnyEntity, propertyName: string) => any;
4
+ export declare function OneToOne<Target, Owner>(entity?: OneToOneOptions<Owner, Target> | string | ((e: Owner) => EntityName<Target>), mappedByOrOptions?: (string & keyof Target) | ((e: Target) => any) | Partial<OneToOneOptions<Owner, Target>>, options?: Partial<OneToOneOptions<Owner, Target>>): (target: Owner, propertyName: string) => any;
5
5
  export interface OneToOneOptions<Owner, Target> extends Partial<Omit<OneToManyOptions<Owner, Target>, 'orderBy'>> {
6
6
  /** Set this side as owning. Owning side is where the foreign key is defined. This option is not required if you use `inversedBy` or `mappedBy` to distinguish owning and inverse side. */
7
7
  owner?: boolean;
@@ -21,4 +21,6 @@ export interface OneToOneOptions<Owner, Target> extends Partial<Omit<OneToManyOp
21
21
  updateRule?: 'cascade' | 'no action' | 'set null' | 'set default' | AnyString;
22
22
  /** Set the constraint type. Immediate constraints are checked for each statement, while deferred ones are only checked at the end of the transaction. Only for postgres unique constraints. */
23
23
  deferMode?: DeferMode | `${DeferMode}`;
24
+ /** Set a custom foreign key constraint name, overriding NamingStrategy.indexName(). */
25
+ foreignKeyName?: string;
24
26
  }
@@ -1,7 +1,6 @@
1
1
  import type { PropertyOptions } from './Property.js';
2
- import type { AnyEntity } from '../typings.js';
3
- export declare function PrimaryKey<T extends object>(options?: PrimaryKeyOptions<T>): (target: AnyEntity, propertyName: string) => any;
4
- export declare function SerializedPrimaryKey<T extends object>(options?: SerializedPrimaryKeyOptions<T>): (target: AnyEntity, propertyName: string) => any;
2
+ export declare function PrimaryKey<T extends object>(options?: PrimaryKeyOptions<T>): (target: T, propertyName: string) => any;
3
+ export declare function SerializedPrimaryKey<T extends object>(options?: SerializedPrimaryKeyOptions<T>): (target: T, propertyName: string) => any;
5
4
  export interface PrimaryKeyOptions<T> extends PropertyOptions<T> {
6
5
  }
7
6
  export interface SerializedPrimaryKeyOptions<T> extends PropertyOptions<T> {
@@ -3,7 +3,7 @@ import type { EntityName, Constructor, CheckCallback, GeneratedColumnCallback, A
3
3
  import type { Type, types } from '../types/index.js';
4
4
  import type { EntityManager } from '../EntityManager.js';
5
5
  import type { SerializeOptions } from '../serialization/EntitySerializer.js';
6
- export declare function Property<T extends object>(options?: PropertyOptions<T>): (target: any, propertyName: string) => any;
6
+ export declare function Property<T extends object>(options?: PropertyOptions<T>): (target: T, propertyName: string) => any;
7
7
  export interface PropertyOptions<Owner> {
8
8
  /**
9
9
  * Alias for `fieldName`.
@@ -146,8 +146,11 @@ export interface FindOptions<Entity, Hint extends string = never, Fields extends
146
146
  hintComments?: string | string[];
147
147
  loggerContext?: LogContext;
148
148
  logging?: LoggingOptions;
149
+ /** @internal used to apply filters to the auto-joined relations */
150
+ em?: EntityManager;
149
151
  }
150
- export interface FindByCursorOptions<T extends object, P extends string = never, F extends string = '*', E extends string = never> extends Omit<FindOptions<T, P, F, E>, 'limit' | 'offset'> {
152
+ export interface FindByCursorOptions<T extends object, P extends string = never, F extends string = '*', E extends string = never, I extends boolean = true> extends Omit<FindOptions<T, P, F, E>, 'limit' | 'offset'> {
153
+ includeCount?: I;
151
154
  }
152
155
  export interface FindOneOptions<T extends object, P extends string = never, F extends string = '*', E extends string = never> extends Omit<FindOptions<T, P, F, E>, 'limit' | 'lockMode'> {
153
156
  lockMode?: LockMode;
@@ -14,7 +14,7 @@ export declare class ArrayCollection<T extends object, O extends object> {
14
14
  getItems(): T[];
15
15
  toArray<TT extends T>(): EntityDTO<TT>[];
16
16
  toJSON(): EntityDTO<T>[];
17
- getIdentifiers<U extends IPrimaryKey = Primary<T> & IPrimaryKey>(field?: string): U[];
17
+ getIdentifiers<U extends IPrimaryKey = Primary<T> & IPrimaryKey>(field?: string | string[]): U[];
18
18
  add(entity: T | Reference<T> | Iterable<T | Reference<T>>, ...entities: (T | Reference<T>)[]): void;
19
19
  /**
20
20
  * @internal
@@ -40,15 +40,22 @@ export class ArrayCollection {
40
40
  }
41
41
  getIdentifiers(field) {
42
42
  const items = this.getItems();
43
+ const targetMeta = this.property.targetMeta;
43
44
  if (items.length === 0) {
44
45
  return [];
45
46
  }
46
- field ??= this.property.targetMeta.serializedPrimaryKey;
47
+ field ??= targetMeta.compositePK ? targetMeta.primaryKeys : targetMeta.serializedPrimaryKey;
48
+ const cb = (i, f) => {
49
+ if (Utils.isEntity(i[f], true)) {
50
+ return wrap(i[f], true).getPrimaryKey();
51
+ }
52
+ return i[f];
53
+ };
47
54
  return items.map(i => {
48
- if (Utils.isEntity(i[field], true)) {
49
- return wrap(i[field], true).getPrimaryKey();
55
+ if (Array.isArray(field)) {
56
+ return field.map(f => cb(i, f));
50
57
  }
51
- return i[field];
58
+ return cb(i, field);
52
59
  });
53
60
  }
54
61
  add(entity, ...entities) {
@@ -2,7 +2,7 @@ import type { EntityDTO, EntityKey, FilterQuery, Loaded, LoadedCollection, Popul
2
2
  import { ArrayCollection } from './ArrayCollection.js';
3
3
  import { Reference } from './Reference.js';
4
4
  import type { Transaction } from '../connections/Connection.js';
5
- import type { FindOptions, CountOptions } from '../drivers/IDatabaseDriver.js';
5
+ import type { CountOptions, FindOptions } from '../drivers/IDatabaseDriver.js';
6
6
  import type { EntityLoaderOptions } from './EntityLoader.js';
7
7
  export interface MatchingOptions<T extends object, P extends string = never> extends FindOptions<T, P> {
8
8
  where?: FilterQuery<T>;
@@ -12,7 +12,6 @@ export interface MatchingOptions<T extends object, P extends string = never> ext
12
12
  export declare class Collection<T extends object, O extends object = object> extends ArrayCollection<T, O> {
13
13
  private readonly?;
14
14
  private _populated?;
15
- private _em?;
16
15
  private _snapshot?;
17
16
  constructor(owner: O, items?: T[], initialized?: boolean);
18
17
  /**