refactor(db): recipe_views -> recipe_view, TIMESTAMP-Konsistenz

Code-Review-Findings nachgezogen: Tabellen-Konvention im Repo ist
singular (profile, recipe, favorite, cooking_log, thumbnail_cache),
deshalb recipe_view statt recipe_views; Index analog umbenannt.
last_viewed_at auf TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
gewechselt — matcht den Rest des Schemas. Header-Kommentar +
notnull-Assertion fuer recipe_id ergaenzt.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-22 14:08:17 +02:00
parent 2cd9b47450
commit 543008b0f2
2 changed files with 12 additions and 9 deletions

View File

@@ -1,8 +1,10 @@
CREATE TABLE recipe_views ( -- Merkt je Profil, wann ein Rezept zuletzt angesehen wurde.
-- Dient als Basis fuer "Zuletzt gesehen"-Sortierung auf der Startseite.
CREATE TABLE recipe_view (
profile_id INTEGER NOT NULL REFERENCES profile(id) ON DELETE CASCADE, profile_id INTEGER NOT NULL REFERENCES profile(id) ON DELETE CASCADE,
recipe_id INTEGER NOT NULL REFERENCES recipe(id) ON DELETE CASCADE, recipe_id INTEGER NOT NULL REFERENCES recipe(id) ON DELETE CASCADE,
last_viewed_at TEXT NOT NULL DEFAULT (datetime('now')), last_viewed_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (profile_id, recipe_id) PRIMARY KEY (profile_id, recipe_id)
); );
CREATE INDEX idx_recipe_views_recent CREATE INDEX idx_recipe_view_recent
ON recipe_views (profile_id, last_viewed_at DESC); ON recipe_view (profile_id, last_viewed_at DESC);

View File

@@ -2,9 +2,9 @@ import { describe, it, expect } from 'vitest';
import { openInMemoryForTest } from '../../src/lib/server/db'; import { openInMemoryForTest } from '../../src/lib/server/db';
describe('014_recipe_views migration', () => { describe('014_recipe_views migration', () => {
it('creates recipe_views table with expected columns', () => { it('creates recipe_view table with expected columns', () => {
const db = openInMemoryForTest(); const db = openInMemoryForTest();
const cols = db.prepare("PRAGMA table_info(recipe_views)").all() as Array<{ const cols = db.prepare("PRAGMA table_info(recipe_view)").all() as Array<{
name: string; name: string;
type: string; type: string;
notnull: number; notnull: number;
@@ -15,16 +15,17 @@ describe('014_recipe_views migration', () => {
expect(byName.profile_id?.notnull).toBe(1); expect(byName.profile_id?.notnull).toBe(1);
expect(byName.profile_id?.pk).toBe(1); expect(byName.profile_id?.pk).toBe(1);
expect(byName.recipe_id?.type).toBe('INTEGER'); expect(byName.recipe_id?.type).toBe('INTEGER');
expect(byName.recipe_id?.notnull).toBe(1);
expect(byName.recipe_id?.pk).toBe(2); expect(byName.recipe_id?.pk).toBe(2);
expect(byName.last_viewed_at?.type).toBe('TEXT'); expect(byName.last_viewed_at?.type).toBe('TIMESTAMP');
expect(byName.last_viewed_at?.notnull).toBe(1); expect(byName.last_viewed_at?.notnull).toBe(1);
}); });
it('has index on (profile_id, last_viewed_at DESC)', () => { it('has index on (profile_id, last_viewed_at DESC)', () => {
const db = openInMemoryForTest(); const db = openInMemoryForTest();
const idxList = db const idxList = db
.prepare("PRAGMA index_list(recipe_views)") .prepare("PRAGMA index_list(recipe_view)")
.all() as Array<{ name: string }>; .all() as Array<{ name: string }>;
expect(idxList.some((i) => i.name === 'idx_recipe_views_recent')).toBe(true); expect(idxList.some((i) => i.name === 'idx_recipe_view_recent')).toBe(true);
}); });
}); });