import { err, ok, type CommandContext } from "@tailor-platform/erp-kit/core"; import type { Transaction } from "../generated/kysely-tailordb"; import { DuplicateLabelNameError, InvalidNameError, PipelineArchivedError, PipelineNotFoundError, } from "../lib/errors.generated"; export interface CreatePipelineLabelInput { pipelineId: string; name: string; color?: string; description?: string; } const LABEL_OWN_KEYS = new Set(["pipelineId", "name", "color", "description"]); export async function run>( db: Transaction, input: CreatePipelineLabelInput & CF, ctx: CommandContext, ) { void ctx; // Consumer extension fields (declared via defineModule's pipelineLabel.fields) // pass through to the insert untouched. const customFields: Record = {}; for (const [key, value] of Object.entries(input as Record)) { if (!LABEL_OWN_KEYS.has(key)) { customFields[key] = value; } } const pipeline = await db .selectFrom("Pipeline") .selectAll() .where("id", "=", input.pipelineId) .executeTakeFirst(); if (!pipeline) { return err(new PipelineNotFoundError(input.pipelineId)); } if (pipeline.status !== "ACTIVE") { return err(new PipelineArchivedError(input.pipelineId)); } if (!input.name.trim()) { return err(new InvalidNameError(input.name)); } const duplicate = await db .selectFrom("PipelineLabel") .selectAll() .where("pipelineId", "=", input.pipelineId) .where("name", "=", input.name) .executeTakeFirst(); if (duplicate) { return err(new DuplicateLabelNameError(input.name)); } const label = await db .insertInto("PipelineLabel") .values({ ...customFields, pipelineId: input.pipelineId, name: input.name, color: input.color ?? null, description: input.description ?? null, createdAt: new Date(), }) .returningAll() .executeTakeFirstOrThrow(); return ok({ label }); }