142 lines
3.6 KiB
TypeScript
142 lines
3.6 KiB
TypeScript
|
|
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 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
|
||
|
|
);
|
||
|
|
}
|