import { err, ok, type CommandContext } from "@tailor-platform/erp-kit/core"; import type { Transaction } from "../generated/kysely-tailordb"; import { DuplicateLabelNameError, InvalidNameError, LabelNotFoundError, } from "../lib/errors.generated"; export interface UpdatePipelineLabelInput { labelId: string; name?: string; color?: string | null; description?: string | null; } const LABEL_OWN_KEYS = new Set(["labelId", "name", "color", "description"]); // Module-managed PipelineLabel columns that must never be writable through the // extension-field pass-through. const LABEL_RESERVED_KEYS = new Set(["id", "pipelineId", "createdAt", "updatedAt"]); export async function run>( db: Transaction, input: UpdatePipelineLabelInput & Partial, ctx: CommandContext, ) { void ctx; // Consumer extension fields (declared via defineModule's pipelineLabel.fields) // pass through to the update untouched — except reserved model columns. const customFields: Record = {}; for (const [key, value] of Object.entries(input as Record)) { if (!LABEL_OWN_KEYS.has(key) && !LABEL_RESERVED_KEYS.has(key)) { customFields[key] = value; } } const label = await db .selectFrom("PipelineLabel") .selectAll() .where("id", "=", input.labelId) .forUpdate() .executeTakeFirst(); if (!label) { return err(new LabelNotFoundError(input.labelId)); } if (input.name !== undefined) { if (!input.name.trim()) { return err(new InvalidNameError(input.name)); } if (input.name !== label.name) { const duplicate = await db .selectFrom("PipelineLabel") .selectAll() .where("pipelineId", "=", label.pipelineId) .where("name", "=", input.name) .executeTakeFirst(); if (duplicate && duplicate.id !== label.id) { return err(new DuplicateLabelNameError(input.name)); } } } const update: Record = { ...customFields, updatedAt: new Date(), }; if (input.name !== undefined) update.name = input.name; if (input.color !== undefined) update.color = input.color; if (input.description !== undefined) update.description = input.description; const updatedLabel = await db .updateTable("PipelineLabel") .set(update) .where("id", "=", input.labelId) .returningAll() .executeTakeFirst(); return ok({ label: updatedLabel ?? { ...label, ...update } }); }