import { eq, desc, and } from 'drizzle-orm'; import { db } from '@/db'; import { recipes } from '@/db/schema'; import type { Recipe, SavedRecipe } from './recipe'; import { ApiError } from './server'; export function serialize(row: typeof recipes.$inferSelect): SavedRecipe { return { ...row.data, steps: row.data.steps.map((step) => ({ ...step, images: step.images ?? [] })), id: row.id, title: row.title, published: row.published, createdAt: row.createdAt.toISOString(), updatedAt: row.updatedAt.toISOString(), }; } export async function listRecipes(isAdmin = false) { return ( await db .select() .from(recipes) .where(isAdmin ? undefined : eq(recipes.published, true)) .orderBy(desc(recipes.createdAt)) ).map(serialize); } export async function getRecipe(id: string, isAdmin = false) { if (!/^[0-9a-f-]{36}$/i.test(id)) return null; const [row] = await db .select() .from(recipes) .where(and(eq(recipes.id, id), isAdmin ? undefined : eq(recipes.published, true))); return row ? serialize(row) : null; } export const titleKey = (title: string) => title.normalize('NFKC').trim().toLocaleLowerCase('de'); export async function saveRecipe(data: Recipe, id?: string, expected?: string) { const values = { title: data.title, titleKey: titleKey(data.title), published: data.published, data, updatedAt: new Date(), }; if (id) { if (!expected) throw new ApiError(428, 'Versionsstand zum Speichern fehlt.'); const [row] = await db .update(recipes) .set(values) .where(and(eq(recipes.id, id), eq(recipes.updatedAt, new Date(expected)))) .returning(); if (!row) throw new ApiError( 409, 'Das Rezept wurde zwischenzeitlich verändert. Entwurf sichern und Seite neu laden.', ); return serialize(row); } const [row] = await db.insert(recipes).values(values).returning(); return serialize(row); }