feat(db): add SQLite schema, FTS5, migration runner
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
140
src/lib/server/db/migrations/001_init.sql
Normal file
140
src/lib/server/db/migrations/001_init.sql
Normal file
@@ -0,0 +1,140 @@
|
||||
PRAGMA foreign_keys = ON;
|
||||
PRAGMA journal_mode = WAL;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS profile (
|
||||
id INTEGER PRIMARY KEY,
|
||||
name TEXT UNIQUE NOT NULL,
|
||||
avatar_emoji TEXT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS recipe (
|
||||
id INTEGER PRIMARY KEY,
|
||||
title TEXT NOT NULL,
|
||||
description TEXT,
|
||||
source_url TEXT UNIQUE,
|
||||
source_domain TEXT,
|
||||
image_path TEXT,
|
||||
servings_default INTEGER,
|
||||
servings_unit TEXT,
|
||||
prep_time_min INTEGER,
|
||||
cook_time_min INTEGER,
|
||||
total_time_min INTEGER,
|
||||
cuisine TEXT,
|
||||
category TEXT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ingredient (
|
||||
id INTEGER PRIMARY KEY,
|
||||
recipe_id INTEGER NOT NULL REFERENCES recipe(id) ON DELETE CASCADE,
|
||||
position INTEGER NOT NULL,
|
||||
quantity REAL,
|
||||
unit TEXT,
|
||||
name TEXT NOT NULL,
|
||||
note TEXT,
|
||||
raw_text TEXT
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS ix_ingredient_recipe ON ingredient(recipe_id, position);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS step (
|
||||
id INTEGER PRIMARY KEY,
|
||||
recipe_id INTEGER NOT NULL REFERENCES recipe(id) ON DELETE CASCADE,
|
||||
position INTEGER NOT NULL,
|
||||
text TEXT NOT NULL
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS ix_step_recipe ON step(recipe_id, position);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS tag (
|
||||
id INTEGER PRIMARY KEY,
|
||||
name TEXT UNIQUE NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS recipe_tag (
|
||||
recipe_id INTEGER NOT NULL REFERENCES recipe(id) ON DELETE CASCADE,
|
||||
tag_id INTEGER NOT NULL REFERENCES tag(id) ON DELETE CASCADE,
|
||||
PRIMARY KEY (recipe_id, tag_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS rating (
|
||||
recipe_id INTEGER NOT NULL REFERENCES recipe(id) ON DELETE CASCADE,
|
||||
profile_id INTEGER NOT NULL REFERENCES profile(id) ON DELETE CASCADE,
|
||||
stars INTEGER NOT NULL CHECK (stars BETWEEN 1 AND 5),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (recipe_id, profile_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS comment (
|
||||
id INTEGER PRIMARY KEY,
|
||||
recipe_id INTEGER NOT NULL REFERENCES recipe(id) ON DELETE CASCADE,
|
||||
profile_id INTEGER NOT NULL REFERENCES profile(id) ON DELETE CASCADE,
|
||||
text TEXT NOT NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS favorite (
|
||||
recipe_id INTEGER NOT NULL REFERENCES recipe(id) ON DELETE CASCADE,
|
||||
profile_id INTEGER NOT NULL REFERENCES profile(id) ON DELETE CASCADE,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (recipe_id, profile_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS cooking_log (
|
||||
id INTEGER PRIMARY KEY,
|
||||
recipe_id INTEGER NOT NULL REFERENCES recipe(id) ON DELETE CASCADE,
|
||||
profile_id INTEGER NOT NULL REFERENCES profile(id) ON DELETE CASCADE,
|
||||
cooked_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS ix_cooking_log_recipe ON cooking_log(recipe_id, cooked_at);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS allowed_domain (
|
||||
id INTEGER PRIMARY KEY,
|
||||
domain TEXT UNIQUE NOT NULL,
|
||||
display_name TEXT,
|
||||
added_by_profile_id INTEGER REFERENCES profile(id),
|
||||
added_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE VIRTUAL TABLE IF NOT EXISTS recipe_fts USING fts5(
|
||||
title, description, ingredients_concat, tags_concat,
|
||||
content='', tokenize='unicode61 remove_diacritics 2'
|
||||
);
|
||||
|
||||
CREATE TRIGGER IF NOT EXISTS trg_recipe_ai AFTER INSERT ON recipe BEGIN
|
||||
INSERT INTO recipe_fts(rowid, title, description, ingredients_concat, tags_concat)
|
||||
VALUES (NEW.id, NEW.title, COALESCE(NEW.description, ''), '', '');
|
||||
END;
|
||||
|
||||
CREATE TRIGGER IF NOT EXISTS trg_recipe_ad AFTER DELETE ON recipe BEGIN
|
||||
INSERT INTO recipe_fts(recipe_fts, rowid, title, description, ingredients_concat, tags_concat)
|
||||
VALUES ('delete', OLD.id, OLD.title, COALESCE(OLD.description, ''), '', '');
|
||||
END;
|
||||
|
||||
CREATE TRIGGER IF NOT EXISTS trg_recipe_au AFTER UPDATE ON recipe BEGIN
|
||||
INSERT INTO recipe_fts(recipe_fts, rowid, title, description, ingredients_concat, tags_concat)
|
||||
VALUES ('delete', OLD.id, OLD.title, COALESCE(OLD.description, ''), '', '');
|
||||
INSERT INTO recipe_fts(rowid, title, description, ingredients_concat, tags_concat)
|
||||
VALUES (NEW.id, NEW.title, COALESCE(NEW.description, ''),
|
||||
COALESCE((SELECT group_concat(name, ' ') FROM ingredient WHERE recipe_id = NEW.id), ''),
|
||||
COALESCE((SELECT group_concat(t.name, ' ') FROM tag t JOIN recipe_tag rt ON rt.tag_id = t.id WHERE rt.recipe_id = NEW.id), '')
|
||||
);
|
||||
END;
|
||||
|
||||
CREATE TRIGGER IF NOT EXISTS trg_ingredient_ai AFTER INSERT ON ingredient BEGIN
|
||||
UPDATE recipe SET updated_at = CURRENT_TIMESTAMP WHERE id = NEW.recipe_id;
|
||||
END;
|
||||
CREATE TRIGGER IF NOT EXISTS trg_ingredient_ad AFTER DELETE ON ingredient BEGIN
|
||||
UPDATE recipe SET updated_at = CURRENT_TIMESTAMP WHERE id = OLD.recipe_id;
|
||||
END;
|
||||
CREATE TRIGGER IF NOT EXISTS trg_recipe_tag_ai AFTER INSERT ON recipe_tag BEGIN
|
||||
UPDATE recipe SET updated_at = CURRENT_TIMESTAMP WHERE id = NEW.recipe_id;
|
||||
END;
|
||||
CREATE TRIGGER IF NOT EXISTS trg_recipe_tag_ad AFTER DELETE ON recipe_tag BEGIN
|
||||
UPDATE recipe SET updated_at = CURRENT_TIMESTAMP WHERE id = OLD.recipe_id;
|
||||
END;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS schema_migration (
|
||||
name TEXT PRIMARY KEY,
|
||||
applied_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
Reference in New Issue
Block a user