import { type Static, StringEnum, StringRecord, objectTransform } from "core/utils"; import * as tb from "@sinclair/typebox"; import { MediaField, mediaFieldConfigSchema } from "../media/MediaField"; import { FieldClassMap } from "data/fields"; import { RelationClassMap, RelationFieldClassMap } from "data/relations"; import { entityConfigSchema, entityTypes } from "data/entities"; import { primaryFieldTypes } from "./fields"; export const FIELDS = { ...FieldClassMap, ...RelationFieldClassMap, media: { schema: mediaFieldConfigSchema, field: MediaField }, }; export type FieldType = keyof typeof FIELDS; export const RELATIONS = RelationClassMap; export const fieldsSchemaObject = objectTransform(FIELDS, (field, name) => { return tb.Type.Object( { type: tb.Type.Const(name, { default: name, readOnly: true }), config: tb.Type.Optional(field.schema), }, { title: name, }, ); }); export const fieldsSchema = tb.Type.Union(Object.values(fieldsSchemaObject)); export const entityFields = StringRecord(fieldsSchema); export type TAppDataField = Static; export type TAppDataEntityFields = Static; export const entitiesSchema = tb.Type.Object({ type: tb.Type.Optional( tb.Type.String({ enum: entityTypes, default: "regular", readOnly: true }), ), config: tb.Type.Optional(entityConfigSchema), fields: tb.Type.Optional(entityFields), }); export type TAppDataEntity = Static; export const relationsSchema = Object.entries(RelationClassMap).map(([name, relationClass]) => { return tb.Type.Object( { type: tb.Type.Const(name, { default: name, readOnly: true }), source: tb.Type.String(), target: tb.Type.String(), config: tb.Type.Optional(relationClass.schema), }, { title: name, }, ); }); export type TAppDataRelation = Static<(typeof relationsSchema)[number]>; export const indicesSchema = tb.Type.Object( { entity: tb.Type.String(), fields: tb.Type.Array(tb.Type.String(), { minItems: 1 }), unique: tb.Type.Optional(tb.Type.Boolean({ default: false })), }, { additionalProperties: false, }, ); export const dataConfigSchema = tb.Type.Object( { basepath: tb.Type.Optional(tb.Type.String({ default: "/api/data" })), default_primary_format: tb.Type.Optional( StringEnum(primaryFieldTypes, { default: "integer" }), ), entities: tb.Type.Optional(StringRecord(entitiesSchema, { default: {} })), relations: tb.Type.Optional(StringRecord(tb.Type.Union(relationsSchema), { default: {} })), indices: tb.Type.Optional(StringRecord(indicesSchema, { default: {} })), }, { additionalProperties: false, }, ); export type AppDataConfig = Static;