feat: add support for indexes (#7756)

This commit is contained in:
Harminder Virk
2024-06-18 13:41:16 +05:30
committed by GitHub
parent d6c6f5998c
commit 4f7bbf1f29
4 changed files with 133 additions and 3 deletions

View File

@@ -479,6 +479,91 @@ describe("Entity builder", () => {
})
})
describe("Entity builder | indexes", () => {
test("define index on a field", () => {
const model = new EntityBuilder()
const user = model.define("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_users_id",
expression:
'CREATE INDEX IF NOT EXISTS "IDX_users_id" ON "users" (id) WHERE deleted_at IS NULL',
},
{
name: "IDX_users_email",
expression:
'CREATE UNIQUE INDEX IF NOT EXISTS "IDX_users_email" ON "users" (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,
},
deleted_at: {
reference: "scalar",
type: "date",
columnType: "timestamptz",
name: "deleted_at",
nullable: true,
getter: false,
setter: false,
},
})
})
})
describe("Entity builder | hasOne", () => {
test("define hasOne relationship", () => {
const model = new EntityBuilder()

View File

@@ -9,7 +9,11 @@ import {
Filter,
} from "@mikro-orm/core"
import { DmlEntity } from "../entity"
import { camelToSnakeCase, pluralize } from "../../common"
import {
pluralize,
camelToSnakeCase,
createPsqlIndexStatementHelper,
} from "../../common"
import { upperCaseFirst } from "../../common/upper-case-first"
import type {
Infer,
@@ -114,6 +118,30 @@ export function createMikrORMEntity() {
})(MikroORMEntity.prototype, field.fieldName)
}
/**
* Prepares indexes for a given field
*/
function applyIndexes(
MikroORMEntity: EntityConstructor<any>,
tableName: string,
field: SchemaMetadata
) {
field.indexes.forEach((index) => {
const name =
index.name || `IDX_${tableName}_${camelToSnakeCase(field.fieldName)}`
const providerEntityIdIndexStatement = createPsqlIndexStatementHelper({
name,
tableName,
columns: [field.fieldName],
unique: index.type === "unique",
where: "deleted_at IS NULL",
})
providerEntityIdIndexStatement.MikroORMIndex()(MikroORMEntity)
})
}
/**
* Defines has one relationship on the Mikro ORM entity.
*/
@@ -421,6 +449,7 @@ export function createMikrORMEntity() {
const field = property.parse(name)
if ("fieldName" in field) {
defineProperty(MikroORMEntity, field)
applyIndexes(MikroORMEntity, tableName, field)
} else {
defineRelationship(MikroORMEntity, field, cascades)
}

View File

@@ -29,6 +29,22 @@ export abstract class BaseSchema<T> implements SchemaType<T> {
return new NullableModifier<T, this>(this)
}
/**
* Define an index on the property
*/
index(name?: string) {
this.#indexes.push({ name, type: "index" })
return this
}
/**
* Define a unique index on the property
*/
unique(name?: string) {
this.#indexes.push({ name, type: "unique" })
return this
}
/**
* Define default value for the property
*/

View File

@@ -42,8 +42,8 @@ export type SchemaMetadata = MaybeFieldMetadata & {
options?: Record<string, any>
}
indexes: {
name: string
type: string
name?: string
type: "index" | "unique"
}[]
relationships: RelationshipMetadata[]
}