Files
kochwas/src/lib/server/wishlist/repository.ts

108 lines
2.8 KiB
TypeScript
Raw Normal View History

import type Database from 'better-sqlite3';
export type WishlistEntry = {
recipe_id: number;
title: string;
image_path: string | null;
source_domain: string | null;
feat(wishlist): per-user Wünsche + Header-Badge mit Gesamtzahl Schema-Änderung (Migration 005): - Tabelle wishlist umgestellt auf PK (recipe_id, profile_id) - wishlist_like-Tabelle zusammengelegt — Liken WAR schon "will ich auch", also werden alle bestehenden Likes Memberships auf der neuen Tabelle. - Alt-Einträge mit added_by_profile_id werden migriert, anonyme gehen verloren (war inkonsistent, jetzt erzwingen wir profile_id NOT NULL). Repository: - listWishlist aggregiert pro Rezept: wanted_by_count, wanted_by_names (kommagetrennt), on_my_wishlist für das aktive Profil - listWishlistProfileIds(recipeId) für den Recipe-Page-Loader - countWishlistRecipes für das Header-Badge (DISTINCT recipe_id) - addToWishlist/removeFromWishlist/isOnMyWishlist alle mit profile_id als Pflicht API: - POST /api/wishlist: profile_id jetzt Pflicht (nullable raus) - DELETE /api/wishlist/[recipe_id]?profile_id=X (nur eigenes Entry) - /api/wishlist/[recipe_id]/like komplett entfernt (Konzept obsolet) - Neu: GET /api/wishlist/count → { count: <distinct recipes> } UI: - Header-Heart bekommt rotes Badge mit Zahl der Wunschliste-Rezepte. wishlistStore in $lib/client/wishlist.svelte.ts hält den Count reaktiv; Refresh auf Mount, nach Add/Remove, beim Öffnen der Wunschliste. - Recipe-Detail: Loader liefert wishlist_profile_ids; onMyWishlist ist ein $derived. Toggle fragt aktives Profil (alertAction sonst), mutiert die lokale Liste + ruft wishlistStore.refresh. - Wunschliste-Seite: Heart toggelt eigenen Wunsch, Count zeigt Gesamt- wünsche, kommagetrennte Namen zeigen "wer will". Trash-Button entfernt — Heart-off reicht jetzt. Tests (99 → 99, 8 neu geschrieben): - Per-User-Add/Remove, aggregierte Counts, on_my_wishlist, Cascades bei Recipe/Profile-Delete, countWishlistRecipes = DISTINCT.
2026-04-17 19:16:19 +02:00
added_at: string; // earliest per recipe
wanted_by_count: number;
wanted_by_names: string; // comma-joined profile names
on_my_wishlist: 0 | 1;
avg_stars: number | null;
};
export type SortKey = 'popular' | 'newest' | 'oldest';
export function listWishlist(
db: Database.Database,
activeProfileId: number | null,
sort: SortKey = 'popular'
): WishlistEntry[] {
const orderBy = {
feat(wishlist): per-user Wünsche + Header-Badge mit Gesamtzahl Schema-Änderung (Migration 005): - Tabelle wishlist umgestellt auf PK (recipe_id, profile_id) - wishlist_like-Tabelle zusammengelegt — Liken WAR schon "will ich auch", also werden alle bestehenden Likes Memberships auf der neuen Tabelle. - Alt-Einträge mit added_by_profile_id werden migriert, anonyme gehen verloren (war inkonsistent, jetzt erzwingen wir profile_id NOT NULL). Repository: - listWishlist aggregiert pro Rezept: wanted_by_count, wanted_by_names (kommagetrennt), on_my_wishlist für das aktive Profil - listWishlistProfileIds(recipeId) für den Recipe-Page-Loader - countWishlistRecipes für das Header-Badge (DISTINCT recipe_id) - addToWishlist/removeFromWishlist/isOnMyWishlist alle mit profile_id als Pflicht API: - POST /api/wishlist: profile_id jetzt Pflicht (nullable raus) - DELETE /api/wishlist/[recipe_id]?profile_id=X (nur eigenes Entry) - /api/wishlist/[recipe_id]/like komplett entfernt (Konzept obsolet) - Neu: GET /api/wishlist/count → { count: <distinct recipes> } UI: - Header-Heart bekommt rotes Badge mit Zahl der Wunschliste-Rezepte. wishlistStore in $lib/client/wishlist.svelte.ts hält den Count reaktiv; Refresh auf Mount, nach Add/Remove, beim Öffnen der Wunschliste. - Recipe-Detail: Loader liefert wishlist_profile_ids; onMyWishlist ist ein $derived. Toggle fragt aktives Profil (alertAction sonst), mutiert die lokale Liste + ruft wishlistStore.refresh. - Wunschliste-Seite: Heart toggelt eigenen Wunsch, Count zeigt Gesamt- wünsche, kommagetrennte Namen zeigen "wer will". Trash-Button entfernt — Heart-off reicht jetzt. Tests (99 → 99, 8 neu geschrieben): - Per-User-Add/Remove, aggregierte Counts, on_my_wishlist, Cascades bei Recipe/Profile-Delete, countWishlistRecipes = DISTINCT.
2026-04-17 19:16:19 +02:00
popular: 'wanted_by_count DESC, first_added DESC',
newest: 'first_added DESC',
oldest: 'first_added ASC'
}[sort];
return db
.prepare(
`SELECT
w.recipe_id,
r.title,
r.image_path,
r.source_domain,
feat(wishlist): per-user Wünsche + Header-Badge mit Gesamtzahl Schema-Änderung (Migration 005): - Tabelle wishlist umgestellt auf PK (recipe_id, profile_id) - wishlist_like-Tabelle zusammengelegt — Liken WAR schon "will ich auch", also werden alle bestehenden Likes Memberships auf der neuen Tabelle. - Alt-Einträge mit added_by_profile_id werden migriert, anonyme gehen verloren (war inkonsistent, jetzt erzwingen wir profile_id NOT NULL). Repository: - listWishlist aggregiert pro Rezept: wanted_by_count, wanted_by_names (kommagetrennt), on_my_wishlist für das aktive Profil - listWishlistProfileIds(recipeId) für den Recipe-Page-Loader - countWishlistRecipes für das Header-Badge (DISTINCT recipe_id) - addToWishlist/removeFromWishlist/isOnMyWishlist alle mit profile_id als Pflicht API: - POST /api/wishlist: profile_id jetzt Pflicht (nullable raus) - DELETE /api/wishlist/[recipe_id]?profile_id=X (nur eigenes Entry) - /api/wishlist/[recipe_id]/like komplett entfernt (Konzept obsolet) - Neu: GET /api/wishlist/count → { count: <distinct recipes> } UI: - Header-Heart bekommt rotes Badge mit Zahl der Wunschliste-Rezepte. wishlistStore in $lib/client/wishlist.svelte.ts hält den Count reaktiv; Refresh auf Mount, nach Add/Remove, beim Öffnen der Wunschliste. - Recipe-Detail: Loader liefert wishlist_profile_ids; onMyWishlist ist ein $derived. Toggle fragt aktives Profil (alertAction sonst), mutiert die lokale Liste + ruft wishlistStore.refresh. - Wunschliste-Seite: Heart toggelt eigenen Wunsch, Count zeigt Gesamt- wünsche, kommagetrennte Namen zeigen "wer will". Trash-Button entfernt — Heart-off reicht jetzt. Tests (99 → 99, 8 neu geschrieben): - Per-User-Add/Remove, aggregierte Counts, on_my_wishlist, Cascades bei Recipe/Profile-Delete, countWishlistRecipes = DISTINCT.
2026-04-17 19:16:19 +02:00
MIN(w.added_at) AS first_added,
MIN(w.added_at) AS added_at,
COUNT(w.profile_id) AS wanted_by_count,
COALESCE(GROUP_CONCAT(p.name, ', '), '') AS wanted_by_names,
CASE
WHEN ? IS NULL THEN 0
feat(wishlist): per-user Wünsche + Header-Badge mit Gesamtzahl Schema-Änderung (Migration 005): - Tabelle wishlist umgestellt auf PK (recipe_id, profile_id) - wishlist_like-Tabelle zusammengelegt — Liken WAR schon "will ich auch", also werden alle bestehenden Likes Memberships auf der neuen Tabelle. - Alt-Einträge mit added_by_profile_id werden migriert, anonyme gehen verloren (war inkonsistent, jetzt erzwingen wir profile_id NOT NULL). Repository: - listWishlist aggregiert pro Rezept: wanted_by_count, wanted_by_names (kommagetrennt), on_my_wishlist für das aktive Profil - listWishlistProfileIds(recipeId) für den Recipe-Page-Loader - countWishlistRecipes für das Header-Badge (DISTINCT recipe_id) - addToWishlist/removeFromWishlist/isOnMyWishlist alle mit profile_id als Pflicht API: - POST /api/wishlist: profile_id jetzt Pflicht (nullable raus) - DELETE /api/wishlist/[recipe_id]?profile_id=X (nur eigenes Entry) - /api/wishlist/[recipe_id]/like komplett entfernt (Konzept obsolet) - Neu: GET /api/wishlist/count → { count: <distinct recipes> } UI: - Header-Heart bekommt rotes Badge mit Zahl der Wunschliste-Rezepte. wishlistStore in $lib/client/wishlist.svelte.ts hält den Count reaktiv; Refresh auf Mount, nach Add/Remove, beim Öffnen der Wunschliste. - Recipe-Detail: Loader liefert wishlist_profile_ids; onMyWishlist ist ein $derived. Toggle fragt aktives Profil (alertAction sonst), mutiert die lokale Liste + ruft wishlistStore.refresh. - Wunschliste-Seite: Heart toggelt eigenen Wunsch, Count zeigt Gesamt- wünsche, kommagetrennte Namen zeigen "wer will". Trash-Button entfernt — Heart-off reicht jetzt. Tests (99 → 99, 8 neu geschrieben): - Per-User-Add/Remove, aggregierte Counts, on_my_wishlist, Cascades bei Recipe/Profile-Delete, countWishlistRecipes = DISTINCT.
2026-04-17 19:16:19 +02:00
WHEN EXISTS (SELECT 1 FROM wishlist w2
WHERE w2.recipe_id = w.recipe_id AND w2.profile_id = ?)
THEN 1
ELSE 0
feat(wishlist): per-user Wünsche + Header-Badge mit Gesamtzahl Schema-Änderung (Migration 005): - Tabelle wishlist umgestellt auf PK (recipe_id, profile_id) - wishlist_like-Tabelle zusammengelegt — Liken WAR schon "will ich auch", also werden alle bestehenden Likes Memberships auf der neuen Tabelle. - Alt-Einträge mit added_by_profile_id werden migriert, anonyme gehen verloren (war inkonsistent, jetzt erzwingen wir profile_id NOT NULL). Repository: - listWishlist aggregiert pro Rezept: wanted_by_count, wanted_by_names (kommagetrennt), on_my_wishlist für das aktive Profil - listWishlistProfileIds(recipeId) für den Recipe-Page-Loader - countWishlistRecipes für das Header-Badge (DISTINCT recipe_id) - addToWishlist/removeFromWishlist/isOnMyWishlist alle mit profile_id als Pflicht API: - POST /api/wishlist: profile_id jetzt Pflicht (nullable raus) - DELETE /api/wishlist/[recipe_id]?profile_id=X (nur eigenes Entry) - /api/wishlist/[recipe_id]/like komplett entfernt (Konzept obsolet) - Neu: GET /api/wishlist/count → { count: <distinct recipes> } UI: - Header-Heart bekommt rotes Badge mit Zahl der Wunschliste-Rezepte. wishlistStore in $lib/client/wishlist.svelte.ts hält den Count reaktiv; Refresh auf Mount, nach Add/Remove, beim Öffnen der Wunschliste. - Recipe-Detail: Loader liefert wishlist_profile_ids; onMyWishlist ist ein $derived. Toggle fragt aktives Profil (alertAction sonst), mutiert die lokale Liste + ruft wishlistStore.refresh. - Wunschliste-Seite: Heart toggelt eigenen Wunsch, Count zeigt Gesamt- wünsche, kommagetrennte Namen zeigen "wer will". Trash-Button entfernt — Heart-off reicht jetzt. Tests (99 → 99, 8 neu geschrieben): - Per-User-Add/Remove, aggregierte Counts, on_my_wishlist, Cascades bei Recipe/Profile-Delete, countWishlistRecipes = DISTINCT.
2026-04-17 19:16:19 +02:00
END AS on_my_wishlist,
(SELECT AVG(stars) FROM rating WHERE recipe_id = w.recipe_id) AS avg_stars
FROM wishlist w
JOIN recipe r ON r.id = w.recipe_id
feat(wishlist): per-user Wünsche + Header-Badge mit Gesamtzahl Schema-Änderung (Migration 005): - Tabelle wishlist umgestellt auf PK (recipe_id, profile_id) - wishlist_like-Tabelle zusammengelegt — Liken WAR schon "will ich auch", also werden alle bestehenden Likes Memberships auf der neuen Tabelle. - Alt-Einträge mit added_by_profile_id werden migriert, anonyme gehen verloren (war inkonsistent, jetzt erzwingen wir profile_id NOT NULL). Repository: - listWishlist aggregiert pro Rezept: wanted_by_count, wanted_by_names (kommagetrennt), on_my_wishlist für das aktive Profil - listWishlistProfileIds(recipeId) für den Recipe-Page-Loader - countWishlistRecipes für das Header-Badge (DISTINCT recipe_id) - addToWishlist/removeFromWishlist/isOnMyWishlist alle mit profile_id als Pflicht API: - POST /api/wishlist: profile_id jetzt Pflicht (nullable raus) - DELETE /api/wishlist/[recipe_id]?profile_id=X (nur eigenes Entry) - /api/wishlist/[recipe_id]/like komplett entfernt (Konzept obsolet) - Neu: GET /api/wishlist/count → { count: <distinct recipes> } UI: - Header-Heart bekommt rotes Badge mit Zahl der Wunschliste-Rezepte. wishlistStore in $lib/client/wishlist.svelte.ts hält den Count reaktiv; Refresh auf Mount, nach Add/Remove, beim Öffnen der Wunschliste. - Recipe-Detail: Loader liefert wishlist_profile_ids; onMyWishlist ist ein $derived. Toggle fragt aktives Profil (alertAction sonst), mutiert die lokale Liste + ruft wishlistStore.refresh. - Wunschliste-Seite: Heart toggelt eigenen Wunsch, Count zeigt Gesamt- wünsche, kommagetrennte Namen zeigen "wer will". Trash-Button entfernt — Heart-off reicht jetzt. Tests (99 → 99, 8 neu geschrieben): - Per-User-Add/Remove, aggregierte Counts, on_my_wishlist, Cascades bei Recipe/Profile-Delete, countWishlistRecipes = DISTINCT.
2026-04-17 19:16:19 +02:00
LEFT JOIN profile p ON p.id = w.profile_id
GROUP BY w.recipe_id
ORDER BY ${orderBy}`
)
.all(activeProfileId, activeProfileId) as WishlistEntry[];
}
feat(wishlist): per-user Wünsche + Header-Badge mit Gesamtzahl Schema-Änderung (Migration 005): - Tabelle wishlist umgestellt auf PK (recipe_id, profile_id) - wishlist_like-Tabelle zusammengelegt — Liken WAR schon "will ich auch", also werden alle bestehenden Likes Memberships auf der neuen Tabelle. - Alt-Einträge mit added_by_profile_id werden migriert, anonyme gehen verloren (war inkonsistent, jetzt erzwingen wir profile_id NOT NULL). Repository: - listWishlist aggregiert pro Rezept: wanted_by_count, wanted_by_names (kommagetrennt), on_my_wishlist für das aktive Profil - listWishlistProfileIds(recipeId) für den Recipe-Page-Loader - countWishlistRecipes für das Header-Badge (DISTINCT recipe_id) - addToWishlist/removeFromWishlist/isOnMyWishlist alle mit profile_id als Pflicht API: - POST /api/wishlist: profile_id jetzt Pflicht (nullable raus) - DELETE /api/wishlist/[recipe_id]?profile_id=X (nur eigenes Entry) - /api/wishlist/[recipe_id]/like komplett entfernt (Konzept obsolet) - Neu: GET /api/wishlist/count → { count: <distinct recipes> } UI: - Header-Heart bekommt rotes Badge mit Zahl der Wunschliste-Rezepte. wishlistStore in $lib/client/wishlist.svelte.ts hält den Count reaktiv; Refresh auf Mount, nach Add/Remove, beim Öffnen der Wunschliste. - Recipe-Detail: Loader liefert wishlist_profile_ids; onMyWishlist ist ein $derived. Toggle fragt aktives Profil (alertAction sonst), mutiert die lokale Liste + ruft wishlistStore.refresh. - Wunschliste-Seite: Heart toggelt eigenen Wunsch, Count zeigt Gesamt- wünsche, kommagetrennte Namen zeigen "wer will". Trash-Button entfernt — Heart-off reicht jetzt. Tests (99 → 99, 8 neu geschrieben): - Per-User-Add/Remove, aggregierte Counts, on_my_wishlist, Cascades bei Recipe/Profile-Delete, countWishlistRecipes = DISTINCT.
2026-04-17 19:16:19 +02:00
export function listWishlistProfileIds(
db: Database.Database,
recipeId: number
): number[] {
return (
db
feat(wishlist): per-user Wünsche + Header-Badge mit Gesamtzahl Schema-Änderung (Migration 005): - Tabelle wishlist umgestellt auf PK (recipe_id, profile_id) - wishlist_like-Tabelle zusammengelegt — Liken WAR schon "will ich auch", also werden alle bestehenden Likes Memberships auf der neuen Tabelle. - Alt-Einträge mit added_by_profile_id werden migriert, anonyme gehen verloren (war inkonsistent, jetzt erzwingen wir profile_id NOT NULL). Repository: - listWishlist aggregiert pro Rezept: wanted_by_count, wanted_by_names (kommagetrennt), on_my_wishlist für das aktive Profil - listWishlistProfileIds(recipeId) für den Recipe-Page-Loader - countWishlistRecipes für das Header-Badge (DISTINCT recipe_id) - addToWishlist/removeFromWishlist/isOnMyWishlist alle mit profile_id als Pflicht API: - POST /api/wishlist: profile_id jetzt Pflicht (nullable raus) - DELETE /api/wishlist/[recipe_id]?profile_id=X (nur eigenes Entry) - /api/wishlist/[recipe_id]/like komplett entfernt (Konzept obsolet) - Neu: GET /api/wishlist/count → { count: <distinct recipes> } UI: - Header-Heart bekommt rotes Badge mit Zahl der Wunschliste-Rezepte. wishlistStore in $lib/client/wishlist.svelte.ts hält den Count reaktiv; Refresh auf Mount, nach Add/Remove, beim Öffnen der Wunschliste. - Recipe-Detail: Loader liefert wishlist_profile_ids; onMyWishlist ist ein $derived. Toggle fragt aktives Profil (alertAction sonst), mutiert die lokale Liste + ruft wishlistStore.refresh. - Wunschliste-Seite: Heart toggelt eigenen Wunsch, Count zeigt Gesamt- wünsche, kommagetrennte Namen zeigen "wer will". Trash-Button entfernt — Heart-off reicht jetzt. Tests (99 → 99, 8 neu geschrieben): - Per-User-Add/Remove, aggregierte Counts, on_my_wishlist, Cascades bei Recipe/Profile-Delete, countWishlistRecipes = DISTINCT.
2026-04-17 19:16:19 +02:00
.prepare('SELECT profile_id FROM wishlist WHERE recipe_id = ?')
.all(recipeId) as { profile_id: number }[]
).map((r) => r.profile_id);
}
export function countWishlistRecipes(db: Database.Database): number {
const row = db
.prepare('SELECT COUNT(DISTINCT recipe_id) AS n FROM wishlist')
.get() as { n: number };
return row.n;
}
export function addToWishlist(
db: Database.Database,
recipeId: number,
feat(wishlist): per-user Wünsche + Header-Badge mit Gesamtzahl Schema-Änderung (Migration 005): - Tabelle wishlist umgestellt auf PK (recipe_id, profile_id) - wishlist_like-Tabelle zusammengelegt — Liken WAR schon "will ich auch", also werden alle bestehenden Likes Memberships auf der neuen Tabelle. - Alt-Einträge mit added_by_profile_id werden migriert, anonyme gehen verloren (war inkonsistent, jetzt erzwingen wir profile_id NOT NULL). Repository: - listWishlist aggregiert pro Rezept: wanted_by_count, wanted_by_names (kommagetrennt), on_my_wishlist für das aktive Profil - listWishlistProfileIds(recipeId) für den Recipe-Page-Loader - countWishlistRecipes für das Header-Badge (DISTINCT recipe_id) - addToWishlist/removeFromWishlist/isOnMyWishlist alle mit profile_id als Pflicht API: - POST /api/wishlist: profile_id jetzt Pflicht (nullable raus) - DELETE /api/wishlist/[recipe_id]?profile_id=X (nur eigenes Entry) - /api/wishlist/[recipe_id]/like komplett entfernt (Konzept obsolet) - Neu: GET /api/wishlist/count → { count: <distinct recipes> } UI: - Header-Heart bekommt rotes Badge mit Zahl der Wunschliste-Rezepte. wishlistStore in $lib/client/wishlist.svelte.ts hält den Count reaktiv; Refresh auf Mount, nach Add/Remove, beim Öffnen der Wunschliste. - Recipe-Detail: Loader liefert wishlist_profile_ids; onMyWishlist ist ein $derived. Toggle fragt aktives Profil (alertAction sonst), mutiert die lokale Liste + ruft wishlistStore.refresh. - Wunschliste-Seite: Heart toggelt eigenen Wunsch, Count zeigt Gesamt- wünsche, kommagetrennte Namen zeigen "wer will". Trash-Button entfernt — Heart-off reicht jetzt. Tests (99 → 99, 8 neu geschrieben): - Per-User-Add/Remove, aggregierte Counts, on_my_wishlist, Cascades bei Recipe/Profile-Delete, countWishlistRecipes = DISTINCT.
2026-04-17 19:16:19 +02:00
profileId: number
): void {
db.prepare(
feat(wishlist): per-user Wünsche + Header-Badge mit Gesamtzahl Schema-Änderung (Migration 005): - Tabelle wishlist umgestellt auf PK (recipe_id, profile_id) - wishlist_like-Tabelle zusammengelegt — Liken WAR schon "will ich auch", also werden alle bestehenden Likes Memberships auf der neuen Tabelle. - Alt-Einträge mit added_by_profile_id werden migriert, anonyme gehen verloren (war inkonsistent, jetzt erzwingen wir profile_id NOT NULL). Repository: - listWishlist aggregiert pro Rezept: wanted_by_count, wanted_by_names (kommagetrennt), on_my_wishlist für das aktive Profil - listWishlistProfileIds(recipeId) für den Recipe-Page-Loader - countWishlistRecipes für das Header-Badge (DISTINCT recipe_id) - addToWishlist/removeFromWishlist/isOnMyWishlist alle mit profile_id als Pflicht API: - POST /api/wishlist: profile_id jetzt Pflicht (nullable raus) - DELETE /api/wishlist/[recipe_id]?profile_id=X (nur eigenes Entry) - /api/wishlist/[recipe_id]/like komplett entfernt (Konzept obsolet) - Neu: GET /api/wishlist/count → { count: <distinct recipes> } UI: - Header-Heart bekommt rotes Badge mit Zahl der Wunschliste-Rezepte. wishlistStore in $lib/client/wishlist.svelte.ts hält den Count reaktiv; Refresh auf Mount, nach Add/Remove, beim Öffnen der Wunschliste. - Recipe-Detail: Loader liefert wishlist_profile_ids; onMyWishlist ist ein $derived. Toggle fragt aktives Profil (alertAction sonst), mutiert die lokale Liste + ruft wishlistStore.refresh. - Wunschliste-Seite: Heart toggelt eigenen Wunsch, Count zeigt Gesamt- wünsche, kommagetrennte Namen zeigen "wer will". Trash-Button entfernt — Heart-off reicht jetzt. Tests (99 → 99, 8 neu geschrieben): - Per-User-Add/Remove, aggregierte Counts, on_my_wishlist, Cascades bei Recipe/Profile-Delete, countWishlistRecipes = DISTINCT.
2026-04-17 19:16:19 +02:00
`INSERT INTO wishlist(recipe_id, profile_id)
VALUES (?, ?)
feat(wishlist): per-user Wünsche + Header-Badge mit Gesamtzahl Schema-Änderung (Migration 005): - Tabelle wishlist umgestellt auf PK (recipe_id, profile_id) - wishlist_like-Tabelle zusammengelegt — Liken WAR schon "will ich auch", also werden alle bestehenden Likes Memberships auf der neuen Tabelle. - Alt-Einträge mit added_by_profile_id werden migriert, anonyme gehen verloren (war inkonsistent, jetzt erzwingen wir profile_id NOT NULL). Repository: - listWishlist aggregiert pro Rezept: wanted_by_count, wanted_by_names (kommagetrennt), on_my_wishlist für das aktive Profil - listWishlistProfileIds(recipeId) für den Recipe-Page-Loader - countWishlistRecipes für das Header-Badge (DISTINCT recipe_id) - addToWishlist/removeFromWishlist/isOnMyWishlist alle mit profile_id als Pflicht API: - POST /api/wishlist: profile_id jetzt Pflicht (nullable raus) - DELETE /api/wishlist/[recipe_id]?profile_id=X (nur eigenes Entry) - /api/wishlist/[recipe_id]/like komplett entfernt (Konzept obsolet) - Neu: GET /api/wishlist/count → { count: <distinct recipes> } UI: - Header-Heart bekommt rotes Badge mit Zahl der Wunschliste-Rezepte. wishlistStore in $lib/client/wishlist.svelte.ts hält den Count reaktiv; Refresh auf Mount, nach Add/Remove, beim Öffnen der Wunschliste. - Recipe-Detail: Loader liefert wishlist_profile_ids; onMyWishlist ist ein $derived. Toggle fragt aktives Profil (alertAction sonst), mutiert die lokale Liste + ruft wishlistStore.refresh. - Wunschliste-Seite: Heart toggelt eigenen Wunsch, Count zeigt Gesamt- wünsche, kommagetrennte Namen zeigen "wer will". Trash-Button entfernt — Heart-off reicht jetzt. Tests (99 → 99, 8 neu geschrieben): - Per-User-Add/Remove, aggregierte Counts, on_my_wishlist, Cascades bei Recipe/Profile-Delete, countWishlistRecipes = DISTINCT.
2026-04-17 19:16:19 +02:00
ON CONFLICT(recipe_id, profile_id) DO NOTHING`
).run(recipeId, profileId);
}
feat(wishlist): per-user Wünsche + Header-Badge mit Gesamtzahl Schema-Änderung (Migration 005): - Tabelle wishlist umgestellt auf PK (recipe_id, profile_id) - wishlist_like-Tabelle zusammengelegt — Liken WAR schon "will ich auch", also werden alle bestehenden Likes Memberships auf der neuen Tabelle. - Alt-Einträge mit added_by_profile_id werden migriert, anonyme gehen verloren (war inkonsistent, jetzt erzwingen wir profile_id NOT NULL). Repository: - listWishlist aggregiert pro Rezept: wanted_by_count, wanted_by_names (kommagetrennt), on_my_wishlist für das aktive Profil - listWishlistProfileIds(recipeId) für den Recipe-Page-Loader - countWishlistRecipes für das Header-Badge (DISTINCT recipe_id) - addToWishlist/removeFromWishlist/isOnMyWishlist alle mit profile_id als Pflicht API: - POST /api/wishlist: profile_id jetzt Pflicht (nullable raus) - DELETE /api/wishlist/[recipe_id]?profile_id=X (nur eigenes Entry) - /api/wishlist/[recipe_id]/like komplett entfernt (Konzept obsolet) - Neu: GET /api/wishlist/count → { count: <distinct recipes> } UI: - Header-Heart bekommt rotes Badge mit Zahl der Wunschliste-Rezepte. wishlistStore in $lib/client/wishlist.svelte.ts hält den Count reaktiv; Refresh auf Mount, nach Add/Remove, beim Öffnen der Wunschliste. - Recipe-Detail: Loader liefert wishlist_profile_ids; onMyWishlist ist ein $derived. Toggle fragt aktives Profil (alertAction sonst), mutiert die lokale Liste + ruft wishlistStore.refresh. - Wunschliste-Seite: Heart toggelt eigenen Wunsch, Count zeigt Gesamt- wünsche, kommagetrennte Namen zeigen "wer will". Trash-Button entfernt — Heart-off reicht jetzt. Tests (99 → 99, 8 neu geschrieben): - Per-User-Add/Remove, aggregierte Counts, on_my_wishlist, Cascades bei Recipe/Profile-Delete, countWishlistRecipes = DISTINCT.
2026-04-17 19:16:19 +02:00
export function removeFromWishlist(
db: Database.Database,
recipeId: number,
profileId: number
): void {
feat(wishlist): per-user Wünsche + Header-Badge mit Gesamtzahl Schema-Änderung (Migration 005): - Tabelle wishlist umgestellt auf PK (recipe_id, profile_id) - wishlist_like-Tabelle zusammengelegt — Liken WAR schon "will ich auch", also werden alle bestehenden Likes Memberships auf der neuen Tabelle. - Alt-Einträge mit added_by_profile_id werden migriert, anonyme gehen verloren (war inkonsistent, jetzt erzwingen wir profile_id NOT NULL). Repository: - listWishlist aggregiert pro Rezept: wanted_by_count, wanted_by_names (kommagetrennt), on_my_wishlist für das aktive Profil - listWishlistProfileIds(recipeId) für den Recipe-Page-Loader - countWishlistRecipes für das Header-Badge (DISTINCT recipe_id) - addToWishlist/removeFromWishlist/isOnMyWishlist alle mit profile_id als Pflicht API: - POST /api/wishlist: profile_id jetzt Pflicht (nullable raus) - DELETE /api/wishlist/[recipe_id]?profile_id=X (nur eigenes Entry) - /api/wishlist/[recipe_id]/like komplett entfernt (Konzept obsolet) - Neu: GET /api/wishlist/count → { count: <distinct recipes> } UI: - Header-Heart bekommt rotes Badge mit Zahl der Wunschliste-Rezepte. wishlistStore in $lib/client/wishlist.svelte.ts hält den Count reaktiv; Refresh auf Mount, nach Add/Remove, beim Öffnen der Wunschliste. - Recipe-Detail: Loader liefert wishlist_profile_ids; onMyWishlist ist ein $derived. Toggle fragt aktives Profil (alertAction sonst), mutiert die lokale Liste + ruft wishlistStore.refresh. - Wunschliste-Seite: Heart toggelt eigenen Wunsch, Count zeigt Gesamt- wünsche, kommagetrennte Namen zeigen "wer will". Trash-Button entfernt — Heart-off reicht jetzt. Tests (99 → 99, 8 neu geschrieben): - Per-User-Add/Remove, aggregierte Counts, on_my_wishlist, Cascades bei Recipe/Profile-Delete, countWishlistRecipes = DISTINCT.
2026-04-17 19:16:19 +02:00
db.prepare('DELETE FROM wishlist WHERE recipe_id = ? AND profile_id = ?').run(
recipeId,
profileId
);
}
feat(wishlist): per-user Wünsche + Header-Badge mit Gesamtzahl Schema-Änderung (Migration 005): - Tabelle wishlist umgestellt auf PK (recipe_id, profile_id) - wishlist_like-Tabelle zusammengelegt — Liken WAR schon "will ich auch", also werden alle bestehenden Likes Memberships auf der neuen Tabelle. - Alt-Einträge mit added_by_profile_id werden migriert, anonyme gehen verloren (war inkonsistent, jetzt erzwingen wir profile_id NOT NULL). Repository: - listWishlist aggregiert pro Rezept: wanted_by_count, wanted_by_names (kommagetrennt), on_my_wishlist für das aktive Profil - listWishlistProfileIds(recipeId) für den Recipe-Page-Loader - countWishlistRecipes für das Header-Badge (DISTINCT recipe_id) - addToWishlist/removeFromWishlist/isOnMyWishlist alle mit profile_id als Pflicht API: - POST /api/wishlist: profile_id jetzt Pflicht (nullable raus) - DELETE /api/wishlist/[recipe_id]?profile_id=X (nur eigenes Entry) - /api/wishlist/[recipe_id]/like komplett entfernt (Konzept obsolet) - Neu: GET /api/wishlist/count → { count: <distinct recipes> } UI: - Header-Heart bekommt rotes Badge mit Zahl der Wunschliste-Rezepte. wishlistStore in $lib/client/wishlist.svelte.ts hält den Count reaktiv; Refresh auf Mount, nach Add/Remove, beim Öffnen der Wunschliste. - Recipe-Detail: Loader liefert wishlist_profile_ids; onMyWishlist ist ein $derived. Toggle fragt aktives Profil (alertAction sonst), mutiert die lokale Liste + ruft wishlistStore.refresh. - Wunschliste-Seite: Heart toggelt eigenen Wunsch, Count zeigt Gesamt- wünsche, kommagetrennte Namen zeigen "wer will". Trash-Button entfernt — Heart-off reicht jetzt. Tests (99 → 99, 8 neu geschrieben): - Per-User-Add/Remove, aggregierte Counts, on_my_wishlist, Cascades bei Recipe/Profile-Delete, countWishlistRecipes = DISTINCT.
2026-04-17 19:16:19 +02:00
export function isOnMyWishlist(
db: Database.Database,
recipeId: number,
profileId: number
feat(wishlist): per-user Wünsche + Header-Badge mit Gesamtzahl Schema-Änderung (Migration 005): - Tabelle wishlist umgestellt auf PK (recipe_id, profile_id) - wishlist_like-Tabelle zusammengelegt — Liken WAR schon "will ich auch", also werden alle bestehenden Likes Memberships auf der neuen Tabelle. - Alt-Einträge mit added_by_profile_id werden migriert, anonyme gehen verloren (war inkonsistent, jetzt erzwingen wir profile_id NOT NULL). Repository: - listWishlist aggregiert pro Rezept: wanted_by_count, wanted_by_names (kommagetrennt), on_my_wishlist für das aktive Profil - listWishlistProfileIds(recipeId) für den Recipe-Page-Loader - countWishlistRecipes für das Header-Badge (DISTINCT recipe_id) - addToWishlist/removeFromWishlist/isOnMyWishlist alle mit profile_id als Pflicht API: - POST /api/wishlist: profile_id jetzt Pflicht (nullable raus) - DELETE /api/wishlist/[recipe_id]?profile_id=X (nur eigenes Entry) - /api/wishlist/[recipe_id]/like komplett entfernt (Konzept obsolet) - Neu: GET /api/wishlist/count → { count: <distinct recipes> } UI: - Header-Heart bekommt rotes Badge mit Zahl der Wunschliste-Rezepte. wishlistStore in $lib/client/wishlist.svelte.ts hält den Count reaktiv; Refresh auf Mount, nach Add/Remove, beim Öffnen der Wunschliste. - Recipe-Detail: Loader liefert wishlist_profile_ids; onMyWishlist ist ein $derived. Toggle fragt aktives Profil (alertAction sonst), mutiert die lokale Liste + ruft wishlistStore.refresh. - Wunschliste-Seite: Heart toggelt eigenen Wunsch, Count zeigt Gesamt- wünsche, kommagetrennte Namen zeigen "wer will". Trash-Button entfernt — Heart-off reicht jetzt. Tests (99 → 99, 8 neu geschrieben): - Per-User-Add/Remove, aggregierte Counts, on_my_wishlist, Cascades bei Recipe/Profile-Delete, countWishlistRecipes = DISTINCT.
2026-04-17 19:16:19 +02:00
): boolean {
return (
db
.prepare('SELECT 1 AS ok FROM wishlist WHERE recipe_id = ? AND profile_id = ?')
.get(recipeId, profileId) !== undefined
);
}