Allow entities to contain pg schema name in their name (#7773)
This commit is contained in:
@@ -646,6 +646,101 @@ describe("Entity builder", () => {
|
||||
'Cannot define field(s) "deleted_at" as they are implicitly defined on every model'
|
||||
)
|
||||
})
|
||||
|
||||
test("define pg schema name in the entity name", () => {
|
||||
const model = new EntityBuilder()
|
||||
const user = model.define("public.user", {
|
||||
id: model.number(),
|
||||
username: model.text(),
|
||||
email: model.text(),
|
||||
})
|
||||
|
||||
const entityBuilder = createMikrORMEntity()
|
||||
const User = entityBuilder(user)
|
||||
expectTypeOf(new User()).toMatchTypeOf<{
|
||||
id: number
|
||||
username: string
|
||||
email: string
|
||||
created_at: Date
|
||||
updated_at: Date
|
||||
deleted_at: Date | null
|
||||
}>()
|
||||
|
||||
const metaData = MetadataStorage.getMetadataFromDecorator(User)
|
||||
expect(metaData.className).toEqual("User")
|
||||
expect(metaData.path).toEqual("User")
|
||||
|
||||
expect(metaData.filters).toEqual({
|
||||
softDeletable: {
|
||||
name: "softDeletable",
|
||||
cond: expect.any(Function),
|
||||
default: true,
|
||||
args: false,
|
||||
},
|
||||
})
|
||||
|
||||
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: "scalar",
|
||||
type: "string",
|
||||
columnType: "text",
|
||||
name: "email",
|
||||
nullable: false,
|
||||
getter: false,
|
||||
setter: false,
|
||||
},
|
||||
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 | indexes", () => {
|
||||
@@ -672,14 +767,120 @@ describe("Entity builder", () => {
|
||||
|
||||
expect(metaData.indexes).toEqual([
|
||||
{
|
||||
name: "IDX_users_id",
|
||||
name: "IDX_user_id",
|
||||
expression:
|
||||
'CREATE INDEX IF NOT EXISTS "IDX_users_id" ON "users" (id) WHERE deleted_at IS NULL',
|
||||
'CREATE INDEX IF NOT EXISTS "IDX_user_id" ON "user" (id) WHERE deleted_at IS NULL',
|
||||
},
|
||||
{
|
||||
name: "IDX_users_email",
|
||||
name: "IDX_user_email",
|
||||
expression:
|
||||
'CREATE UNIQUE INDEX IF NOT EXISTS "IDX_users_email" ON "users" (email) WHERE deleted_at IS NULL',
|
||||
'CREATE UNIQUE INDEX IF NOT EXISTS "IDX_user_email" ON "user" (email) WHERE deleted_at IS NULL',
|
||||
},
|
||||
])
|
||||
|
||||
expect(metaData.filters).toEqual({
|
||||
softDeletable: {
|
||||
name: "softDeletable",
|
||||
cond: expect.any(Function),
|
||||
default: true,
|
||||
args: false,
|
||||
},
|
||||
})
|
||||
|
||||
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: "scalar",
|
||||
type: "string",
|
||||
columnType: "text",
|
||||
name: "email",
|
||||
nullable: false,
|
||||
getter: false,
|
||||
setter: false,
|
||||
},
|
||||
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 index when entity is using an explicit pg Schema", () => {
|
||||
const model = new EntityBuilder()
|
||||
const user = model.define("platform.user", {
|
||||
id: model.number().index(),
|
||||
username: model.text(),
|
||||
email: model.text().unique(),
|
||||
})
|
||||
|
||||
const entityBuilder = createMikrORMEntity()
|
||||
const User = entityBuilder(user)
|
||||
expectTypeOf(new User()).toMatchTypeOf<{
|
||||
id: number
|
||||
username: string
|
||||
email: string
|
||||
deleted_at: Date | null
|
||||
}>()
|
||||
|
||||
const metaData = MetadataStorage.getMetadataFromDecorator(User)
|
||||
expect(metaData.className).toEqual("User")
|
||||
expect(metaData.path).toEqual("User")
|
||||
|
||||
expect(metaData.indexes).toEqual([
|
||||
{
|
||||
name: "IDX_user_id",
|
||||
expression:
|
||||
'CREATE INDEX IF NOT EXISTS "IDX_user_id" ON "platform"."user" (id) WHERE deleted_at IS NULL',
|
||||
},
|
||||
{
|
||||
name: "IDX_user_email",
|
||||
expression:
|
||||
'CREATE UNIQUE INDEX IF NOT EXISTS "IDX_user_email" ON "platform"."user" (email) WHERE deleted_at IS NULL',
|
||||
},
|
||||
])
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
pluralize,
|
||||
camelToSnakeCase,
|
||||
createPsqlIndexStatementHelper,
|
||||
toCamelCase,
|
||||
} from "../../common"
|
||||
import { upperCaseFirst } from "../../common/upper-case-first"
|
||||
import type {
|
||||
@@ -110,7 +111,7 @@ export function createMikrORMEntity() {
|
||||
* any user land APIs to explicitly define an owner.
|
||||
*
|
||||
* The object contains values as follows.
|
||||
* - [entityname.relationship]: true // true means, it is already marked as owner
|
||||
* - [modelName.relationship]: true // true means, it is already marked as owner
|
||||
*
|
||||
* Example:
|
||||
* - [user.teams]: true // the teams relationship on user is an owner
|
||||
@@ -161,7 +162,10 @@ export function createMikrORMEntity() {
|
||||
*/
|
||||
function applyIndexes(
|
||||
MikroORMEntity: EntityConstructor<any>,
|
||||
tableName: string,
|
||||
{
|
||||
tableName,
|
||||
pgSchema,
|
||||
}: { tableName: string; pgSchema: undefined | string },
|
||||
field: PropertyMetadata
|
||||
) {
|
||||
field.indexes.forEach((index) => {
|
||||
@@ -170,7 +174,7 @@ export function createMikrORMEntity() {
|
||||
|
||||
const providerEntityIdIndexStatement = createPsqlIndexStatementHelper({
|
||||
name,
|
||||
tableName,
|
||||
tableName: pgSchema ? `${pgSchema}"."${tableName}` : tableName,
|
||||
columns: [field.fieldName],
|
||||
unique: index.type === "unique",
|
||||
where: "deleted_at IS NULL",
|
||||
@@ -466,9 +470,26 @@ export function createMikrORMEntity() {
|
||||
return function createEntity<T extends DmlEntity<any>>(entity: T): Infer<T> {
|
||||
class MikroORMEntity {}
|
||||
const { name, schema, cascades } = entity.parse()
|
||||
const [pgSchema, ...rest] = name.split(".")
|
||||
|
||||
const className = upperCaseFirst(name)
|
||||
const tableName = pluralize(camelToSnakeCase(className))
|
||||
/**
|
||||
* 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)
|
||||
|
||||
/**
|
||||
* Assigning name to the class constructor, so that it matches
|
||||
@@ -476,7 +497,7 @@ export function createMikrORMEntity() {
|
||||
*/
|
||||
Object.defineProperty(MikroORMEntity, "name", {
|
||||
get: function () {
|
||||
return className
|
||||
return modelName
|
||||
},
|
||||
})
|
||||
|
||||
@@ -487,7 +508,11 @@ export function createMikrORMEntity() {
|
||||
const field = property.parse(name)
|
||||
if ("fieldName" in field) {
|
||||
defineProperty(MikroORMEntity, field)
|
||||
applyIndexes(MikroORMEntity, tableName, field)
|
||||
applyIndexes(
|
||||
MikroORMEntity,
|
||||
{ tableName, pgSchema: rest.length ? pgSchema : undefined },
|
||||
field
|
||||
)
|
||||
} else {
|
||||
defineRelationship(MikroORMEntity, field, cascades)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user