/** Row shape returned by PostgreSQL (snake_case). */ export interface RaceRow { id: string; race_date: string; title: string; distance_km: string; status: string | null; official_url: string | null; start_time: string | null; cluster_schedule: string | null; bib_pickup: string | null; bib_number: string | null; finish_time: string | null; finish_place: string | null; notes: string | null; created_at: string; updated_at: string | null; } /** API shape (camelCase). */ export interface RaceDto { id: string; date: string; title: string; distanceKm: number; status: string | null; officialUrl: string | null; startTime: string | null; clusterSchedule: string | null; bibPickup: string | null; bibNumber: string | null; finishTime: string | null; finishPlace: string | null; notes: string | null; createdAt: string; updatedAt: string | null; } /** Convert a DB row to the API DTO (camelCase). */ export function rowToDto(row: RaceRow): RaceDto { return { id: row.id, date: row.race_date, title: row.title, distanceKm: parseFloat(row.distance_km), status: row.status, officialUrl: row.official_url, startTime: row.start_time, clusterSchedule: row.cluster_schedule, bibPickup: row.bib_pickup, bibNumber: row.bib_number, finishTime: row.finish_time, finishPlace: row.finish_place, notes: row.notes, createdAt: row.created_at, updatedAt: row.updated_at, }; } /** Map incoming camelCase body fields to snake_case column names. */ const FIELD_MAP: Record = { date: "race_date", title: "title", distanceKm: "distance_km", status: "status", officialUrl: "official_url", startTime: "start_time", clusterSchedule: "cluster_schedule", bibPickup: "bib_pickup", bibNumber: "bib_number", finishTime: "finish_time", finishPlace: "finish_place", notes: "notes", }; /** * Convert a partial camelCase body into { columns, values, placeholders } * suitable for SQL INSERT / UPDATE. */ export function bodyToColumns(body: Record) { const columns: string[] = []; const values: unknown[] = []; for (const [camel, snake] of Object.entries(FIELD_MAP)) { if (camel in body) { columns.push(snake); values.push(body[camel]); } } return { columns, values }; }