Files
kochwas/src/lib/server/shopping/repository.ts
hsiegeln 83fe95ac76
All checks were successful
Build & Publish Docker Image / build-and-push (push) Successful in 2m27s
feat(shopping): removeRecipeFromCart
2026-04-21 22:56:26 +02:00

96 lines
2.7 KiB
TypeScript

import type Database from 'better-sqlite3';
// Fallback when a recipe has no servings_default set — matches the default
// used by RecipeEditor's "new recipe" template.
const DEFAULT_SERVINGS = 4;
export type ShoppingCartRecipe = {
recipe_id: number;
title: string;
image_path: string | null;
servings: number;
servings_default: number;
};
export type ShoppingListRow = {
name_key: string;
unit_key: string;
display_name: string;
display_unit: string | null;
total_quantity: number | null;
from_recipes: string;
checked: 0 | 1;
};
export type ShoppingListSnapshot = {
recipes: ShoppingCartRecipe[];
rows: ShoppingListRow[];
uncheckedCount: number;
};
export function addRecipeToCart(
db: Database.Database,
recipeId: number,
profileId: number | null,
servings?: number
): void {
const row = db
.prepare('SELECT servings_default FROM recipe WHERE id = ?')
.get(recipeId) as { servings_default: number | null } | undefined;
const resolved = servings ?? row?.servings_default ?? DEFAULT_SERVINGS;
// ON CONFLICT updates only servings — added_by_profile_id stays with the
// first profile that added the recipe (household cart, audit trail).
db.prepare(
`INSERT INTO shopping_cart_recipe (recipe_id, servings, added_by_profile_id)
VALUES (?, ?, ?)
ON CONFLICT(recipe_id) DO UPDATE SET servings = excluded.servings`
).run(recipeId, resolved, profileId);
}
export function removeRecipeFromCart(
db: Database.Database,
recipeId: number
): void {
db.prepare('DELETE FROM shopping_cart_recipe WHERE recipe_id = ?').run(recipeId);
}
export function setCartServings(
_db: Database.Database,
_recipeId: number,
_servings: number
): void {
throw new Error('not implemented');
}
export function listShoppingList(db: Database.Database): ShoppingListSnapshot {
const recipes = db
.prepare(
`SELECT cr.recipe_id, r.title, r.image_path, cr.servings,
COALESCE(r.servings_default, cr.servings) AS servings_default
FROM shopping_cart_recipe cr
JOIN recipe r ON r.id = cr.recipe_id
ORDER BY cr.added_at ASC`
)
.all() as ShoppingCartRecipe[];
// TODO(Task 6): rows + uncheckedCount are populated by the aggregation query.
// Until then, callers must not rely on these fields.
return { recipes, rows: [], uncheckedCount: 0 };
}
export function toggleCheck(
_db: Database.Database,
_nameKey: string,
_unitKey: string,
_checked: boolean
): void {
throw new Error('not implemented');
}
export function clearCheckedItems(_db: Database.Database): void {
throw new Error('not implemented');
}
export function clearCart(_db: Database.Database): void {
throw new Error('not implemented');
}