| |
| |
| |
| |
|
|
| import type { Database } from "@midday/db/client"; |
| import { createLoggerWithContext } from "@midday/logger"; |
|
|
| const logger = createLoggerWithContext("status-management"); |
|
|
| |
| |
| |
| |
| export type StatusTransition<T extends string> = { |
| from: T | null; |
| to: T; |
| }; |
|
|
| |
| |
| |
| |
| export async function updateStatusAtomically<T extends string>( |
| _db: Database, |
| table: { update: (data: unknown) => unknown }, |
| id: string, |
| newStatus: T, |
| dataUpdate?: Record<string, unknown>, |
| validTransitions?: Array<StatusTransition<T>>, |
| ): Promise<void> { |
| |
| if (validTransitions && validTransitions.length > 0) { |
| |
| |
| logger.debug( |
| "Status transition validation skipped (requires current status query)", |
| { |
| id, |
| newStatus, |
| }, |
| ); |
| } |
|
|
| try { |
| |
| |
| const updateData: Record<string, unknown> = { |
| ...dataUpdate, |
| status: newStatus, |
| }; |
|
|
| await table.update(updateData); |
| logger.debug("Status updated atomically", { |
| id, |
| newStatus, |
| hasDataUpdate: !!dataUpdate, |
| }); |
| } catch (error) { |
| logger.error("Failed to update status atomically", { |
| id, |
| newStatus, |
| error: error instanceof Error ? error.message : "Unknown error", |
| }); |
| throw error; |
| } |
| } |
|
|
| |
| |
| |
| |
| export function isValidStatusTransition<T extends string>( |
| currentStatus: T | null, |
| newStatus: T, |
| validTransitions: Array<StatusTransition<T>>, |
| ): boolean { |
| |
| const isAllowed = validTransitions.some( |
| (transition) => |
| (transition.from === null || transition.from === currentStatus) && |
| transition.to === newStatus, |
| ); |
|
|
| if (!isAllowed) { |
| logger.warn("Invalid status transition", { |
| currentStatus, |
| newStatus, |
| allowedTransitions: validTransitions, |
| }); |
| } |
|
|
| return isAllowed; |
| } |
|
|