@mikro-orm/core 7.1.0-dev.5 → 7.1.0-dev.50

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 (66) hide show
  1. package/EntityManager.d.ts +87 -12
  2. package/EntityManager.js +252 -40
  3. package/README.md +2 -1
  4. package/connections/Connection.d.ts +67 -1
  5. package/connections/Connection.js +64 -0
  6. package/drivers/IDatabaseDriver.d.ts +45 -7
  7. package/entity/BaseEntity.d.ts +68 -1
  8. package/entity/BaseEntity.js +18 -0
  9. package/entity/Collection.d.ts +6 -3
  10. package/entity/Collection.js +15 -4
  11. package/entity/EntityAssigner.js +8 -0
  12. package/entity/EntityFactory.js +5 -3
  13. package/entity/EntityLoader.d.ts +8 -1
  14. package/entity/EntityLoader.js +103 -30
  15. package/entity/EntityRepository.d.ts +27 -9
  16. package/entity/EntityRepository.js +12 -0
  17. package/entity/Reference.d.ts +42 -1
  18. package/entity/Reference.js +9 -0
  19. package/entity/defineEntity.d.ts +101 -21
  20. package/entity/defineEntity.js +17 -6
  21. package/entity/utils.js +4 -5
  22. package/enums.d.ts +8 -1
  23. package/errors.d.ts +2 -0
  24. package/errors.js +4 -0
  25. package/index.d.ts +2 -2
  26. package/index.js +1 -1
  27. package/metadata/EntitySchema.js +18 -0
  28. package/metadata/MetadataDiscovery.d.ts +12 -0
  29. package/metadata/MetadataDiscovery.js +173 -22
  30. package/metadata/MetadataValidator.d.ts +26 -0
  31. package/metadata/MetadataValidator.js +237 -1
  32. package/metadata/Routine.d.ts +74 -0
  33. package/metadata/Routine.js +140 -0
  34. package/metadata/index.d.ts +1 -0
  35. package/metadata/index.js +1 -0
  36. package/metadata/types.d.ts +78 -9
  37. package/naming-strategy/AbstractNamingStrategy.d.ts +1 -1
  38. package/naming-strategy/NamingStrategy.d.ts +1 -1
  39. package/package.json +1 -1
  40. package/platforms/Platform.d.ts +18 -3
  41. package/platforms/Platform.js +58 -6
  42. package/serialization/EntitySerializer.js +4 -3
  43. package/typings.d.ts +399 -22
  44. package/typings.js +43 -12
  45. package/unit-of-work/UnitOfWork.js +43 -5
  46. package/utils/AbstractMigrator.d.ts +20 -5
  47. package/utils/AbstractMigrator.js +263 -28
  48. package/utils/AbstractSchemaGenerator.d.ts +1 -1
  49. package/utils/AbstractSchemaGenerator.js +4 -1
  50. package/utils/Configuration.d.ts +30 -0
  51. package/utils/Configuration.js +45 -0
  52. package/utils/DataloaderUtils.d.ts +10 -1
  53. package/utils/DataloaderUtils.js +78 -0
  54. package/utils/EntityComparator.js +1 -1
  55. package/utils/QueryHelper.d.ts +16 -0
  56. package/utils/QueryHelper.js +15 -0
  57. package/utils/TransactionManager.js +2 -0
  58. package/utils/Utils.js +1 -1
  59. package/utils/fs-utils.d.ts +2 -0
  60. package/utils/fs-utils.js +7 -1
  61. package/utils/index.d.ts +1 -0
  62. package/utils/index.js +1 -0
  63. package/utils/partition-utils.d.ts +17 -0
  64. package/utils/partition-utils.js +79 -0
  65. package/utils/upsert-utils.d.ts +2 -0
  66. package/utils/upsert-utils.js +26 -1
package/typings.d.ts CHANGED
@@ -10,8 +10,9 @@ import { Reference, type ScalarReference } from './entity/Reference.js';
10
10
  import type { SerializationContext } from './serialization/SerializationContext.js';
11
11
  import type { SerializeOptions } from './serialization/EntitySerializer.js';
12
12
  import type { MetadataStorage } from './metadata/MetadataStorage.js';
13
+ import type { Routine } from './metadata/Routine.js';
13
14
  import type { EntitySchema } from './metadata/EntitySchema.js';
14
- import type { IndexColumnOptions } from './metadata/types.js';
15
+ import type { EntityPartitionBy, IndexColumnOptions } from './metadata/types.js';
15
16
  import type { Type, types } from './types/index.js';
16
17
  import type { Platform } from './platforms/Platform.js';
17
18
  import type { Configuration } from './utils/Configuration.js';
@@ -47,7 +48,7 @@ export type AsyncFunction<R = any, T = Dictionary> = (args: T) => Promise<T>;
47
48
  export type Compute<T> = {
48
49
  [K in keyof T]: T[K];
49
50
  } & {};
50
- type InternalKeys = 'EntityRepositoryType' | 'PrimaryKeyProp' | 'OptionalProps' | 'EagerProps' | 'HiddenProps' | '__selectedType' | '__loadedType';
51
+ type InternalKeys = 'EntityRepositoryType' | 'PrimaryKeyProp' | 'OptionalProps' | 'EagerProps' | 'HiddenProps' | 'IndexHints' | '__selectedType' | '__loadedType';
51
52
  /** Filters out function, symbol, and internal keys from an entity type. When `B = true`, also excludes scalar keys. */
52
53
  export type CleanKeys<T, K extends keyof T, B extends boolean = false> = T[K] & {} extends Function ? never : K extends symbol | InternalKeys ? never : B extends true ? T[K] & {} extends Scalar ? never : K : K;
53
54
  /** Extracts keys of `T` whose values are functions. */
@@ -113,7 +114,7 @@ type LoadedReferenceShape<T = any> = ReferenceShape & {
113
114
  * Using this instead of `Loadable<any>` in conditional type checks prevents
114
115
  * TypeScript from evaluating the full Collection/Reference interfaces.
115
116
  */
116
- type LoadableShape = CollectionShape | ReferenceShape | readonly any[];
117
+ type LoadableShape = CollectionShape | ReferenceShape | LazyRef.Brand<any> | readonly any[];
117
118
  /** Gets all keys from all members of a union type (distributes over the union). */
118
119
  export type UnionKeys<T> = T extends any ? keyof T : never;
119
120
  /** Gets the type of a property from all union members that have it (distributes over the union). */
@@ -150,6 +151,44 @@ export declare const EntityName: unique symbol;
150
151
  export type InferEntityName<T> = T extends {
151
152
  [EntityName]?: infer Name;
152
153
  } ? (Name extends string ? Name : never) : never;
154
+ /**
155
+ * Symbol used to declare index-to-column mappings on an entity type.
156
+ * For decorator entities, declare as a phantom property:
157
+ * ```typescript
158
+ * [IndexHints]?: { idx_email: 'email'; idx_name_age: 'name' | 'age' };
159
+ * ```
160
+ * For `defineEntity` entities, index hints are inferred automatically from
161
+ * named indexes (property-level `.index('name')` and entity-level `indexes`/`uniques`).
162
+ */
163
+ export declare const IndexHints: unique symbol;
164
+ /**
165
+ * Extracts the index hints map from an entity type. Returns `never` when no hints are declared.
166
+ * For decorator entities, `[IndexHints]` contains a pre-computed `{ idxName: 'prop' }` map.
167
+ * For `defineEntity` entities, `[IndexHints]` contains `[Properties]` (a tuple wrapping the
168
+ * raw property builders), which is lazily converted to the index map when first accessed.
169
+ */
170
+ export type ExtractIndexHints<T> = T extends {
171
+ [IndexHints]?: infer H;
172
+ } ? H extends [infer P extends Record<string, any>] ? InferPropertyIndexMap<P> : H : never;
173
+ /**
174
+ * Extracts `{ indexName: propertyKey }` from property builder options.
175
+ * Checks `.index('name')` and `.unique('name')` on each property in a single pass.
176
+ */
177
+ export type InferPropertyIndexMap<Properties extends Record<string, any>> = {
178
+ [K in keyof Properties as MaybeReturnType<Properties[K]> extends {
179
+ '~options': {
180
+ index: infer N extends string;
181
+ };
182
+ } ? N : MaybeReturnType<Properties[K]> extends {
183
+ '~options': {
184
+ unique: infer N extends string;
185
+ };
186
+ } ? N : never]: K & string;
187
+ };
188
+ /** Union of declared index names on an entity. Falls back to `string` when no `[IndexHints]` are declared. */
189
+ export type IndexName<T> = [ExtractIndexHints<T>] extends [never] ? string : (keyof ExtractIndexHints<T> & string) | (string & {});
190
+ /** Properties covered by the named index on entity T. Falls back to all entity keys when the index is unknown. */
191
+ export type IndexColumns<T, Name extends string> = ExtractIndexHints<T> extends Record<Name, infer Cols> ? Cols & string : EntityKey<T>;
153
192
  /**
154
193
  * Branded type that marks a property as optional in `em.create()`.
155
194
  * Use as a property type wrapper: `createdAt: Opt<Date>` instead of listing in `[OptionalProps]`.
@@ -328,6 +367,18 @@ export type ObjectQuery<T> = OperatorMap<T> & FilterObject<T>;
328
367
  * Accepts an object query, a primary key value, entity props with operators, or an array of filters.
329
368
  */
330
369
  export type FilterQuery<T> = ObjectQuery<T> | NonNullable<ExpandScalar<Primary<T>>> | NonNullable<EntityProps<T> & OperatorMap<T>> | FilterQuery<T>[];
370
+ /**
371
+ * `FilterQuery` restricted to only properties covered by the specified index(es).
372
+ * Used when `using` option is set in `FindOptions` to enforce type-safe index usage.
373
+ */
374
+ export type IndexFilterQuery<T, Using extends string> = [Using] extends [never] ? FilterQuery<T> : (OperatorMap<T> & {
375
+ -readonly [K in Extract<EntityKey<T>, IndexColumns<T, Using>>]?: ExpandQuery<ExpandProperty<FilterObjectProp<T, K>>> | ExpandQueryMerged<ExpandProperty<FilterObjectProp<T, K>>> | FilterValue<ExpandProperty<FilterObjectProp<T, K>>> | ElemMatchFilter<FilterObjectProp<T, K>> | null;
376
+ }) | NonNullable<ExpandScalar<Primary<T>>> | IndexFilterQuery<T, Using>[];
377
+ /** Replaces `where` and `using` on an options type with index-aware variants when `Using` is specified. */
378
+ export type WithUsingOptions<Opts, Entity, Using extends string> = Omit<Opts, 'where' | 'using'> & {
379
+ using?: Using | Using[];
380
+ where?: [Using] extends [never] ? FilterQuery<Entity> : IndexFilterQuery<Entity, Using>;
381
+ };
331
382
  /** Public interface for the entity wrapper, accessible via `wrap(entity)`. Provides helper methods for entity state management. */
332
383
  export interface IWrappedEntity<Entity extends object> {
333
384
  isInitialized(): boolean;
@@ -417,12 +468,12 @@ type NonArrayObject = object & {
417
468
  export type EntityDataProp<T, C extends boolean> = T extends Date ? string | Date : T extends Scalar ? T : T extends ScalarReference<infer U> ? EntityDataProp<U, C> : T extends {
418
469
  __runtime?: infer Runtime;
419
470
  __raw?: infer Raw;
420
- } ? C extends true ? Raw : Runtime : T extends ReferenceShape<infer U> ? EntityDataNested<U, C> : T extends CollectionShape<infer U> ? U | U[] | EntityDataNested<U & object, C> | EntityDataNested<U & object, C>[] : T extends readonly (infer U)[] ? U extends NonArrayObject ? U | U[] | EntityDataNested<U, C> | EntityDataNested<U, C>[] : U[] | EntityDataNested<U, C>[] : EntityDataNested<T, C>;
471
+ } ? C extends true ? Raw : Runtime : T extends LazyRef.Brand<infer U> ? EntityDataNested<U, C> : T extends ReferenceShape<infer U> ? EntityDataNested<U, C> : T extends CollectionShape<infer U> ? U | U[] | EntityDataNested<U & object, C> | EntityDataNested<U & object, C>[] : T extends readonly (infer U)[] ? U extends NonArrayObject ? U | U[] | EntityDataNested<U, C> | EntityDataNested<U, C>[] : U[] | EntityDataNested<U, C>[] : EntityDataNested<T, C>;
421
472
  /** Like `EntityDataProp` but used in `RequiredEntityData` context with required/optional key distinction. */
422
473
  export type RequiredEntityDataProp<T, O, C extends boolean> = T extends Date ? string | Date : Exclude<T, null> extends RequiredNullable.Brand ? T | null : T extends Scalar ? T : T extends ScalarReference<infer U> ? RequiredEntityDataProp<U, O, C> : T extends {
423
474
  __runtime?: infer Runtime;
424
475
  __raw?: infer Raw;
425
- } ? C extends true ? Raw : Runtime : T extends ReferenceShape<infer U> ? RequiredEntityDataNested<U, O, C> : T extends CollectionShape<infer U> ? U | U[] | RequiredEntityDataNested<U & object, O, C> | RequiredEntityDataNested<U & object, O, C>[] : T extends readonly (infer U)[] ? U extends NonArrayObject ? U | U[] | RequiredEntityDataNested<U, O, C> | RequiredEntityDataNested<U, O, C>[] : U[] | RequiredEntityDataNested<U, O, C>[] : RequiredEntityDataNested<T, O, C>;
476
+ } ? C extends true ? Raw : Runtime : T extends LazyRef.Brand<infer U> ? RequiredEntityDataNested<U, O, C> : T extends ReferenceShape<infer U> ? RequiredEntityDataNested<U, O, C> : T extends CollectionShape<infer U> ? U | U[] | RequiredEntityDataNested<U & object, O, C> | RequiredEntityDataNested<U & object, O, C>[] : T extends readonly (infer U)[] ? U extends NonArrayObject ? U | U[] | RequiredEntityDataNested<U, O, C> | RequiredEntityDataNested<U, O, C>[] : U[] | RequiredEntityDataNested<U, O, C>[] : RequiredEntityDataNested<T, O, C>;
426
477
  /** Nested entity data shape for embedded or related entities within `EntityData`. */
427
478
  export type EntityDataNested<T, C extends boolean = false> = T extends undefined ? never : T extends any[] ? Readonly<T> : EntityData<T, C> | ExpandEntityProp<T, C>;
428
479
  type UnwrapScalarRef<T> = T extends ScalarReference<infer U> ? U : T;
@@ -471,6 +522,35 @@ type Relation<T> = {
471
522
  export type Rel<T> = T;
472
523
  /** Alias for `ScalarReference` (see {@apilink Ref}). */
473
524
  export type ScalarRef<T> = ScalarReference<T>;
525
+ /**
526
+ * Type-level marker for a to-one relation that is **direct at runtime** (no `Reference` wrapper) but
527
+ * **restricted at compile time** until narrowed via `Loaded<>`.
528
+ *
529
+ * Use as the property type on a `@ManyToOne`/`@OneToOne` relation that does **not** have `ref: true`:
530
+ *
531
+ * ```ts
532
+ * @ManyToOne(() => User)
533
+ * author!: LazyRef<User>;
534
+ * ```
535
+ *
536
+ * Semantics:
537
+ * - **Runtime**: identical to a plain direct relation — `article.author` is a `User` instance (stub or hydrated),
538
+ * `article.author instanceof User` is `true`, no `Reference` object is created.
539
+ * - **Type (unloaded view)**: only the primary key is accessible. Accessing other properties is a compile error.
540
+ * - **Type (loaded view)**: once the relation is in the populate hint of a `Loaded<Entity, 'author'>`, it narrows
541
+ * back to the full entity — no `.$` or `.get()` indirection needed.
542
+ *
543
+ * Note: the safety is purely compile-time. JS code or `as any` casts bypass it.
544
+ */
545
+ export type LazyRef<T extends object> = IsAny<T> extends true ? LazyRef.Brand<T> : {
546
+ [K in PrimaryProperty<T> & keyof T]: T[K];
547
+ } & LazyRef.Brand<T>;
548
+ export declare namespace LazyRef {
549
+ const __lazyRef: unique symbol;
550
+ interface Brand<T> {
551
+ [__lazyRef]?: (arg: T) => T;
552
+ }
553
+ }
474
554
  /** Alias for `Reference<T> & { id: number }` (see {@apilink Ref}). */
475
555
  export type EntityRef<T extends object> = true extends IsUnknown<PrimaryProperty<T>> ? Reference<T> : IsAny<T> extends true ? Reference<T> : {
476
556
  [K in PrimaryProperty<T> & keyof T]: T[K];
@@ -594,19 +674,39 @@ export type SchemaTable = {
594
674
  export type FormulaColumns<T> = Record<PropertyName<T>, string> & {
595
675
  toString(): string;
596
676
  };
677
+ /**
678
+ * Column reference for schema callbacks. Behaves like a string (coercible via `toString()`),
679
+ * with arbitrary nested property access for embedded sub-columns (e.g. `cols.address.city`).
680
+ */
681
+ export type SchemaColumnRef = string & {
682
+ readonly [key: string]: SchemaColumnRef;
683
+ };
597
684
  /**
598
685
  * Column mapping for schema callbacks (indexes, checks, generated columns).
599
686
  * Maps property names to field names. For TPT entities, only includes properties
600
687
  * that belong to the current table (not inherited properties from parent tables).
688
+ * Embedded properties expose their sub-columns via nested access (e.g. `cols.address.city`),
689
+ * while coercing to the embedded property's own column name via `toString()` (matches the
690
+ * pre-7712 behaviour, regardless of any custom `prefix`).
691
+ */
692
+ export type SchemaColumns<T> = Record<PropertyName<T>, SchemaColumnRef>;
693
+ /**
694
+ * Callback for custom index expressions. Receives column mappings, table info, and the index name.
695
+ * The runtime `columns` object includes nested entries for embedded properties (see `SchemaColumnRef`);
696
+ * cast to `SchemaColumns<T>` if you need typed nested access.
601
697
  */
602
- export type SchemaColumns<T> = Record<PropertyName<T>, string>;
603
- /** Callback for custom index expressions. Receives column mappings, table info, and the index name. */
604
698
  export type IndexCallback<T> = (columns: Record<PropertyName<T>, string>, table: SchemaTable, indexName: string) => string | Raw;
605
699
  /** Callback for computed (formula) properties. Receives column mappings and table info, returns a SQL expression. */
606
700
  export type FormulaCallback<T> = (columns: FormulaColumns<T>, table: FormulaTable) => string | Raw;
607
701
  /** Callback for CHECK constraint expressions. Receives column mappings and table info. */
608
- export type CheckCallback<T> = (columns: Record<PropertyName<T>, string>, table: SchemaTable) => string | Raw;
609
- /** Callback for generated (computed) column expressions. Receives column mappings and table info. */
702
+ export type CheckCallback<T> = (columns: SchemaColumns<T>, table: SchemaTable) => string | Raw;
703
+ /** Callback for trigger body expressions. Receives column mappings and table info. */
704
+ export type TriggerCallback<T> = (columns: Record<PropertyName<T>, string>, table: SchemaTable) => string | Raw;
705
+ /**
706
+ * Callback for generated (computed) column expressions. Receives column mappings and table info.
707
+ * The runtime `columns` object includes nested entries for embedded properties (see `SchemaColumnRef`);
708
+ * cast to `SchemaColumns<T>` if you need typed nested access.
709
+ */
610
710
  export type GeneratedColumnCallback<T> = (columns: Record<PropertyName<T>, string>, table: SchemaTable) => string | Raw;
611
711
  /** Definition of a CHECK constraint on a table or property. */
612
712
  export interface CheckConstraint<T = any> {
@@ -614,6 +714,214 @@ export interface CheckConstraint<T = any> {
614
714
  property?: string;
615
715
  expression: string | Raw | CheckCallback<T>;
616
716
  }
717
+ /** Definition of a database trigger on a table. */
718
+ export interface TriggerDef<T = any> {
719
+ /** Trigger name. Auto-generated if omitted. */
720
+ name?: string;
721
+ /** When the trigger fires relative to the event. */
722
+ timing: 'before' | 'after' | 'instead of';
723
+ /** Which DML events activate the trigger. */
724
+ events: ('insert' | 'update' | 'delete' | 'truncate')[];
725
+ /** Whether the trigger fires once per row or per statement. Defaults to `'row'`. */
726
+ forEach?: 'row' | 'statement';
727
+ /** SQL body of the trigger. Can be a string, Raw query, or callback receiving column name mappings. */
728
+ body?: string | Raw | TriggerCallback<T>;
729
+ /** Optional SQL WHEN condition for the trigger. */
730
+ when?: string;
731
+ /** Raw DDL escape hatch — full CREATE TRIGGER statement. Mutually exclusive with `body`. */
732
+ expression?: string;
733
+ }
734
+ export type RoutineParamDirection = 'in' | 'out' | 'inout';
735
+ /** Mirrors MySQL/MariaDB's `SQL DATA ACCESS` clause; ignored by other dialects. */
736
+ export type RoutineDataAccess = 'contains-sql' | 'no-sql' | 'reads-sql-data' | 'modifies-sql-data';
737
+ export type RoutineSecurity = 'invoker' | 'definer';
738
+ export type RoutineKind = 'procedure' | 'function';
739
+ export type RoutineIgnoreField = 'body' | 'comment' | 'security' | 'deterministic' | 'definer';
740
+ export type RoutineParamMap<T> = Record<PropertyName<T>, string>;
741
+ export type RoutineBodyCallback<T> = (params: RoutineParamMap<T>, em: any) => string | Raw;
742
+ /**
743
+ * Routine return shape:
744
+ * - omitted/`void`: procedures with no result set
745
+ * - `() => Entity` (single or tuple): hydrated row arrays, one per result set
746
+ * - `{ type: Type<...> }`: scalar function return — runtime/column types both inferred
747
+ * from the {@link Type} generics
748
+ * - `{ runtimeType, columnType }`: scalar function return with explicit SQL+TS types
749
+ * - `{ hydrate }`: fully custom row mapping
750
+ */
751
+ export type RoutineReturns<T = unknown> = (() => EntityName<any>) | (() => EntityName<any>)[] | {
752
+ type: Type<unknown> | Constructor<Type<unknown>>;
753
+ nullable?: boolean;
754
+ } | {
755
+ runtimeType: RoutineRuntimeType;
756
+ columnType?: string;
757
+ nullable?: boolean;
758
+ customType?: Type<unknown> | Constructor<Type<unknown>>;
759
+ } | {
760
+ hydrate: (rows: Dictionary[][], args: T, em: any) => unknown;
761
+ };
762
+ /** JS fallback registered as a UDF on SQLite (better-sqlite3). Functions only. */
763
+ export type RoutineJsBody<T> = (params: T) => unknown;
764
+ export interface RoutineDef<T = any> {
765
+ type: RoutineKind;
766
+ name?: string;
767
+ schema?: string;
768
+ comment?: string;
769
+ security?: RoutineSecurity;
770
+ /** User the routine runs as when `security: 'definer'`. */
771
+ definer?: string;
772
+ deterministic?: boolean;
773
+ /** MySQL/MariaDB only. */
774
+ dataAccess?: RoutineDataAccess;
775
+ language?: 'sql' | 'plpgsql' | 'tsql' | 'plsql' | AnyString;
776
+ /** Mutually exclusive with `expression`. */
777
+ body?: string | Raw | RoutineBodyCallback<T>;
778
+ /** Raw `CREATE PROCEDURE`/`FUNCTION` escape hatch — schema diff can't detect changes. Prefer `body`. */
779
+ expression?: string;
780
+ /** JS fallback registered as a UDF on SQLite (better-sqlite3). Functions only. */
781
+ bodyJs?: RoutineJsBody<T>;
782
+ returns?: RoutineReturns<T>;
783
+ /** Skip selected fields in schema diff; useful when the engine normalises the body differently. */
784
+ ignoreSchemaChanges?: RoutineIgnoreField[];
785
+ }
786
+ export interface RoutineProperty<Owner = any> {
787
+ name: EntityKey<Owner>;
788
+ /** SQL string, or a `Type` instance (resolved to the dialect column type at schema-gen time via `getColumnType`). */
789
+ type: keyof typeof types | AnyString | Type<unknown>;
790
+ runtimeType: EntityProperty['runtimeType'];
791
+ /** Singleton array to align with EntityProperty's `columnTypes`/Type API surface. */
792
+ columnTypes: string[];
793
+ customType?: Type<unknown>;
794
+ direction: RoutineParamDirection;
795
+ /** Required for OUT/INOUT params — wraps the JS-side value in `ScalarReference`. */
796
+ ref?: boolean;
797
+ length?: number;
798
+ precision?: number;
799
+ scale?: number;
800
+ nullable?: boolean;
801
+ /** Default expression used when the caller omits the parameter, where the dialect supports it. */
802
+ defaultRaw?: string;
803
+ /** Original declaration order, used to rebuild positional argument lists. */
804
+ index: number;
805
+ }
806
+ export interface RoutineParamConfig {
807
+ runtimeType?: RoutineRuntimeType;
808
+ type?: keyof typeof types | AnyString | Type<any> | Constructor<Type<any>>;
809
+ direction?: RoutineParamDirection;
810
+ ref?: boolean;
811
+ length?: number;
812
+ precision?: number;
813
+ scale?: number;
814
+ nullable?: boolean;
815
+ defaultRaw?: string;
816
+ /** Marshals the param via `Type.convertToDatabaseValue` inbound and `convertToJSValue` outbound. */
817
+ customType?: Type<unknown> | Constructor<Type<unknown>>;
818
+ }
819
+ /** Routine declaration shape accepted by the {@link Routine} class. */
820
+ export interface RoutineConfig<T = any> extends Omit<RoutineDef<T>, 'name'> {
821
+ name: string;
822
+ /** Order is preserved from `Object.keys`. */
823
+ params?: Record<string, RoutineParamConfig>;
824
+ }
825
+ export type RoutineRuntimeTypeMap = {
826
+ string: string;
827
+ number: number;
828
+ boolean: boolean;
829
+ bigint: bigint;
830
+ Buffer: Buffer;
831
+ Date: Date;
832
+ object: Dictionary;
833
+ any: any;
834
+ };
835
+ /** Narrow union (vs `EntityProperty['runtimeType']`) so literals survive `const` inference and feed args/return inference. */
836
+ export type RoutineRuntimeType = keyof RoutineRuntimeTypeMap;
837
+ type RoutineRuntimeOf<R> = R extends keyof RoutineRuntimeTypeMap ? RoutineRuntimeTypeMap[R] : unknown;
838
+ type Nullify<P, V> = P extends {
839
+ nullable: true;
840
+ } ? V | null : V;
841
+ type StripSqlTypeArgs<S extends string> = S extends `${infer Base}(${string}` ? Base : S;
842
+ type SqlStringTypes = 'varchar' | 'char' | 'character' | 'nvarchar' | 'nchar' | 'text' | 'mediumtext' | 'longtext' | 'tinytext' | 'ntext' | 'clob' | 'nclob' | 'citext' | 'xml' | 'uuid' | 'string' | 'decimal' | 'numeric' | 'money' | 'bigint' | 'int8' | 'bigserial';
843
+ type SqlNumberTypes = 'int' | 'integer' | 'smallint' | 'tinyint' | 'mediumint' | 'int2' | 'int4' | 'serial' | 'smallserial' | 'real' | 'float' | 'float4' | 'float8' | 'double';
844
+ type SqlBooleanTypes = 'boolean' | 'bool' | 'bit';
845
+ type SqlDateTypes = 'date' | 'datetime' | 'datetime2' | 'smalldatetime' | 'timestamp' | 'timestamptz' | 'time' | 'timetz';
846
+ type SqlJsonTypes = 'json' | 'jsonb';
847
+ type SqlBufferTypes = 'blob' | 'tinyblob' | 'mediumblob' | 'longblob' | 'binary' | 'varbinary' | 'bytea' | 'bytes' | 'image' | 'raw';
848
+ type SqlTypeMap = {
849
+ [K in SqlStringTypes]: string;
850
+ } & {
851
+ [K in SqlNumberTypes]: number;
852
+ } & {
853
+ [K in SqlBooleanTypes]: boolean;
854
+ } & {
855
+ [K in SqlDateTypes]: Date;
856
+ } & {
857
+ [K in SqlJsonTypes]: Dictionary;
858
+ } & {
859
+ [K in SqlBufferTypes]: Buffer;
860
+ } & {
861
+ 'character varying': string;
862
+ 'double precision': number;
863
+ 'time with time zone': Date;
864
+ 'timestamp with time zone': Date;
865
+ 'long raw': Buffer;
866
+ };
867
+ type LookupSqlType<K> = K extends keyof SqlTypeMap ? SqlTypeMap[K] : any;
868
+ /**
869
+ * Maps a SQL-flavoured `type` string (e.g. `'varchar(255)'`, `'int'`, `'timestamp'`) to a TS
870
+ * runtime type, used as a fallback when {@link RoutineParamConfig} does not declare an explicit
871
+ * `runtimeType`. Length/precision arguments are stripped, the lowercase token is matched
872
+ * against {@link SqlTypeMap}. `decimal`/`numeric`/`money`/`bigint` default to `string` since
873
+ * drivers typically return them as strings to preserve precision; opt in to `number` or
874
+ * `bigint` via `runtimeType` when the value range is safe. Unrecognised or genuinely
875
+ * ambiguous types (`refcursor`, `sys_refcursor`, …) fall through to `any`.
876
+ */
877
+ export type SqlTypeToTs<S> = S extends string ? Lowercase<S> extends `tinyint(1)${string}` ? boolean : LookupSqlType<StripSqlTypeArgs<Lowercase<S>>> : any;
878
+ /** Strips `null | undefined` from a `Type<JSType, _>` JSType, so e.g. `StringType extends Type<string | null | undefined>` resolves to `string`. */
879
+ type TypeJsType<T> = T extends Type<infer J, any> ? Exclude<J, null | undefined> : T extends new (...args: any[]) => Type<infer J, any> ? Exclude<J, null | undefined> : never;
880
+ /**
881
+ * TS value type for a single routine parameter. Resolution order:
882
+ *
883
+ * 1. explicit `runtimeType`
884
+ * 2. `type` set to a {@link Type} class or instance — JSType is extracted from the Type generic
885
+ * 3. `type` set to a SQL string — mapped via {@link SqlTypeToTs}
886
+ * 4. fallback `any`
887
+ *
888
+ * `ref: true` wraps the result in `ScalarReference`; `nullable: true` adds `| null`.
889
+ */
890
+ export type RoutineParamValue<P> = P extends {
891
+ runtimeType: infer R;
892
+ } ? P extends {
893
+ ref: true;
894
+ } ? ScalarReference<Nullify<P, RoutineRuntimeOf<R>>> : Nullify<P, RoutineRuntimeOf<R>> : P extends {
895
+ type: infer T;
896
+ } ? [TypeJsType<T>] extends [never] ? T extends string ? P extends {
897
+ ref: true;
898
+ } ? ScalarReference<Nullify<P, SqlTypeToTs<T>>> : Nullify<P, SqlTypeToTs<T>> : P extends {
899
+ ref: true;
900
+ } ? ScalarReference<any> : any : P extends {
901
+ ref: true;
902
+ } ? ScalarReference<Nullify<P, TypeJsType<T>>> : Nullify<P, TypeJsType<T>> : P extends {
903
+ ref: true;
904
+ } ? ScalarReference<any> : any;
905
+ /** Default `TArgs` for {@link Routine}; consumers use {@link RoutineArgs}, which honours overrides from {@link Routine.create}. */
906
+ export type RoutineArgsOf<Config> = Config extends {
907
+ params: infer P;
908
+ } ? P extends Record<string, RoutineParamConfig> ? {
909
+ [K in keyof P]: RoutineParamValue<P[K]>;
910
+ } : Record<string, unknown> : Record<string, unknown>;
911
+ /** Default `TReturn` for {@link Routine}; consumers use {@link RoutineReturn}, which honours overrides from {@link Routine.create}. */
912
+ export type RoutineReturnOf<Config> = Config extends {
913
+ returns: infer R;
914
+ } ? R extends {
915
+ runtimeType: infer RT;
916
+ } ? Nullify<R, RoutineRuntimeOf<RT>> : R extends {
917
+ type: infer T;
918
+ } ? [TypeJsType<T>] extends [never] ? unknown : Nullify<R, TypeJsType<T>> : R extends readonly (() => EntityName<any>)[] ? {
919
+ [K in keyof R]: R[K] extends () => EntityName<infer E> ? E[] : never;
920
+ } : R extends () => EntityName<infer E> ? E[] : R extends {
921
+ hydrate: (...args: any[]) => infer H;
922
+ } ? Awaited<H> : void : void;
923
+ export type RoutineArgs<R> = R extends Routine<any, infer A, any> ? A : Record<string, unknown>;
924
+ export type RoutineReturn<R> = R extends Routine<any, any, infer Re> ? Re : unknown;
617
925
  /** Branded string that accepts any string value while preserving autocompletion for known literals. */
618
926
  export type AnyString = string & {};
619
927
  /** Describes a single property (column, relation, or embedded) within an entity's metadata. */
@@ -711,11 +1019,12 @@ export interface EntityProperty<Owner = any, Target = any> {
711
1019
  serializer?: (value: any, options?: SerializeOptions<any>) => any;
712
1020
  serializedName?: string;
713
1021
  comment?: string;
1022
+ collation?: string;
714
1023
  /** mysql only */
715
1024
  extra?: string;
716
1025
  userDefined?: boolean;
717
1026
  optional?: boolean;
718
- ignoreSchemaChanges?: ('type' | 'extra' | 'default')[];
1027
+ ignoreSchemaChanges?: ('type' | 'extra' | 'default' | 'collation')[];
719
1028
  deferMode?: DeferMode;
720
1029
  createForeignKeyConstraint: boolean;
721
1030
  foreignKeyName?: string;
@@ -743,8 +1052,12 @@ export declare class EntityMetadata<Entity = any, Class extends EntityCtor<Entit
743
1052
  /**
744
1053
  * Creates a column mapping for schema callbacks (indexes, checks, generated columns).
745
1054
  * For TPT entities, only includes properties that belong to the current table (ownProps).
1055
+ * Embedded properties expose their sub-columns via nested access (e.g. `cols.address.city`),
1056
+ * while still coercing to the embedded column prefix when used as a string (GH #7712).
746
1057
  */
747
1058
  createSchemaColumnMappingObject(): SchemaColumns<Entity>;
1059
+ /** @internal Recursively builds a column mapping for an embedded property's sub-columns. */
1060
+ private static buildEmbeddedColumnMapping;
748
1061
  get tableName(): string;
749
1062
  set tableName(name: string);
750
1063
  get uniqueName(): string;
@@ -763,7 +1076,6 @@ export type EntityCtor<T = any> = abstract new (...args: any[]) => T;
763
1076
  export interface EntityMetadata<Entity = any, Class extends EntityCtor<Entity> = EntityCtor<Entity>> {
764
1077
  name?: string;
765
1078
  className: string;
766
- tableName: string;
767
1079
  schema?: string;
768
1080
  pivotTable?: boolean;
769
1081
  virtual?: boolean;
@@ -776,8 +1088,15 @@ export interface EntityMetadata<Entity = any, Class extends EntityCtor<Entity> =
776
1088
  materialized?: boolean;
777
1089
  /** For materialized views, whether data is populated on creation. Defaults to true. */
778
1090
  withData?: boolean;
1091
+ /** PostgreSQL partitioning definition for this table. */
1092
+ partitionBy?: EntityPartitionBy<Entity>;
779
1093
  expression?: string | ((em: any, where: ObjectQuery<Entity>, options: FindOptions<Entity, any, any, any>, stream?: boolean) => MaybePromise<Raw | object | string>);
1094
+ /** Property name on the entity that stores the discriminator value. */
1095
+ discriminator?: EntityKey<Entity> | AnyString;
1096
+ /** Internally holds the discriminator property name (legacy) or a column-name override (when different from `discriminator`); normalized in `EntitySchema.init()`. */
780
1097
  discriminatorColumn?: EntityKey<Entity> | AnyString;
1098
+ /** Explicit column-name override for the auto-managed discriminator property. Set when both `discriminator` and `discriminatorColumn` are provided and differ. */
1099
+ discriminatorFieldName?: string;
781
1100
  discriminatorValue?: number | string;
782
1101
  discriminatorMap?: Dictionary<EntityClass>;
783
1102
  embeddable: boolean;
@@ -814,6 +1133,7 @@ export interface EntityMetadata<Entity = any, Class extends EntityCtor<Entity> =
814
1133
  type?: string;
815
1134
  options?: Dictionary;
816
1135
  expression?: string | IndexCallback<Entity>;
1136
+ where?: string | FilterQuery<Entity>;
817
1137
  columns?: IndexColumnOptions[];
818
1138
  include?: EntityKey<Entity> | EntityKey<Entity>[];
819
1139
  fillFactor?: number;
@@ -826,6 +1146,7 @@ export interface EntityMetadata<Entity = any, Class extends EntityCtor<Entity> =
826
1146
  name?: string;
827
1147
  options?: Dictionary;
828
1148
  expression?: string | IndexCallback<Entity>;
1149
+ where?: string | FilterQuery<Entity>;
829
1150
  deferMode?: DeferMode | `${DeferMode}`;
830
1151
  columns?: IndexColumnOptions[];
831
1152
  include?: EntityKey<Entity> | EntityKey<Entity>[];
@@ -833,6 +1154,7 @@ export interface EntityMetadata<Entity = any, Class extends EntityCtor<Entity> =
833
1154
  disabled?: boolean;
834
1155
  }[];
835
1156
  checks: CheckConstraint<Entity>[];
1157
+ triggers: TriggerDef<Entity>[];
836
1158
  repositoryClass?: string;
837
1159
  repository: () => EntityClass<EntityRepository<any>>;
838
1160
  hooks: {
@@ -853,6 +1175,8 @@ export interface EntityMetadata<Entity = any, Class extends EntityCtor<Entity> =
853
1175
  polymorphicDiscriminatorMap?: Dictionary<EntityClass>;
854
1176
  /** Inheritance type: 'sti' (Single Table Inheritance) or 'tpt' (Table-Per-Type). Only set on root entities. */
855
1177
  inheritanceType?: 'sti' | 'tpt';
1178
+ /** Legacy alias populated from `EntityOptions.inheritance`; mirrored to `inheritanceType` during discovery. */
1179
+ inheritance?: 'tpt';
856
1180
  /** For TPT: direct parent entity metadata (the entity this one extends). */
857
1181
  tptParent?: EntityMetadata;
858
1182
  /** For TPT: direct child entities (entities that extend this one). */
@@ -880,6 +1204,11 @@ export interface EntityMetadata<Entity = any, Class extends EntityCtor<Entity> =
880
1204
  export interface CreateSchemaOptions {
881
1205
  wrap?: boolean;
882
1206
  schema?: string;
1207
+ /**
1208
+ * When true, entities with a wildcard schema (`schema: '*'`) are included in the generated DDL.
1209
+ * Without this, wildcard tables are skipped.
1210
+ */
1211
+ includeWildcardSchema?: boolean;
883
1212
  }
884
1213
  /** Options for `ISchemaGenerator.clear()` to truncate/clear database tables. */
885
1214
  export interface ClearDatabaseOptions {
@@ -909,6 +1238,13 @@ export interface UpdateSchemaOptions<DatabaseSchema = unknown> {
909
1238
  dropTables?: boolean;
910
1239
  schema?: string;
911
1240
  fromSchema?: DatabaseSchema;
1241
+ /**
1242
+ * When true, entities with a wildcard schema (`schema: '*'`) are included in the diff so migrations
1243
+ * can be generated for them. The emitted SQL is unqualified — and therefore safe to apply against
1244
+ * any schema at runtime — only when neither `options.schema` nor `config.schema` is set; otherwise
1245
+ * wildcard tables inherit that schema qualifier.
1246
+ */
1247
+ includeWildcardSchema?: boolean;
912
1248
  }
913
1249
  /** Options for `ISchemaGenerator.refresh()` which drops and recreates the schema. */
914
1250
  export interface RefreshDatabaseOptions extends CreateSchemaOptions {
@@ -989,6 +1325,12 @@ export type MigrateOptions = {
989
1325
  to?: string | number;
990
1326
  migrations?: string[];
991
1327
  transaction?: Transaction;
1328
+ /**
1329
+ * Target schema to run migrations against. Issues a driver-specific "set current schema"
1330
+ * statement (e.g. `SET search_path` on PostgreSQL) before each migration, and places the
1331
+ * tracking table in this schema. Overrides `migrations.schema` from config. Not supported on MSSQL.
1332
+ */
1333
+ schema?: string;
992
1334
  };
993
1335
  /** Result of creating a new migration file, including the generated code and schema diff. */
994
1336
  export type MigrationResult = {
@@ -1006,21 +1348,25 @@ export type MigrationRow = {
1006
1348
  * @internal
1007
1349
  */
1008
1350
  export interface IMigrationRunner {
1009
- run(migration: Migration, method: 'up' | 'down'): Promise<void>;
1351
+ run(migration: Migration, method: 'up' | 'down', afterRun?: (tx?: Transaction) => Promise<void>): Promise<void>;
1010
1352
  setMasterMigration(trx: Transaction): void;
1011
1353
  unsetMasterMigration(): void;
1354
+ setRunSchema?(schema?: string): void;
1355
+ unsetRunSchema?(): void;
1012
1356
  }
1013
1357
  /**
1014
1358
  * @internal
1015
1359
  */
1016
1360
  export interface IMigratorStorage {
1017
1361
  executed(): Promise<string[]>;
1018
- logMigration(params: Dictionary): Promise<void>;
1019
- unlogMigration(params: Dictionary): Promise<void>;
1362
+ logMigration(params: Dictionary, tx?: Transaction): Promise<void>;
1363
+ unlogMigration(params: Dictionary, tx?: Transaction): Promise<void>;
1020
1364
  getExecutedMigrations(): Promise<MigrationRow[]>;
1021
1365
  ensureTable?(): Promise<void>;
1022
1366
  setMasterMigration(trx: Transaction): void;
1023
1367
  unsetMasterMigration(): void;
1368
+ setRunSchema?(schema?: string): void;
1369
+ unsetRunSchema?(): void;
1024
1370
  getMigrationName(name: string): string;
1025
1371
  getTableName?(): {
1026
1372
  schemaName?: string;
@@ -1047,11 +1393,15 @@ export interface IMigrator {
1047
1393
  /**
1048
1394
  * Returns list of already executed migrations.
1049
1395
  */
1050
- getExecuted(): Promise<MigrationRow[]>;
1396
+ getExecuted(options?: {
1397
+ schema?: string;
1398
+ }): Promise<MigrationRow[]>;
1051
1399
  /**
1052
1400
  * Returns list of pending (not yet executed) migrations found in the migration directory.
1053
1401
  */
1054
- getPending(): Promise<MigrationInfo[]>;
1402
+ getPending(options?: {
1403
+ schema?: string;
1404
+ }): Promise<MigrationInfo[]>;
1055
1405
  /**
1056
1406
  * Executes specified migrations. Without parameter it will migrate up to the latest version.
1057
1407
  */
@@ -1060,6 +1410,11 @@ export interface IMigrator {
1060
1410
  * Executes down migrations to the given point. Without parameter it will migrate one version down.
1061
1411
  */
1062
1412
  down(options?: string | string[] | Omit<MigrateOptions, 'from'>): Promise<MigrationInfo[]>;
1413
+ /**
1414
+ * Combines multiple executed migrations into a single migration file.
1415
+ * Concatenates source code without touching the database schema.
1416
+ */
1417
+ rollup(migrations?: string[]): Promise<MigrationResult>;
1063
1418
  /**
1064
1419
  * Registers event handler.
1065
1420
  */
@@ -1142,13 +1497,32 @@ export type PopulateOptions<T> = {
1142
1497
  children?: PopulateOptions<T[keyof T]>[];
1143
1498
  /** When true, ignores `mapToPk` on the property and returns full entity data instead of just PKs. */
1144
1499
  dataOnly?: boolean;
1500
+ /** Limit the number of items loaded per parent entity. Collections will be marked as partial and readonly. */
1501
+ limit?: number;
1502
+ /** Offset for per-parent limiting (used with `limit`). */
1503
+ offset?: number;
1504
+ /** Order by clause for per-parent limiting. Takes precedence over nested `FindOptions.orderBy`. */
1505
+ orderBy?: QueryOrderMap<T[keyof T]>;
1145
1506
  };
1146
1507
  /** Inline options that can be appended to populate hint strings (e.g., strategy, join type). */
1147
1508
  export type PopulateHintOptions = {
1148
1509
  strategy?: LoadStrategy.JOINED | LoadStrategy.SELECT_IN | 'joined' | 'select-in';
1149
1510
  joinType?: 'inner join' | 'left join';
1511
+ /** Limit the number of items loaded per parent entity. Collections will be marked as partial and readonly. */
1512
+ limit?: number;
1513
+ /** Offset for per-parent limiting (used with `limit`). */
1514
+ offset?: number;
1515
+ /** Order by clause for per-parent limiting. Takes precedence over nested `FindOptions.orderBy`. */
1516
+ orderBy?: QueryOrderMap<any>;
1150
1517
  };
1151
1518
  type ExtractType<T> = T extends CollectionShape<infer U> ? U : T extends ReferenceShape<infer U> ? U : T extends Ref<infer U> ? U : T extends readonly (infer U)[] ? U : T;
1519
+ /**
1520
+ * Like {@link ExtractType} but also unwraps {@link LazyRef}. Kept separate so {@link ExtractType}'s
1521
+ * hot path (used by `IsOptional`, `EntityData`, `RequiredEntityData`) doesn't pay the cost of the
1522
+ * extra branch — those contexts handle `LazyRef` in their own earlier branches (see
1523
+ * `EntityDataProp` / `RequiredEntityDataProp`) before delegating to `ExtractType`.
1524
+ */
1525
+ type ExtractTypeWithLazyRef<T> = T extends LazyRef.Brand<infer U> ? U : ExtractType<T>;
1152
1526
  type ExtractStringKeys<T> = {
1153
1527
  [K in keyof T]-?: CleanKeys<T, K>;
1154
1528
  }[keyof T] & {};
@@ -1156,8 +1530,8 @@ type ExtractStringKeys<T> = {
1156
1530
  * Extracts string keys from an entity type, handling Collection/Reference wrappers.
1157
1531
  * Simplified to just check `T extends object` since ExtractType handles the unwrapping.
1158
1532
  */
1159
- type StringKeys<T, E extends string = never> = T extends object ? ExtractStringKeys<ExtractType<T>> | E : never;
1160
- type GetStringKey<T, K extends StringKeys<T, string>, E extends string> = K extends keyof T ? ExtractType<T[K]> : K extends E ? keyof T : never;
1533
+ type StringKeys<T, E extends string = never> = T extends object ? ExtractStringKeys<ExtractTypeWithLazyRef<T>> | E : never;
1534
+ type GetStringKey<T, K extends StringKeys<T, string>, E extends string> = K extends keyof T ? ExtractTypeWithLazyRef<T[K]> : K extends E ? keyof T : never;
1161
1535
  type Prev = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
1162
1536
  type RelationKeys<T> = T extends object ? {
1163
1537
  [K in keyof T]-?: CleanKeys<T, K, true>;
@@ -1172,8 +1546,8 @@ export type UnboxArray<T> = T extends any[] ? ArrayElement<T> : T;
1172
1546
  /** Extracts the element type from an array type. */
1173
1547
  export type ArrayElement<ArrayType extends unknown[]> = ArrayType extends (infer ElementType)[] ? ElementType : never;
1174
1548
  /** Unwraps a property type from its wrapper (Reference, Collection, or array) to the inner entity type. */
1175
- export type ExpandProperty<T> = T extends ReferenceShape<infer U> ? NonNullable<U> : T extends CollectionShape<infer U> ? NonNullable<U> : T extends (infer U)[] ? NonNullable<U> : NonNullable<T>;
1176
- type LoadedLoadable<T, E extends object> = T extends CollectionShape ? LoadedCollection<E> : T extends ScalarReference<infer U> ? LoadedScalarReference<U> : T extends ReferenceShape ? T & LoadedReference<E> : T extends Scalar ? T : T extends (infer U)[] ? U extends Scalar ? T : E[] : E;
1549
+ export type ExpandProperty<T> = T extends LazyRef.Brand<infer U> ? NonNullable<U> : T extends ReferenceShape<infer U> ? NonNullable<U> : T extends CollectionShape<infer U> ? NonNullable<U> : T extends (infer U)[] ? NonNullable<U> : NonNullable<T>;
1550
+ type LoadedLoadable<T, E extends object> = T extends CollectionShape ? LoadedCollection<E> : T extends ScalarReference<infer U> ? LoadedScalarReference<U> : T extends LazyRef.Brand<any> ? E : T extends ReferenceShape ? T & LoadedReference<E> : T extends Scalar ? T : T extends (infer U)[] ? U extends Scalar ? T : E[] : E;
1177
1551
  type IsTrue<T> = IsNever<T> extends true ? false : T extends boolean ? (T extends true ? true : false) : false;
1178
1552
  type StringLiteral<T> = T extends string ? (string extends T ? never : T) : never;
1179
1553
  type Prefix<T, K> = K extends `${infer S}.${string}` ? S : K extends '*' ? keyof T : K;
@@ -1207,7 +1581,7 @@ export type MergeSelected<T, U, F extends string> = IsLoadedType<T> extends true
1207
1581
  export type MergeLoaded<T, U, P extends string, F extends string, E extends string, R extends boolean = false> = IsLoadedType<T> extends true ? T & Loaded<U, P, F, E> : Loaded<T, P, F, E>;
1208
1582
  /** Extracts the nullability modifiers (`null`, `undefined`, or both) from a type `T`. */
1209
1583
  export type AddOptional<T> = undefined | null extends T ? null | undefined : null extends T ? null : undefined extends T ? undefined : never;
1210
- type LoadedProp<T, L extends string = never, F extends string = '*', E extends string = never> = LoadedLoadable<T, Loaded<ExtractType<T>, L, F, E>>;
1584
+ type LoadedProp<T, L extends string = never, F extends string = '*', E extends string = never> = LoadedLoadable<T, Loaded<ExtractTypeWithLazyRef<T>, L, F, E>>;
1211
1585
  /** Extracts the eager-loaded property names declared via `[EagerProps]` as a string union. */
1212
1586
  export type AddEager<T> = ExtractEagerProps<T> & string;
1213
1587
  /** Combines an explicit populate hint `L` with the entity's eagerly loaded properties. */
@@ -1322,15 +1696,18 @@ export type MaybeReturnType<T> = T extends (...args: any[]) => infer R ? R : T;
1322
1696
  * Extended `EntitySchema` interface that carries additional type-level metadata (entity name, properties, table name).
1323
1697
  * Returned by `defineEntity()` to provide strong type inference without explicit generics.
1324
1698
  */
1325
- export interface EntitySchemaWithMeta<TName extends string = string, TTableName extends string = string, TEntity = any, TBase = never, TProperties extends Record<string, any> = Record<string, any>, TClass extends EntityCtor = EntityCtor<TEntity>> extends EntitySchema<TEntity, TBase, TClass> {
1699
+ export interface EntitySchemaWithMeta<TName extends string = string, TTableName extends string = string, TEntity = any, TBase = never, TProperties extends Record<string, any> = Record<string, any>, TClass extends EntityCtor = EntityCtor<TEntity>, TDiscriminatorColumn extends string | undefined = undefined> extends EntitySchema<TEntity, TBase, TClass> {
1326
1700
  readonly name: TName;
1327
1701
  readonly properties: TProperties;
1328
1702
  readonly tableName: TTableName;
1329
1703
  /** @internal Direct entity type access - avoids expensive pattern matching */
1330
1704
  readonly '~entity': TEntity;
1705
+ /** @internal Type-level marker carrying the discriminator column name, used by `defineEntity()` to narrow inherited discriminator properties to the literal `discriminatorValue` of each child schema. */
1706
+ readonly '~discriminatorColumn'?: TDiscriminatorColumn;
1331
1707
  /** @internal */
1332
1708
  readonly class: TClass & {
1333
1709
  '~entityName'?: TName;
1710
+ '~discriminatorColumn'?: TDiscriminatorColumn;
1334
1711
  };
1335
1712
  }
1336
1713
  /**