import { ok, err } from "@tailor-platform/erp-kit/core"; import type { Transaction, Updateable } from "../generated/kysely-tailordb"; import { InvalidEmailError, InvalidNameError, MissingRequiredFieldError, UserAlreadyExistsError, UserNotFoundError, } from "../lib/errors.generated"; export type UpdateUserInput = { id: string } & { name?: string; email?: string }; const EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; /** * Function: updateUser * * Updates an existing user's name or email. * At least one field must be provided. Email must be unique. */ export async function run>( db: Transaction, input: UpdateUserInput & Omit, "status">, ) { const { id, name, email, ...customFields } = input; if (name === undefined && email === undefined && Object.keys(customFields).length === 0) { return err(new MissingRequiredFieldError("name or email")); } if (name?.trim() === "") { return err(new InvalidNameError(name)); } if (email !== undefined && !EMAIL_PATTERN.test(email)) { return err(new InvalidEmailError(email)); } const user = await db .selectFrom("User") .selectAll() .where("id", "=", id) .forUpdate() .executeTakeFirst(); if (!user) { return err(new UserNotFoundError(id)); } if (email !== undefined && email !== user.email) { const existingUser = await db .selectFrom("User") .selectAll() .where("email", "=", email) .forUpdate() .executeTakeFirst(); if (existingUser) { return err(new UserAlreadyExistsError(email)); } } const updates: Updateable<"User"> = { ...(customFields as Updateable<"User">), }; if (name !== undefined) updates.name = name; if (email !== undefined) updates.email = email; const updatedUser = await db .updateTable("User") .set(updates) .where("id", "=", id) .returningAll() .executeTakeFirstOrThrow(); return ok({ user: updatedUser }); }