diff --git a/packages/core/types/src/dml/index.ts b/packages/core/types/src/dml/index.ts index 0414cac04b..5a9eb5f109 100644 --- a/packages/core/types/src/dml/index.ts +++ b/packages/core/types/src/dml/index.ts @@ -121,33 +121,71 @@ export interface EntityConstructor extends Function { * From a IDmlEntity, infer the foreign keys name and type for * "belongsTo" relation meaning "hasOne" and "ManyToOne" */ -export type InferForeignKeys = T extends IDmlEntity - ? { - [K in keyof Schema as Schema[K] extends { type: infer Type } - ? Type extends RelationshipTypes - ? `${K & string}_id` - : K - : K]: Schema[K] extends { type: infer Type } - ? Type extends RelationshipTypes - ? string - : Schema[K] - : Schema[K] - } +export type InferForeignKeys = { + [K in keyof Schema as Schema[K] extends { type: infer Type } + ? Type extends RelationshipTypes + ? `${K & string}_id` + : K + : K]: Schema[K] extends { type: infer Type } + ? Type extends RelationshipTypes + ? string + : Schema[K] + : Schema[K] +} + +/** + * Infer fields for a belongsTo relationship + */ +export type InferBelongsToFields = Relation extends () => IDmlEntity< + infer R +> + ? InferSchemaFields + : Relation extends () => IDmlEntity | null + ? InferSchemaFields | null : never +/** + * Infer fields for a hasOne relationship + */ +export type InferHasOneFields = InferBelongsToFields + +/** + * Infer fields for hasMany relationship + */ +export type InferHasManyFields = Relation extends () => IDmlEntity< + infer R +> + ? InferSchemaFields[] + : never + +/** + * Infer fields for manyToMany relationship + */ +export type InferManyToManyFields = InferHasManyFields + +/** + * Inferring the types of the schema fields from the DML + * entity + */ +export type InferSchemaFields = { + [K in keyof Schema]: Schema[K] extends RelationshipType + ? Schema[K]["type"] extends "belongsTo" + ? InferBelongsToFields + : Schema[K]["type"] extends "hasOne" + ? InferHasOneFields + : Schema[K]["type"] extends "hasMany" + ? InferHasManyFields + : Schema[K]["type"] extends "manyToMany" + ? InferManyToManyFields + : never + : Schema[K]["$dataType"] +} + /** * Helper to infer the schema type of a DmlEntity */ export type Infer = T extends IDmlEntity - ? EntityConstructor< - { - [K in keyof Schema]: Schema[K]["$dataType"] extends () => infer R - ? Infer - : Schema[K]["$dataType"] extends (() => infer R) | null - ? Infer | null - : Schema[K]["$dataType"] - } & InferForeignKeys - > + ? EntityConstructor> : never /** @@ -200,7 +238,7 @@ export type InferIndexableProperties = keyof (T extends IDmlEntity< ? never : K : K]: string - } & InferForeignKeys + } & InferForeignKeys : never) export type EntityIndex< diff --git a/packages/core/utils/src/dml/__tests__/entity-builder.spec.ts b/packages/core/utils/src/dml/__tests__/entity-builder.spec.ts index db606528cf..1b28265f4e 100644 --- a/packages/core/utils/src/dml/__tests__/entity-builder.spec.ts +++ b/packages/core/utils/src/dml/__tests__/entity-builder.spec.ts @@ -1,4 +1,3 @@ -import { EntityConstructor } from "@medusajs/types" import { ArrayType, MetadataStorage } from "@mikro-orm/core" import { expectTypeOf } from "expect-type" import { DmlEntity } from "../entity" @@ -77,7 +76,6 @@ describe("Entity builder", () => { expect(user.parse().tableName).toEqual("user") const User = toMikroORMEntity(user) - expectTypeOf(new User()).toMatchTypeOf<{ id: number username: string @@ -1808,15 +1806,20 @@ describe("Entity builder", () => { }) const User = toMikroORMEntity(user) - expectTypeOf(new User()).toMatchTypeOf<{ + + expectTypeOf(new User()).toEqualTypeOf<{ id: number username: string + created_at: Date + updated_at: Date deleted_at: Date | null - email: EntityConstructor<{ + email: { email: string isVerified: boolean + created_at: Date + updated_at: Date deleted_at: Date | null - }> + } }>() const metaData = MetadataStorage.getMetadataFromDecorator(User) @@ -1901,11 +1904,11 @@ describe("Entity builder", () => { id: number username: string deleted_at: Date | null - emails: EntityConstructor<{ + emails: { email: string isVerified: boolean deleted_at: Date | null - }> | null + } | null }>() const metaData = MetadataStorage.getMetadataFromDecorator(User) @@ -1988,7 +1991,7 @@ describe("Entity builder", () => { expectTypeOf(new User()).toMatchTypeOf<{ id: number username: string - email: EntityConstructor<{ email: string; isVerified: boolean }> + email: { email: string; isVerified: boolean } }>() const metaData = MetadataStorage.getMetadataFromDecorator(User) @@ -2075,7 +2078,7 @@ describe("Entity builder", () => { expectTypeOf(new User()).toMatchTypeOf<{ id: number username: string - email: EntityConstructor<{ email: string; isVerified: boolean }> + email: { email: string; isVerified: boolean } }>() const metaData = MetadataStorage.getMetadataFromDecorator(User) @@ -2221,14 +2224,14 @@ describe("Entity builder", () => { expectTypeOf(new User()).toMatchTypeOf<{ id: number username: string - email: EntityConstructor<{ + email: { email: string isVerified: boolean - user: EntityConstructor<{ + user: { id: number username: string - }> - }> + } + } }>() const metaData = MetadataStorage.getMetadataFromDecorator(User) @@ -2661,7 +2664,7 @@ describe("Entity builder", () => { expectTypeOf(new User()).toMatchTypeOf<{ id: number username: string - emails: EntityConstructor<{ email: string; isVerified: boolean }> + emails: { email: string; isVerified: boolean }[] }>() const metaData = MetadataStorage.getMetadataFromDecorator(User) @@ -2747,7 +2750,7 @@ describe("Entity builder", () => { expectTypeOf(new User()).toMatchTypeOf<{ id: number username: string - emails: EntityConstructor<{ email: string; isVerified: boolean }> | null + emails: { email: string; isVerified: boolean }[] }>() const metaData = MetadataStorage.getMetadataFromDecorator(User) @@ -2834,7 +2837,7 @@ describe("Entity builder", () => { expectTypeOf(new User()).toMatchTypeOf<{ id: number username: string - emails: EntityConstructor<{ email: string; isVerified: boolean }> + emails: { email: string; isVerified: boolean }[] }>() const metaData = MetadataStorage.getMetadataFromDecorator(User) @@ -2924,7 +2927,7 @@ describe("Entity builder", () => { expectTypeOf(new User()).toMatchTypeOf<{ id: number username: string - emails: EntityConstructor<{ email: string; isVerified: boolean }> + emails: { email: string; isVerified: boolean }[] }>() const metaData = MetadataStorage.getMetadataFromDecorator(User) @@ -3087,32 +3090,32 @@ describe("Entity builder", () => { id: number username: string deleted_at: Date | null - email: EntityConstructor<{ + email: { email: string isVerified: boolean deleted_at: Date | null - user: EntityConstructor<{ + user: { id: number username: string deleted_at: Date | null - }> - }> + } + } }>() expectTypeOf(new Email()).toMatchTypeOf<{ email: string isVerified: boolean deleted_at: Date | null - user: EntityConstructor<{ + user: { id: number username: string deleted_at: Date | null - email: EntityConstructor<{ + email: { email: string isVerified: boolean deleted_at: Date | null - }> - }> + } + } }>() const metaData = MetadataStorage.getMetadataFromDecorator(User) @@ -3272,27 +3275,27 @@ describe("Entity builder", () => { expectTypeOf(new User()).toMatchTypeOf<{ id: number username: string - email: EntityConstructor<{ + email: { email: string isVerified: boolean - user: EntityConstructor<{ + user: { id: number username: string - }> | null - }> + } | null + } }>() expectTypeOf(new Email()).toMatchTypeOf<{ email: string isVerified: boolean - user: EntityConstructor<{ + user: { id: number username: string - email: EntityConstructor<{ + email: { email: string isVerified: boolean - }> - }> | null + } + } | null }>() const metaData = MetadataStorage.getMetadataFromDecorator(User) @@ -3452,27 +3455,27 @@ describe("Entity builder", () => { expectTypeOf(new User()).toMatchTypeOf<{ id: number username: string - emails: EntityConstructor<{ + emails: { email: string isVerified: boolean - user: EntityConstructor<{ + user: { id: number username: string - }> - }> + } + }[] }>() expectTypeOf(new Email()).toMatchTypeOf<{ email: string isVerified: boolean - user: EntityConstructor<{ + user: { id: number username: string - emails: EntityConstructor<{ + emails: { email: string isVerified: boolean - }> - }> + }[] + } }>() const metaData = MetadataStorage.getMetadataFromDecorator(User) @@ -3631,27 +3634,27 @@ describe("Entity builder", () => { expectTypeOf(new User()).toMatchTypeOf<{ id: number username: string - emails: EntityConstructor<{ + emails: { email: string isVerified: boolean - user: EntityConstructor<{ + user: { id: number username: string - }> | null - }> + } | null + }[] }>() expectTypeOf(new Email()).toMatchTypeOf<{ email: string isVerified: boolean - user: EntityConstructor<{ + user: { id: number username: string - emails: EntityConstructor<{ + emails: { email: string isVerified: boolean - }> - }> | null + }[] + } | null }>() const metaData = MetadataStorage.getMetadataFromDecorator(User) @@ -3869,32 +3872,32 @@ describe("Entity builder", () => { id: number username: string deleted_at: Date | null - email: EntityConstructor<{ + email: { email: string isVerified: boolean deleted_at: Date | null - user: EntityConstructor<{ + user: { id: number username: string deleted_at: Date | null - }> - }> + } + } }>() expectTypeOf(new Email()).toMatchTypeOf<{ email: string isVerified: boolean deleted_at: Date | null - user: EntityConstructor<{ + user: { id: number username: string deleted_at: Date | null - email: EntityConstructor<{ + email: { email: string isVerified: boolean deleted_at: Date | null - }> - }> + } + } }>() const metaData = MetadataStorage.getMetadataFromDecorator(User) @@ -4057,32 +4060,32 @@ describe("Entity builder", () => { id: number username: string deleted_at: Date | null - email: EntityConstructor<{ + email: { email: string isVerified: boolean deleted_at: Date | null - user: EntityConstructor<{ + user: { id: number username: string deleted_at: Date | null - }> - }> + } + } }>() expectTypeOf(new Email()).toMatchTypeOf<{ email: string isVerified: boolean deleted_at: Date | null - user: EntityConstructor<{ + user: { id: number username: string deleted_at: Date | null - email: EntityConstructor<{ + email: { email: string isVerified: boolean deleted_at: Date | null - }> - }> + } + } }>() const metaData = MetadataStorage.getMetadataFromDecorator(User) @@ -4246,27 +4249,27 @@ describe("Entity builder", () => { expectTypeOf(new User()).toMatchTypeOf<{ id: number username: string - teams: EntityConstructor<{ + teams: { id: number name: string - users: EntityConstructor<{ + users: { id: number username: string - }> - }> + }[] + }[] }>() expectTypeOf(new Team()).toMatchTypeOf<{ id: number name: string - users: EntityConstructor<{ + users: { id: number username: string - teams: EntityConstructor<{ + teams: { id: number name: string - }> - }> + }[] + }[] }>() const metaData = MetadataStorage.getMetadataFromDecorator(User) @@ -4413,27 +4416,27 @@ describe("Entity builder", () => { expectTypeOf(new User()).toMatchTypeOf<{ id: number username: string - teams: EntityConstructor<{ + teams: { id: number name: string - users: EntityConstructor<{ + users: { id: number username: string - }> - }> + }[] + }[] }>() expectTypeOf(new Team()).toMatchTypeOf<{ id: number name: string - users: EntityConstructor<{ + users: { id: number username: string - teams: EntityConstructor<{ + teams: { id: number name: string - }> - }> + }[] + }[] }>() const metaData = MetadataStorage.getMetadataFromDecorator(User) @@ -4615,27 +4618,27 @@ describe("Entity builder", () => { expectTypeOf(new User()).toMatchTypeOf<{ id: number username: string - teams: EntityConstructor<{ + teams: { id: number name: string - users: EntityConstructor<{ + users: { id: number username: string - }> - }> + }[] + }[] }>() expectTypeOf(new Team()).toMatchTypeOf<{ id: number name: string - users: EntityConstructor<{ + users: { id: number username: string - teams: EntityConstructor<{ + teams: { id: number name: string - }> - }> + }[] + }[] }>() const metaData = MetadataStorage.getMetadataFromDecorator(User) @@ -4789,27 +4792,27 @@ describe("Entity builder", () => { expectTypeOf(new User()).toMatchTypeOf<{ id: number username: string - teams: EntityConstructor<{ + teams: { id: number name: string - users: EntityConstructor<{ + users: { id: number username: string - }> - }> + }[] + }[] }>() expectTypeOf(new Team()).toMatchTypeOf<{ id: number name: string - users: EntityConstructor<{ + users: { id: number username: string - teams: EntityConstructor<{ + teams: { id: number name: string - }> - }> + }[] + }[] }>() const metaData = MetadataStorage.getMetadataFromDecorator(User) @@ -4969,39 +4972,39 @@ describe("Entity builder", () => { expectTypeOf(new User()).toMatchTypeOf<{ id: number username: string - teams: EntityConstructor<{ + teams: { id: number name: string - users: EntityConstructor<{ + users: { id: number username: string - }> - }> - activeTeams: EntityConstructor<{ + }[] + }[] + activeTeams: { id: number name: string - users: EntityConstructor<{ + users: { id: number username: string - }> - }> + }[] + }[] }>() expectTypeOf(new Team()).toMatchTypeOf<{ id: number name: string - users: EntityConstructor<{ + users: { id: number username: string - teams: EntityConstructor<{ + teams: { id: number name: string - }> - activeTeams: EntityConstructor<{ + }[] + activeTeams: { id: number name: string - }> - }> + }[] + }[] }>() const metaData = MetadataStorage.getMetadataFromDecorator(User) @@ -5168,27 +5171,27 @@ describe("Entity builder", () => { expectTypeOf(new User()).toMatchTypeOf<{ id: number username: string - teams: EntityConstructor<{ + teams: { id: number name: string - users: EntityConstructor<{ + users: { id: number username: string - }> - }> + }[] + }[] }>() expectTypeOf(new Team()).toMatchTypeOf<{ id: number name: string - users: EntityConstructor<{ + users: { id: number username: string - teams: EntityConstructor<{ + teams: { id: number name: string - }> - }> + }[] + }[] }>() const metaData = MetadataStorage.getMetadataFromDecorator(User) @@ -5339,27 +5342,27 @@ describe("Entity builder", () => { expectTypeOf(new User()).toMatchTypeOf<{ id: number username: string - teams: EntityConstructor<{ + teams: { id: number name: string - users: EntityConstructor<{ + users: { id: number username: string - }> - }> + }[] + }[] }>() expectTypeOf(new Team()).toMatchTypeOf<{ id: number name: string - users: EntityConstructor<{ + users: { id: number username: string - teams: EntityConstructor<{ + teams: { id: number name: string - }> - }> + }[] + }[] }>() const metaData = MetadataStorage.getMetadataFromDecorator(User) @@ -5513,27 +5516,27 @@ describe("Entity builder", () => { expectTypeOf(new User()).toMatchTypeOf<{ id: number username: string - teams: EntityConstructor<{ + teams: { id: number name: string - users: EntityConstructor<{ + users: { id: number username: string - }> - }> + }[] + }[] }>() expectTypeOf(new Team()).toMatchTypeOf<{ id: number name: string - users: EntityConstructor<{ + users: { id: number username: string - teams: EntityConstructor<{ + teams: { id: number name: string - }> - }> + }[] + }[] }>() const squadMetaData = MetadataStorage.getMetadataFromDecorator(Squad) diff --git a/packages/core/utils/src/dml/helpers/create-mikro-orm-entity.ts b/packages/core/utils/src/dml/helpers/create-mikro-orm-entity.ts index 104984d88f..46dc5659b0 100644 --- a/packages/core/utils/src/dml/helpers/create-mikro-orm-entity.ts +++ b/packages/core/utils/src/dml/helpers/create-mikro-orm-entity.ts @@ -85,16 +85,14 @@ export function createMikrORMEntity() { * return the input idempotently * @param entity */ -export const toMikroORMEntity = ( - entity: T -): T extends DmlEntity ? Infer : T => { +export const toMikroORMEntity = (entity: T): Infer => { let mikroOrmEntity: T | EntityConstructor = entity if (DmlEntity.isDmlEntity(entity)) { mikroOrmEntity = createMikrORMEntity()(entity) } - return mikroOrmEntity as T extends DmlEntity ? Infer : T + return mikroOrmEntity as Infer } /** diff --git a/packages/core/utils/src/dml/relations/nullable.ts b/packages/core/utils/src/dml/relations/nullable.ts index dfa0f081f1..e5f7749d7e 100644 --- a/packages/core/utils/src/dml/relations/nullable.ts +++ b/packages/core/utils/src/dml/relations/nullable.ts @@ -16,7 +16,7 @@ export class NullableModifier> return !!modifier?.[IsNullableModifier] } - declare type: RelationshipType["type"] + declare type: Relation["type"] /** * A type-only property to infer the JavScript data-type