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'
|
'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", () => {
|
describe("Entity builder | indexes", () => {
|
||||||
@@ -672,14 +767,120 @@ describe("Entity builder", () => {
|
|||||||
|
|
||||||
expect(metaData.indexes).toEqual([
|
expect(metaData.indexes).toEqual([
|
||||||
{
|
{
|
||||||
name: "IDX_users_id",
|
name: "IDX_user_id",
|
||||||
expression:
|
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:
|
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,
|
pluralize,
|
||||||
camelToSnakeCase,
|
camelToSnakeCase,
|
||||||
createPsqlIndexStatementHelper,
|
createPsqlIndexStatementHelper,
|
||||||
|
toCamelCase,
|
||||||
} from "../../common"
|
} from "../../common"
|
||||||
import { upperCaseFirst } from "../../common/upper-case-first"
|
import { upperCaseFirst } from "../../common/upper-case-first"
|
||||||
import type {
|
import type {
|
||||||
@@ -110,7 +111,7 @@ export function createMikrORMEntity() {
|
|||||||
* any user land APIs to explicitly define an owner.
|
* any user land APIs to explicitly define an owner.
|
||||||
*
|
*
|
||||||
* The object contains values as follows.
|
* 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:
|
* Example:
|
||||||
* - [user.teams]: true // the teams relationship on user is an owner
|
* - [user.teams]: true // the teams relationship on user is an owner
|
||||||
@@ -161,7 +162,10 @@ export function createMikrORMEntity() {
|
|||||||
*/
|
*/
|
||||||
function applyIndexes(
|
function applyIndexes(
|
||||||
MikroORMEntity: EntityConstructor<any>,
|
MikroORMEntity: EntityConstructor<any>,
|
||||||
tableName: string,
|
{
|
||||||
|
tableName,
|
||||||
|
pgSchema,
|
||||||
|
}: { tableName: string; pgSchema: undefined | string },
|
||||||
field: PropertyMetadata
|
field: PropertyMetadata
|
||||||
) {
|
) {
|
||||||
field.indexes.forEach((index) => {
|
field.indexes.forEach((index) => {
|
||||||
@@ -170,7 +174,7 @@ export function createMikrORMEntity() {
|
|||||||
|
|
||||||
const providerEntityIdIndexStatement = createPsqlIndexStatementHelper({
|
const providerEntityIdIndexStatement = createPsqlIndexStatementHelper({
|
||||||
name,
|
name,
|
||||||
tableName,
|
tableName: pgSchema ? `${pgSchema}"."${tableName}` : tableName,
|
||||||
columns: [field.fieldName],
|
columns: [field.fieldName],
|
||||||
unique: index.type === "unique",
|
unique: index.type === "unique",
|
||||||
where: "deleted_at IS NULL",
|
where: "deleted_at IS NULL",
|
||||||
@@ -466,9 +470,26 @@ export function createMikrORMEntity() {
|
|||||||
return function createEntity<T extends DmlEntity<any>>(entity: T): Infer<T> {
|
return function createEntity<T extends DmlEntity<any>>(entity: T): Infer<T> {
|
||||||
class MikroORMEntity {}
|
class MikroORMEntity {}
|
||||||
const { name, schema, cascades } = entity.parse()
|
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
|
* Assigning name to the class constructor, so that it matches
|
||||||
@@ -476,7 +497,7 @@ export function createMikrORMEntity() {
|
|||||||
*/
|
*/
|
||||||
Object.defineProperty(MikroORMEntity, "name", {
|
Object.defineProperty(MikroORMEntity, "name", {
|
||||||
get: function () {
|
get: function () {
|
||||||
return className
|
return modelName
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -487,7 +508,11 @@ export function createMikrORMEntity() {
|
|||||||
const field = property.parse(name)
|
const field = property.parse(name)
|
||||||
if ("fieldName" in field) {
|
if ("fieldName" in field) {
|
||||||
defineProperty(MikroORMEntity, field)
|
defineProperty(MikroORMEntity, field)
|
||||||
applyIndexes(MikroORMEntity, tableName, field)
|
applyIndexes(
|
||||||
|
MikroORMEntity,
|
||||||
|
{ tableName, pgSchema: rest.length ? pgSchema : undefined },
|
||||||
|
field
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
defineRelationship(MikroORMEntity, field, cascades)
|
defineRelationship(MikroORMEntity, field, cascades)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user