mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-17 12:56:05 +00:00
97 lines
2.9 KiB
TypeScript
97 lines
2.9 KiB
TypeScript
import { type Static, StringEnum } from "core/utils";
|
|
import type { EntityManager } from "../entities";
|
|
import { Field, baseFieldConfigSchema, primaryFieldTypes } from "../fields";
|
|
import type { EntityRelation } from "./EntityRelation";
|
|
import type { EntityRelationAnchor } from "./EntityRelationAnchor";
|
|
import * as tbbox from "@sinclair/typebox";
|
|
import type { TFieldTSType } from "data/entities/EntityTypescript";
|
|
const { Type } = tbbox;
|
|
|
|
const CASCADES = ["cascade", "set null", "set default", "restrict", "no action"] as const;
|
|
|
|
export const relationFieldConfigSchema = Type.Composite([
|
|
baseFieldConfigSchema,
|
|
Type.Object({
|
|
reference: Type.String(),
|
|
target: Type.String(), // @todo: potentially has to be an instance!
|
|
target_field: Type.Optional(Type.String({ default: "id" })),
|
|
target_field_type: Type.Optional(StringEnum(["integer", "text"], { default: "integer" })),
|
|
on_delete: Type.Optional(StringEnum(CASCADES, { default: "set null" })),
|
|
}),
|
|
]);
|
|
|
|
export type RelationFieldConfig = Static<typeof relationFieldConfigSchema>;
|
|
export type RelationFieldBaseConfig = { label?: string };
|
|
|
|
export class RelationField extends Field<RelationFieldConfig> {
|
|
override readonly type = "relation";
|
|
|
|
protected getSchema() {
|
|
return relationFieldConfigSchema;
|
|
}
|
|
|
|
static create(
|
|
relation: EntityRelation,
|
|
target: EntityRelationAnchor,
|
|
config?: RelationFieldBaseConfig,
|
|
) {
|
|
const name = [
|
|
target.reference ?? target.entity.name,
|
|
target.entity.getPrimaryField().name,
|
|
].join("_");
|
|
|
|
return new RelationField(name, {
|
|
...config,
|
|
required: relation.required,
|
|
reference: target.reference,
|
|
target: target.entity.name,
|
|
target_field: target.entity.getPrimaryField().name,
|
|
target_field_type: target.entity.getPrimaryField().fieldType,
|
|
});
|
|
}
|
|
|
|
reference() {
|
|
return this.config.reference;
|
|
}
|
|
|
|
target() {
|
|
return this.config.target;
|
|
}
|
|
|
|
targetField(): string {
|
|
return this.config.target_field!;
|
|
}
|
|
|
|
override schema() {
|
|
return Object.freeze({
|
|
...super.schema()!,
|
|
type: this.config.target_field_type ?? "integer",
|
|
references: `${this.config.target}.${this.config.target_field}`,
|
|
onDelete: this.config.on_delete ?? "set null",
|
|
});
|
|
}
|
|
|
|
override transformRetrieve(value: any): any {
|
|
return value;
|
|
}
|
|
|
|
override async transformPersist(value: any, em: EntityManager<any>): Promise<any> {
|
|
throw new Error("RelationField: This function should not be called");
|
|
}
|
|
|
|
override toJsonSchema() {
|
|
return this.toSchemaWrapIfRequired(
|
|
Type.Number({
|
|
$ref: `${this.config?.target}#/properties/${this.config?.target_field}`,
|
|
}),
|
|
);
|
|
}
|
|
|
|
override toType(): TFieldTSType {
|
|
return {
|
|
...super.toType(),
|
|
type: "number",
|
|
};
|
|
}
|
|
}
|