import { TRPCError } from "@trpc/server"; import { z } from "zod"; import { asc, eq } from "drizzle-orm"; import { propertyDefinitions, propertyValues, } from "@tasks/database/schema"; import { router, protectedProcedure } from "@/server/trpc"; export const propertiesRouter = router({ listDefinitions: protectedProcedure .input(z.object({ workspaceId: z.string().uuid() })) .query(async ({ ctx, input }) => { const definitions = await ctx.db .select() .from(propertyDefinitions) .where(eq(propertyDefinitions.workspaceId, input.workspaceId)) .orderBy(asc(propertyDefinitions.sortOrder), asc(propertyDefinitions.id)); return { definitions }; }), createDefinition: protectedProcedure .input( z.object({ workspaceId: z.string().uuid(), name: z.string().min(1).max(255), fieldType: z.string().min(1).max(50), config: z.any().optional(), }), ) .mutation(async ({ ctx, input }) => { const [created] = await ctx.db .insert(propertyDefinitions) .values({ workspaceId: input.workspaceId, name: input.name, fieldType: input.fieldType, config: input.config ?? null, }) .returning(); if (!created) { throw new TRPCError({ code: "INTERNAL_SERVER_ERROR", message: "Failed to create property definition", }); } return created; }), getValues: protectedProcedure .input(z.object({ objectId: z.string().uuid() })) .query(async ({ ctx, input }) => { const rows = await ctx.db .select({ valueRow: propertyValues, definition: propertyDefinitions, }) .from(propertyValues) .innerJoin( propertyDefinitions, eq(propertyValues.propertyDefId, propertyDefinitions.id), ) .where(eq(propertyValues.objectId, input.objectId)) .orderBy(asc(propertyDefinitions.sortOrder), asc(propertyDefinitions.id)); return { values: rows.map((r) => ({ ...r.valueRow, definition: r.definition, })), }; }), setValue: protectedProcedure .input( z.object({ objectId: z.string().uuid(), propertyDefId: z.string().uuid(), value: z.any(), }), ) .mutation(async ({ ctx, input }) => { const now = new Date(); const [row] = await ctx.db .insert(propertyValues) .values({ objectId: input.objectId, propertyDefId: input.propertyDefId, value: input.value, updatedAt: now, }) .onConflictDoUpdate({ target: [propertyValues.objectId, propertyValues.propertyDefId], set: { value: input.value, updatedAt: now, }, }) .returning(); if (!row) { throw new TRPCError({ code: "INTERNAL_SERVER_ERROR", message: "Failed to set property value", }); } return row; }), });