import type Database from 'better-sqlite3'; export type RatingRow = { profile_id: number; stars: number }; export type CommentRow = { id: number; profile_id: number; text: string; created_at: string; author: string; }; export type CookedRow = { id: number; profile_id: number; cooked_at: string }; export function setRating( db: Database.Database, recipeId: number, profileId: number, stars: number ): void { if (stars < 1 || stars > 5) throw new Error('stars must be 1..5'); db.prepare( `INSERT INTO rating(recipe_id, profile_id, stars) VALUES (?, ?, ?) ON CONFLICT(recipe_id, profile_id) DO UPDATE SET stars = excluded.stars, updated_at = CURRENT_TIMESTAMP` ).run(recipeId, profileId, stars); } export function clearRating( db: Database.Database, recipeId: number, profileId: number ): void { db.prepare('DELETE FROM rating WHERE recipe_id = ? AND profile_id = ?').run( recipeId, profileId ); } export function listRatings(db: Database.Database, recipeId: number): RatingRow[] { return db .prepare('SELECT profile_id, stars FROM rating WHERE recipe_id = ?') .all(recipeId) as RatingRow[]; } export function addFavorite( db: Database.Database, recipeId: number, profileId: number ): void { db.prepare( 'INSERT OR IGNORE INTO favorite(recipe_id, profile_id) VALUES (?, ?)' ).run(recipeId, profileId); } export function removeFavorite( db: Database.Database, recipeId: number, profileId: number ): void { db.prepare('DELETE FROM favorite WHERE recipe_id = ? AND profile_id = ?').run( recipeId, profileId ); } export function isFavorite( db: Database.Database, recipeId: number, profileId: number ): boolean { return ( db .prepare('SELECT 1 AS ok FROM favorite WHERE recipe_id = ? AND profile_id = ?') .get(recipeId, profileId) !== undefined ); } export function listFavoriteProfiles( db: Database.Database, recipeId: number ): number[] { return ( db .prepare('SELECT profile_id FROM favorite WHERE recipe_id = ?') .all(recipeId) as { profile_id: number }[] ).map((r) => r.profile_id); } export function logCooked( db: Database.Database, recipeId: number, profileId: number ): CookedRow { return db .prepare( `INSERT INTO cooking_log(recipe_id, profile_id) VALUES (?, ?) RETURNING id, profile_id, cooked_at` ) .get(recipeId, profileId) as CookedRow; } export function listCookingLog( db: Database.Database, recipeId: number ): CookedRow[] { return db .prepare( 'SELECT id, profile_id, cooked_at FROM cooking_log WHERE recipe_id = ? ORDER BY cooked_at DESC' ) .all(recipeId) as CookedRow[]; } export function addComment( db: Database.Database, recipeId: number, profileId: number, text: string ): number { const trimmed = text.trim(); if (!trimmed) throw new Error('comment text cannot be empty'); const info = db .prepare('INSERT INTO comment(recipe_id, profile_id, text) VALUES (?, ?, ?)') .run(recipeId, profileId, trimmed); return Number(info.lastInsertRowid); } export function deleteComment(db: Database.Database, id: number): void { db.prepare('DELETE FROM comment WHERE id = ?').run(id); } export function listComments(db: Database.Database, recipeId: number): CommentRow[] { return db .prepare( `SELECT c.id, c.profile_id, c.text, c.created_at, p.name AS author FROM comment c JOIN profile p ON p.id = c.profile_id WHERE c.recipe_id = ? ORDER BY c.created_at ASC` ) .all(recipeId) as CommentRow[]; } export function renameRecipe( db: Database.Database, recipeId: number, newTitle: string ): void { const trimmed = newTitle.trim(); if (!trimmed) throw new Error('title cannot be empty'); db.prepare('UPDATE recipe SET title = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?').run( trimmed, recipeId ); }