diff --git a/packages/db/generated/attributeSupplementSchema.ts b/packages/db/generated/attributeSupplementSchema.ts new file mode 100644 index 0000000000..fc6480b32a --- /dev/null +++ b/packages/db/generated/attributeSupplementSchema.ts @@ -0,0 +1,30 @@ +import { z } from 'zod' + +export const attributeSupplementSchema = { + accessInstructions: z.object({ + access_type: z.enum(['email', 'file', 'link', 'location', 'other', 'phone']), + access_value: z.union([z.string(), z.null()]).optional(), + instructions: z.string(), + }), + currency: z.any(), + incompatible: z.any(), + incompatibleData: z.array(z.record(z.any())), + number: z.object({ num: z.number() }), + 'num-max': z.any(), + numMax: z.object({ max: z.number() }), + 'num-min': z.any(), + numMin: z.object({ min: z.number() }), + 'num-min-max': z.any(), + numMinMaxOrRange: z.union([ + z.object({ min: z.number() }), + z.object({ max: z.number() }), + z.object({ max: z.number(), min: z.number() }), + ]), + numRange: z.object({ max: z.number(), min: z.number() }), + otherDescribe: z.object({ other: z.string() }), +} + +export const isAttributeSupplementSchema = (schema: string): schema is AttributeSupplementSchemas => + Object.keys(attributeSupplementSchema).includes(schema) + +export type AttributeSupplementSchemas = keyof typeof attributeSupplementSchema diff --git a/packages/db/lib/generateData.ts b/packages/db/lib/generateData.ts index af5986c364..486a147497 100644 --- a/packages/db/lib/generateData.ts +++ b/packages/db/lib/generateData.ts @@ -39,6 +39,7 @@ const tasks = new Listr( defineJob('Service Categories', job.generateServiceCategories), defineJob('Language lists', job.generateLanguageFiles), defineJob('Translation Namespaces', job.generateNamespaces), + defineJob('Attribute Supplement Data Schemas', job.generateDataSchemas), ], { concurrent: true } ), diff --git a/packages/db/lib/generators/attributeSuppDataSchemas.ts b/packages/db/lib/generators/attributeSuppDataSchemas.ts new file mode 100644 index 0000000000..7d557a76c0 --- /dev/null +++ b/packages/db/lib/generators/attributeSuppDataSchemas.ts @@ -0,0 +1,35 @@ +import { type JsonSchemaObject, jsonSchemaToZod } from 'json-schema-to-zod' + +import { prisma } from '~db/client' +import { type ListrTask } from '~db/lib/generateData' + +import { writeOutput } from './common' + +export const generateDataSchemas = async (task: ListrTask) => { + const data = await prisma.attributeSupplementDataSchema.findMany({ + where: { + active: true, + }, + select: { + tag: true, + schema: true, + }, + orderBy: { tag: 'asc' }, + }) + const schemas = data.map(({ tag, schema }) => { + return `"${tag}": ${jsonSchemaToZod(schema as JsonSchemaObject)},` + }) + + const out = ` + import { z } from 'zod'; + export const attributeSupplementSchema = { + ${schemas.join('\n')} + } + + export const isAttributeSupplementSchema = (schema: string): schema is AttributeSupplementSchemas => Object.keys(attributeSupplementSchema).includes(schema) + + export type AttributeSupplementSchemas = keyof typeof attributeSupplementSchema + ` + await writeOutput('attributeSupplementSchema', out) + task.title = `${task.title} (${data.length} items)` +} diff --git a/packages/db/lib/generators/index.ts b/packages/db/lib/generators/index.ts index 17e4078d0f..91661da73a 100644 --- a/packages/db/lib/generators/index.ts +++ b/packages/db/lib/generators/index.ts @@ -2,6 +2,7 @@ export * from './allAttributes' export * from './attributeCategory' export * from './attributesByCategory' +export * from './attributeSuppDataSchemas' export * from './langs' export * from './namespaces' export * from './permission' diff --git a/packages/db/package.json b/packages/db/package.json index 6b72ec4d5e..66d9c7e3bd 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -51,6 +51,7 @@ "@weareinreach/env": "workspace:*", "@weareinreach/util": "workspace:*", "id128": "1.6.6", + "json-schema-to-zod": "2.0.14", "kysely": "0.27.2", "pg": "8.11.3", "prisma-kysely": "1.8.0", diff --git a/packages/db/prisma/migrations/20240214173007_attribute_supplement_schemas/migration.sql b/packages/db/prisma/migrations/20240214173007_attribute_supplement_schemas/migration.sql new file mode 100644 index 0000000000..3ccd720ef8 --- /dev/null +++ b/packages/db/prisma/migrations/20240214173007_attribute_supplement_schemas/migration.sql @@ -0,0 +1,48 @@ +/* + Warnings: + + - Added the required column `schema` to the `AttributeSupplementDataSchema` table without a default value. This is not possible if the table is not empty. + */ +-- AlterTable +ALTER TABLE "AttributeSupplementDataSchema" + ADD COLUMN "schema" JSONB; + +UPDATE + "AttributeSupplementDataSchema" +SET + "schema" = "definition"; + +ALTER TABLE "AttributeSupplementDataSchema" + ALTER COLUMN "schema" SET NOT NULL; + +-- CreateIndex +CREATE INDEX IF NOT EXISTS "AttributeSupplement_active_attributeId_idx" ON + "AttributeSupplement"("active", "attributeId"); + +-- CreateIndex +CREATE INDEX IF NOT EXISTS "OrgLocationService_active_serviceId_idx" ON + "OrgLocationService"("active", "serviceId"); + +-- CreateIndex +CREATE INDEX IF NOT EXISTS "OrgService_organizationId_published_deleted_idx" ON + "OrgService"("organizationId", "published" DESC, "deleted"); + +-- CreateIndex +CREATE INDEX IF NOT EXISTS "ServiceArea_active_organizationId_idx" ON + "ServiceArea"("active", "organizationId"); + +-- CreateIndex +CREATE INDEX IF NOT EXISTS "ServiceArea_active_orgLocationId_idx" ON + "ServiceArea"("active", "orgLocationId"); + +-- CreateIndex +CREATE INDEX IF NOT EXISTS "ServiceArea_active_orgServiceId_idx" ON + "ServiceArea"("active", "orgServiceId"); + +-- CreateIndex +CREATE INDEX IF NOT EXISTS "ServiceAreaCountry_active_serviceAreaId_idx" ON + "ServiceAreaCountry"("active", "serviceAreaId"); + +-- CreateIndex +CREATE INDEX IF NOT EXISTS "ServiceAreaDist_active_serviceAreaId_idx" ON + "ServiceAreaDist"("active", "serviceAreaId"); diff --git a/packages/db/prisma/schema.prisma b/packages/db/prisma/schema.prisma index d3f68836ee..9b9f04b707 100644 --- a/packages/db/prisma/schema.prisma +++ b/packages/db/prisma/schema.prisma @@ -1062,6 +1062,7 @@ model AttributeSupplementDataSchema { name String active Boolean @default(true) definition Json + schema Json // entryComponent String? createdAt DateTime @default(now()) diff --git a/packages/db/zod_util/attributeSupplement.ts b/packages/db/zod_util/attributeSupplement.ts index 9ca2a5fd9c..5e0cd88f7f 100644 --- a/packages/db/zod_util/attributeSupplement.ts +++ b/packages/db/zod_util/attributeSupplement.ts @@ -131,3 +131,37 @@ export const AttSuppSchemas = { } export type AttributeSupplementSchemas = keyof typeof AttSuppSchemas +/** Dynamic Fields for Supplement Data Schemas */ + +export enum FieldType { + text = 'text', + select = 'select', + number = 'number', + currency = 'currency', +} +interface BaseFieldAttributes { + key: string + label: string + name: string + type: FieldType + required?: boolean +} + +interface TextFieldAttributes extends BaseFieldAttributes { + type: FieldType.text +} +interface SelectFieldAttributes extends BaseFieldAttributes { + type: FieldType.select + options: { value: string; label: string }[] +} +interface NumberFieldAttributes extends BaseFieldAttributes { + type: FieldType.number +} +interface CurrencyFieldAttributes extends BaseFieldAttributes { + type: FieldType.currency +} +export type FieldAttributes = + | TextFieldAttributes + | SelectFieldAttributes + | NumberFieldAttributes + | CurrencyFieldAttributes diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d8b6fc4a5d..0293d8e3b3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -961,6 +961,9 @@ importers: id128: specifier: 1.6.6 version: 1.6.6 + json-schema-to-zod: + specifier: 2.0.14 + version: 2.0.14 kysely: specifier: 0.27.2 version: 0.27.2