diff --git a/packages/core/utils/src/common/__tests__/create-psql-index-helper.ts b/packages/core/utils/src/common/__tests__/create-psql-index-helper.spec.ts similarity index 70% rename from packages/core/utils/src/common/__tests__/create-psql-index-helper.ts rename to packages/core/utils/src/common/__tests__/create-psql-index-helper.spec.ts index a275477716..f832da27a2 100644 --- a/packages/core/utils/src/common/__tests__/create-psql-index-helper.ts +++ b/packages/core/utils/src/common/__tests__/create-psql-index-helper.spec.ts @@ -89,4 +89,42 @@ describe("createPsqlIndexStatementHelper", function () { }" (${options.columns.join(", ")}) WHERE ${options.where}` ) }) + + it("should generate index on an explicit pg schema", function () { + const options = { + name: "index_name", + tableName: "public.table_name", + columns: "column_name", + } + + const indexStatement = createPsqlIndexStatementHelper(options) + expect(indexStatement + "").toEqual( + `CREATE INDEX IF NOT EXISTS "${options.name}" ON "public"."table_name" (${options.columns})` + ) + }) + + it("generate index name from table name when using explicit pg schema", function () { + const options = { + tableName: "public.table_name", + columns: "column_name", + } + + const indexStatement = createPsqlIndexStatementHelper(options) + expect(indexStatement + "").toEqual( + `CREATE INDEX IF NOT EXISTS "IDX_table_name_column_name" ON "public"."table_name" (${options.columns})` + ) + }) + + it("should generate index when table name was previously formatted to allow pg schema name", function () { + const options = { + name: "index_name", + tableName: 'public"."table_name', + columns: "column_name", + } + + const indexStatement = createPsqlIndexStatementHelper(options) + expect(indexStatement + "").toEqual( + `CREATE INDEX IF NOT EXISTS "${options.name}" ON "public"."table_name" (${options.columns})` + ) + }) }) diff --git a/packages/core/utils/src/common/create-psql-index-helper.ts b/packages/core/utils/src/common/create-psql-index-helper.ts index 524efcd8e1..b2b15436e8 100644 --- a/packages/core/utils/src/common/create-psql-index-helper.ts +++ b/packages/core/utils/src/common/create-psql-index-helper.ts @@ -31,7 +31,7 @@ import { Index } from "@mikro-orm/core" */ export function createPsqlIndexStatementHelper({ name, - tableName, + tableName: qualifiedName, columns, type, where, @@ -45,6 +45,20 @@ export function createPsqlIndexStatementHelper({ unique?: boolean }) { const columnsName = Array.isArray(columns) ? columns.join("_") : columns + const tokens = qualifiedName.replace(/"/g, "").split(".") + + let pgSchemaName: string | undefined + let tableName: string + let tableReference: string + + if (tokens.length > 1) { + pgSchemaName = tokens.shift() + tableName = tokens.join(".") + tableReference = `"${pgSchemaName}"."${tableName}"` + } else { + tableName = qualifiedName + tableReference = `"${tableName}"` + } columns = Array.isArray(columns) ? columns.join(", ") : columns name = name || `IDX_${tableName}_${columnsName}${unique ? "_unique" : ""}` @@ -53,7 +67,7 @@ export function createPsqlIndexStatementHelper({ const optionsStr = where ? ` WHERE ${where}` : "" const uniqueStr = unique ? "UNIQUE " : "" - const expression = `CREATE ${uniqueStr}INDEX IF NOT EXISTS "${name}" ON "${tableName}"${typeStr} (${columns})${optionsStr}` + const expression = `CREATE ${uniqueStr}INDEX IF NOT EXISTS "${name}" ON ${tableReference}${typeStr} (${columns})${optionsStr}` return { toString: () => { return expression 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 477b2fa553..02121a2e4b 100644 --- a/packages/core/utils/src/dml/__tests__/entity-builder.spec.ts +++ b/packages/core/utils/src/dml/__tests__/entity-builder.spec.ts @@ -669,6 +669,7 @@ describe("Entity builder", () => { const metaData = MetadataStorage.getMetadataFromDecorator(User) expect(metaData.className).toEqual("User") expect(metaData.path).toEqual("User") + expect(metaData.tableName).toEqual("public.user") expect(metaData.filters).toEqual({ softDeletable: { @@ -772,9 +773,9 @@ describe("Entity builder", () => { 'CREATE INDEX IF NOT EXISTS "IDX_user_id" ON "user" (id) WHERE deleted_at IS NULL', }, { - name: "IDX_user_email", + name: "IDX_user_email_unique", expression: - 'CREATE UNIQUE INDEX IF NOT EXISTS "IDX_user_email" ON "user" (email) WHERE deleted_at IS NULL', + 'CREATE UNIQUE INDEX IF NOT EXISTS "IDX_user_email_unique" ON "user" (email) WHERE deleted_at IS NULL', }, ]) @@ -870,6 +871,7 @@ describe("Entity builder", () => { const metaData = MetadataStorage.getMetadataFromDecorator(User) expect(metaData.className).toEqual("User") expect(metaData.path).toEqual("User") + expect(metaData.tableName).toEqual("platform.user") expect(metaData.indexes).toEqual([ { @@ -878,9 +880,9 @@ describe("Entity builder", () => { 'CREATE INDEX IF NOT EXISTS "IDX_user_id" ON "platform"."user" (id) WHERE deleted_at IS NULL', }, { - name: "IDX_user_email", + name: "IDX_user_email_unique", expression: - 'CREATE UNIQUE INDEX IF NOT EXISTS "IDX_user_email" ON "platform"."user" (email) WHERE deleted_at IS NULL', + 'CREATE UNIQUE INDEX IF NOT EXISTS "IDX_user_email_unique" ON "platform"."user" (email) WHERE deleted_at IS NULL', }, ]) @@ -2694,7 +2696,7 @@ describe("Entity builder", () => { const entityBuilder = createMikrORMEntity() expect(() => entityBuilder(email)).toThrow( - 'Missing property "email" on "user" entity. Make sure to define it as a relationship' + 'Missing property "email" on "User" entity. Make sure to define it as a relationship' ) }) @@ -2715,7 +2717,7 @@ describe("Entity builder", () => { const entityBuilder = createMikrORMEntity() expect(() => entityBuilder(email)).toThrow( - 'Invalid relationship reference for "email" on "user" entity. Make sure to define a hasOne or hasMany relationship' + 'Invalid relationship reference for "email" on "User" entity. Make sure to define a hasOne or hasMany relationship' ) }) @@ -2743,6 +2745,368 @@ describe("Entity builder", () => { 'Cannot cascade delete "user" relationship(s) from "email" entity. Child to parent cascades are not allowed' ) }) + + test("define relationships when entity names has pg schema name", () => { + const model = new EntityBuilder() + + const email = model.define("platform.email", { + email: model.text(), + isVerified: model.boolean(), + user: model.belongsTo(() => user), + }) + + const user = model.define("platform.user", { + id: model.number(), + username: model.text(), + email: model.hasOne(() => email), + }) + + const entityBuilder = createMikrORMEntity() + const User = entityBuilder(user) + const Email = entityBuilder(email) + + expectTypeOf(new User()).toMatchTypeOf<{ + id: number + username: string + deleted_at: Date | null + email: EntityConstructor<{ + email: string + isVerified: boolean + deleted_at: Date | null + user: EntityConstructor<{ + id: number + username: string + deleted_at: Date | null + }> + }> + }>() + + expectTypeOf(new Email()).toMatchTypeOf<{ + email: string + isVerified: boolean + deleted_at: Date | null + user: EntityConstructor<{ + id: number + username: string + deleted_at: Date | null + email: EntityConstructor<{ + email: string + isVerified: boolean + deleted_at: Date | null + }> + }> + }>() + + const metaData = MetadataStorage.getMetadataFromDecorator(User) + expect(metaData.className).toEqual("User") + expect(metaData.path).toEqual("User") + expect(metaData.tableName).toEqual("platform.user") + expect(metaData.properties).toEqual({ + id: { + reference: "scalar", + type: "number", + columnType: "integer", + name: "id", + nullable: false, + getter: false, + setter: false, + }, + username: { + reference: "scalar", + type: "string", + columnType: "text", + name: "username", + nullable: false, + getter: false, + setter: false, + }, + email: { + reference: "1:1", + name: "email", + entity: "Email", + nullable: false, + mappedBy: "user", + }, + created_at: { + reference: "scalar", + type: "date", + columnType: "timestamptz", + name: "created_at", + defaultRaw: "now()", + onCreate: expect.any(Function), + nullable: false, + getter: false, + setter: false, + }, + updated_at: { + reference: "scalar", + type: "date", + columnType: "timestamptz", + name: "updated_at", + defaultRaw: "now()", + onCreate: expect.any(Function), + onUpdate: expect.any(Function), + nullable: false, + getter: false, + setter: false, + }, + deleted_at: { + reference: "scalar", + type: "date", + columnType: "timestamptz", + name: "deleted_at", + nullable: true, + getter: false, + setter: false, + }, + }) + + const emailMetaData = MetadataStorage.getMetadataFromDecorator(Email) + expect(emailMetaData.className).toEqual("Email") + expect(emailMetaData.path).toEqual("Email") + expect(emailMetaData.tableName).toEqual("platform.email") + expect(emailMetaData.properties).toEqual({ + email: { + reference: "scalar", + type: "string", + columnType: "text", + name: "email", + nullable: false, + getter: false, + setter: false, + }, + isVerified: { + reference: "scalar", + type: "boolean", + columnType: "boolean", + name: "isVerified", + nullable: false, + getter: false, + setter: false, + }, + user: { + reference: "1:1", + name: "user", + entity: "User", + nullable: false, + owner: true, + mappedBy: "email", + }, + created_at: { + reference: "scalar", + type: "date", + columnType: "timestamptz", + name: "created_at", + defaultRaw: "now()", + onCreate: expect.any(Function), + nullable: false, + getter: false, + setter: false, + }, + updated_at: { + reference: "scalar", + type: "date", + columnType: "timestamptz", + name: "updated_at", + defaultRaw: "now()", + onCreate: expect.any(Function), + onUpdate: expect.any(Function), + nullable: false, + getter: false, + setter: false, + }, + deleted_at: { + reference: "scalar", + type: "date", + columnType: "timestamptz", + name: "deleted_at", + nullable: true, + getter: false, + setter: false, + }, + }) + }) + + test("define relationships between cross pg schemas entities", () => { + const model = new EntityBuilder() + + const email = model.define("platform.email", { + email: model.text(), + isVerified: model.boolean(), + user: model.belongsTo(() => user), + }) + + const user = model.define("public.user", { + id: model.number(), + username: model.text(), + email: model.hasOne(() => email), + }) + + const entityBuilder = createMikrORMEntity() + const User = entityBuilder(user) + const Email = entityBuilder(email) + + expectTypeOf(new User()).toMatchTypeOf<{ + id: number + username: string + deleted_at: Date | null + email: EntityConstructor<{ + email: string + isVerified: boolean + deleted_at: Date | null + user: EntityConstructor<{ + id: number + username: string + deleted_at: Date | null + }> + }> + }>() + + expectTypeOf(new Email()).toMatchTypeOf<{ + email: string + isVerified: boolean + deleted_at: Date | null + user: EntityConstructor<{ + id: number + username: string + deleted_at: Date | null + email: EntityConstructor<{ + email: string + isVerified: boolean + deleted_at: Date | null + }> + }> + }>() + + const metaData = MetadataStorage.getMetadataFromDecorator(User) + expect(metaData.className).toEqual("User") + expect(metaData.path).toEqual("User") + expect(metaData.tableName).toEqual("public.user") + expect(metaData.properties).toEqual({ + id: { + reference: "scalar", + type: "number", + columnType: "integer", + name: "id", + nullable: false, + getter: false, + setter: false, + }, + username: { + reference: "scalar", + type: "string", + columnType: "text", + name: "username", + nullable: false, + getter: false, + setter: false, + }, + email: { + reference: "1:1", + name: "email", + entity: "Email", + nullable: false, + mappedBy: "user", + }, + created_at: { + reference: "scalar", + type: "date", + columnType: "timestamptz", + name: "created_at", + defaultRaw: "now()", + onCreate: expect.any(Function), + nullable: false, + getter: false, + setter: false, + }, + updated_at: { + reference: "scalar", + type: "date", + columnType: "timestamptz", + name: "updated_at", + defaultRaw: "now()", + onCreate: expect.any(Function), + onUpdate: expect.any(Function), + nullable: false, + getter: false, + setter: false, + }, + deleted_at: { + reference: "scalar", + type: "date", + columnType: "timestamptz", + name: "deleted_at", + nullable: true, + getter: false, + setter: false, + }, + }) + + const emailMetaData = MetadataStorage.getMetadataFromDecorator(Email) + expect(emailMetaData.className).toEqual("Email") + expect(emailMetaData.path).toEqual("Email") + expect(emailMetaData.tableName).toEqual("platform.email") + expect(emailMetaData.properties).toEqual({ + email: { + reference: "scalar", + type: "string", + columnType: "text", + name: "email", + nullable: false, + getter: false, + setter: false, + }, + isVerified: { + reference: "scalar", + type: "boolean", + columnType: "boolean", + name: "isVerified", + nullable: false, + getter: false, + setter: false, + }, + user: { + reference: "1:1", + name: "user", + entity: "User", + nullable: false, + owner: true, + mappedBy: "email", + }, + created_at: { + reference: "scalar", + type: "date", + columnType: "timestamptz", + name: "created_at", + defaultRaw: "now()", + onCreate: expect.any(Function), + nullable: false, + getter: false, + setter: false, + }, + updated_at: { + reference: "scalar", + type: "date", + columnType: "timestamptz", + name: "updated_at", + defaultRaw: "now()", + onCreate: expect.any(Function), + onUpdate: expect.any(Function), + nullable: false, + getter: false, + setter: false, + }, + deleted_at: { + reference: "scalar", + type: "date", + columnType: "timestamptz", + name: "deleted_at", + nullable: true, + getter: false, + setter: false, + }, + }) + }) }) describe("Entity builder | manyToMany", () => { @@ -3100,7 +3464,7 @@ describe("Entity builder", () => { const entityBuilder = createMikrORMEntity() expect(() => entityBuilder(user)).toThrow( - 'Missing property "users" on "team" entity. Make sure to define it as a relationship' + 'Missing property "users" on "Team" entity. Make sure to define it as a relationship' ) }) @@ -3120,7 +3484,7 @@ describe("Entity builder", () => { const entityBuilder = createMikrORMEntity() expect(() => entityBuilder(user)).toThrow( - 'Invalid relationship reference for "users" on "team" entity. Make sure to define a manyToMany relationship' + 'Invalid relationship reference for "users" on "Team" entity. Make sure to define a manyToMany relationship' ) }) @@ -3680,5 +4044,176 @@ describe("Entity builder", () => { }, }) }) + + test("define manyToMany relationship when entity names has pg schema name", () => { + const model = new EntityBuilder() + const team = model.define("platform.team", { + id: model.number(), + name: model.text(), + users: model.manyToMany(() => user), + }) + + const user = model.define("platform.user", { + id: model.number(), + username: model.text(), + teams: model.manyToMany(() => team), + }) + + const entityBuilder = createMikrORMEntity() + const User = entityBuilder(user) + const Team = entityBuilder(team) + + expectTypeOf(new User()).toMatchTypeOf<{ + id: number + username: string + teams: EntityConstructor<{ + id: number + name: string + users: EntityConstructor<{ + id: number + username: string + }> + }> + }>() + + expectTypeOf(new Team()).toMatchTypeOf<{ + id: number + name: string + users: EntityConstructor<{ + id: number + username: string + teams: EntityConstructor<{ + id: number + name: string + }> + }> + }>() + + const metaData = MetadataStorage.getMetadataFromDecorator(User) + expect(metaData.className).toEqual("User") + expect(metaData.path).toEqual("User") + expect(metaData.tableName).toEqual("platform.user") + expect(metaData.properties).toEqual({ + id: { + reference: "scalar", + type: "number", + columnType: "integer", + name: "id", + nullable: false, + getter: false, + setter: false, + }, + username: { + reference: "scalar", + type: "string", + columnType: "text", + name: "username", + nullable: false, + getter: false, + setter: false, + }, + teams: { + reference: "m:n", + name: "teams", + entity: "Team", + pivotTable: "platform.team_users", + }, + created_at: { + reference: "scalar", + type: "date", + columnType: "timestamptz", + name: "created_at", + defaultRaw: "now()", + onCreate: expect.any(Function), + nullable: false, + getter: false, + setter: false, + }, + updated_at: { + reference: "scalar", + type: "date", + columnType: "timestamptz", + name: "updated_at", + defaultRaw: "now()", + onCreate: expect.any(Function), + onUpdate: expect.any(Function), + nullable: false, + getter: false, + setter: false, + }, + deleted_at: { + reference: "scalar", + type: "date", + columnType: "timestamptz", + name: "deleted_at", + nullable: true, + getter: false, + setter: false, + }, + }) + + const teamMetaData = MetadataStorage.getMetadataFromDecorator(Team) + expect(teamMetaData.className).toEqual("Team") + expect(teamMetaData.path).toEqual("Team") + expect(teamMetaData.tableName).toEqual("platform.team") + expect(teamMetaData.properties).toEqual({ + id: { + reference: "scalar", + type: "number", + columnType: "integer", + name: "id", + nullable: false, + getter: false, + setter: false, + }, + name: { + reference: "scalar", + type: "string", + columnType: "text", + name: "name", + nullable: false, + getter: false, + setter: false, + }, + users: { + reference: "m:n", + name: "users", + entity: "User", + pivotTable: "platform.team_users", + }, + created_at: { + reference: "scalar", + type: "date", + columnType: "timestamptz", + name: "created_at", + defaultRaw: "now()", + onCreate: expect.any(Function), + nullable: false, + getter: false, + setter: false, + }, + updated_at: { + reference: "scalar", + type: "date", + columnType: "timestamptz", + name: "updated_at", + defaultRaw: "now()", + onCreate: expect.any(Function), + onUpdate: expect.any(Function), + nullable: false, + getter: false, + setter: false, + }, + deleted_at: { + reference: "scalar", + type: "date", + columnType: "timestamptz", + name: "deleted_at", + nullable: true, + getter: false, + setter: false, + }, + }) + }) }) }) 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 5245989bc4..cacfe86d90 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 @@ -104,6 +104,33 @@ const SPECIAL_PROPERTIES: { * to Mikro ORM entities. */ export function createMikrORMEntity() { + /** + * Parses entity name and returns model and table name from + * it + */ + function parseEntityName(entityName: string) { + /** + * Table name is going to be the snake case version of the entity name. + * Here we should preserve PG schema (if defined). + * + * For example: "platform.user" should stay as "platform.user" + */ + const tableName = camelToSnakeCase(entityName) + + /** + * Entity name is going to be the camelCase version of the + * name defined by the user + */ + const [pgSchema, ...rest] = tableName.split(".") + return { + tableName, + modelName: upperCaseFirst( + toCamelCase(rest.length ? rest.join("_") : pgSchema) + ), + pgSchema: rest.length ? pgSchema : undefined, + } + } + /** * The following property is used to track many to many relationship * between two entities. It is needed because we have to mark one @@ -162,19 +189,12 @@ export function createMikrORMEntity() { */ function applyIndexes( MikroORMEntity: EntityConstructor, - { - tableName, - pgSchema, - }: { tableName: string; pgSchema: undefined | string }, + tableName: string, field: PropertyMetadata ) { field.indexes.forEach((index) => { - const name = - index.name || `IDX_${tableName}_${camelToSnakeCase(field.fieldName)}` - const providerEntityIdIndexStatement = createPsqlIndexStatementHelper({ - name, - tableName: pgSchema ? `${pgSchema}"."${tableName}` : tableName, + tableName, columns: [field.fieldName], unique: index.type === "unique", where: "deleted_at IS NULL", @@ -190,12 +210,9 @@ export function createMikrORMEntity() { function defineHasOneRelationship( MikroORMEntity: EntityConstructor, relationship: RelationshipMetadata, - relatedEntity: DmlEntity< - Record | RelationshipType> - >, + { relatedModelName }: { relatedModelName: string }, cascades: EntityCascades ) { - const relatedModelName = upperCaseFirst(relatedEntity.name) const shouldRemoveRelated = !!cascades.delete?.includes(relationship.name) OneToOne({ @@ -214,12 +231,9 @@ export function createMikrORMEntity() { function defineHasManyRelationship( MikroORMEntity: EntityConstructor, relationship: RelationshipMetadata, - relatedEntity: DmlEntity< - Record | RelationshipType> - >, + { relatedModelName }: { relatedModelName: string }, cascades: EntityCascades ) { - const relatedModelName = upperCaseFirst(relatedEntity.name) const shouldRemoveRelated = !!cascades.delete?.includes(relationship.name) OneToMany({ @@ -246,7 +260,8 @@ export function createMikrORMEntity() { relationship: RelationshipMetadata, relatedEntity: DmlEntity< Record | RelationshipType> - > + >, + { relatedModelName }: { relatedModelName: string } ) { const mappedBy = relationship.mappedBy || camelToSnakeCase(MikroORMEntity.name) @@ -254,7 +269,6 @@ export function createMikrORMEntity() { relatedEntity.parse() const otherSideRelation = relationSchema[mappedBy] - const relatedModelName = upperCaseFirst(relatedEntity.name) /** * In DML the relationships are cascaded from parent to child. A belongsTo @@ -269,7 +283,7 @@ export function createMikrORMEntity() { */ if (!otherSideRelation) { throw new Error( - `Missing property "${mappedBy}" on "${relatedEntity.name}" entity. Make sure to define it as a relationship` + `Missing property "${mappedBy}" on "${relatedModelName}" entity. Make sure to define it as a relationship` ) } @@ -311,7 +325,7 @@ export function createMikrORMEntity() { * Other side is some unsupported data-type */ throw new Error( - `Invalid relationship reference for "${mappedBy}" on "${relatedEntity.name}" entity. Make sure to define a hasOne or hasMany relationship` + `Invalid relationship reference for "${mappedBy}" on "${relatedModelName}" entity. Make sure to define a hasOne or hasMany relationship` ) } @@ -324,9 +338,11 @@ export function createMikrORMEntity() { relatedEntity: DmlEntity< Record | RelationshipType> >, - cascades: EntityCascades + { + relatedModelName, + pgSchema, + }: { relatedModelName: string; pgSchema: string | undefined } ) { - const relatedModelName = upperCaseFirst(relatedEntity.name) let mappedBy = relationship.mappedBy let inversedBy: undefined | string @@ -340,7 +356,7 @@ export function createMikrORMEntity() { */ const pivotTableName = [ MikroORMEntity.name.toLowerCase(), - relatedEntity.name.toLowerCase(), + relatedModelName.toLowerCase(), ] .sort() .map((token, index) => { @@ -355,13 +371,13 @@ export function createMikrORMEntity() { const otherSideRelation = relatedEntity.parse().schema[mappedBy] if (!otherSideRelation) { throw new Error( - `Missing property "${mappedBy}" on "${relatedEntity.name}" entity. Make sure to define it as a relationship` + `Missing property "${mappedBy}" on "${relatedModelName}" entity. Make sure to define it as a relationship` ) } if (otherSideRelation instanceof DmlManyToMany === false) { throw new Error( - `Invalid relationship reference for "${mappedBy}" on "${relatedEntity.name}" entity. Make sure to define a manyToMany relationship` + `Invalid relationship reference for "${mappedBy}" on "${relatedModelName}" entity. Make sure to define a manyToMany relationship` ) } @@ -387,7 +403,7 @@ export function createMikrORMEntity() { ManyToMany({ entity: relatedModelName, - pivotTable: pivotTableName, + pivotTable: pgSchema ? `${pgSchema}.${pivotTableName}` : pivotTableName, ...(mappedBy ? { mappedBy: mappedBy as any } : {}), ...(inversedBy ? { inversedBy: inversedBy as any } : {}), })(MikroORMEntity.prototype, relationship.name) @@ -429,6 +445,15 @@ export function createMikrORMEntity() { ) } + const { modelName, tableName, pgSchema } = parseEntityName( + relatedEntity.parse().name + ) + const relatedEntityInfo = { + relatedModelName: modelName, + relatedTableName: tableName, + pgSchema, + } + /** * Defining relationships */ @@ -437,7 +462,7 @@ export function createMikrORMEntity() { defineHasOneRelationship( MikroORMEntity, relationship, - relatedEntity, + relatedEntityInfo, cascades ) break @@ -445,19 +470,24 @@ export function createMikrORMEntity() { defineHasManyRelationship( MikroORMEntity, relationship, - relatedEntity, + relatedEntityInfo, cascades ) break case "belongsTo": - defineBelongsToRelationship(MikroORMEntity, relationship, relatedEntity) + defineBelongsToRelationship( + MikroORMEntity, + relationship, + relatedEntity, + relatedEntityInfo + ) break case "manyToMany": defineManyToManyRelationship( MikroORMEntity, relationship, relatedEntity, - cascades + relatedEntityInfo ) break } @@ -470,26 +500,7 @@ export function createMikrORMEntity() { return function createEntity>(entity: T): Infer { class MikroORMEntity {} const { name, schema, cascades } = entity.parse() - const [pgSchema, ...rest] = name.split(".") - - /** - * Entity name is computed by splitting the pgSchema - * from the original name and converting everything - * to camelCase - */ - const entityName = rest.length - ? toCamelCase(rest.join("_")) - : toCamelCase(pgSchema) - - /** - * Table name is the snake case version of entityName - */ - const tableName = camelToSnakeCase(entityName) - - /** - * Table name is the Pascal case version of entityName - */ - const modelName = upperCaseFirst(entityName) + const { modelName, tableName } = parseEntityName(name) /** * Assigning name to the class constructor, so that it matches @@ -508,11 +519,7 @@ export function createMikrORMEntity() { const field = property.parse(name) if ("fieldName" in field) { defineProperty(MikroORMEntity, field) - applyIndexes( - MikroORMEntity, - { tableName, pgSchema: rest.length ? pgSchema : undefined }, - field - ) + applyIndexes(MikroORMEntity, tableName, field) } else { defineRelationship(MikroORMEntity, field, cascades) }