import { ok, err } from "@tailor-platform/erp-kit/core"; import type { Transaction, Updateable } from "../generated/kysely-tailordb"; import { AttributeNotFoundError, MissingRequiredFieldError } from "../lib/errors.generated"; export type UpdateProductAttributeInput = ( | { id: string; } | { code: string; } ) & { name?: string; }; /** * Function: updateProductAttribute * * Updates the display name of an existing product attribute. * The attribute can be looked up by id or code. */ export async function run>( db: Transaction, input: UpdateProductAttributeInput & Omit, "status">, ) { const { name } = input; const KNOWN_KEYS = new Set(["id", "code", "name"]); const customFields: Record = {}; for (const [key, value] of Object.entries(input as Record)) { if (!KNOWN_KEYS.has(key)) { customFields[key] = value; } } // 1. Check attribute exists (lookup by id or code) const attribute = "id" in input ? await db .selectFrom("ProductAttribute") .selectAll() .where("id", "=", (input as { id: string }).id) .forUpdate() .executeTakeFirst() : await db .selectFrom("ProductAttribute") .selectAll() .where("code", "=", (input as { code: string }).code) .forUpdate() .executeTakeFirst(); if (!attribute) { const key = "id" in input ? (input as { id: string }).id : (input as { code: string }).code; return err(new AttributeNotFoundError(key)); } const hasNameUpdate = name !== undefined; const hasCustomFields = Object.keys(customFields).length > 0; if (!hasNameUpdate && !hasCustomFields) { return err(new MissingRequiredFieldError(attribute.id)); } if (hasNameUpdate && !name?.trim()) { return err(new MissingRequiredFieldError("name")); } const updates: Updateable<"ProductAttribute"> = { ...(customFields as Updateable<"ProductAttribute">), }; if (hasNameUpdate) updates.name = name; const updated = await db .updateTable("ProductAttribute") .set(updates) .where("id", "=", attribute.id) .returningAll() .executeTakeFirstOrThrow(); return ok({ attribute: updated }); }