From 072f3b230e917e9bd5c036d510f258821c5df1d9 Mon Sep 17 00:00:00 2001 From: Lea Tveteraas Date: Tue, 6 Oct 2026 13:57:12 +0200 Subject: [PATCH] Laget databaseskjema --- backend/db/migrations/001_create_tables.sql | 103 +++++++++++++++++++ backend/db/migrations/002_create_indexes.sql | 31 ++++++ 2 files changed, 134 insertions(+) create mode 100644 backend/db/migrations/001_create_tables.sql create mode 100644 backend/db/migrations/002_create_indexes.sql diff --git a/backend/db/migrations/001_create_tables.sql b/backend/db/migrations/001_create_tables.sql new file mode 100644 index 0000000..eb8a0d0 --- /dev/null +++ b/backend/db/migrations/001_create_tables.sql @@ -0,0 +1,103 @@ +-- 001_create_tables.sql +-- Wine not? – tabeller og typer for PostgreSQL +-- Kjør med: psql -d winenot -v ON_ERROR_STOP=1 -f backend/db/migrations/001_create_tables.sql +-- En migrasjon som er merget, endres ikke. Nye endringer legges i en ny, nummerert fil. + +BEGIN; + +-- ---------- Typer ---------- +-- Verdiene er de samme som i X-Wines, og rekkefølgen her bestemmer sorteringen. + +CREATE TYPE body_level AS ENUM ( + 'Very light-bodied', + 'Light-bodied', + 'Medium-bodied', + 'Full-bodied', + 'Very full-bodied' +); + +CREATE TYPE acidity_level AS ENUM ( + 'Low', + 'Medium', + 'High' +); + +-- ---------- Oppslagstabeller ---------- + +CREATE TABLE countries ( + code text PRIMARY KEY, -- Code fra X-Wines, f.eks. 'FR' + name text NOT NULL UNIQUE +); + +CREATE TABLE regions ( + id integer PRIMARY KEY, -- RegionID fra X-Wines + name text NOT NULL, + country_code text NOT NULL REFERENCES countries(code) +); + +CREATE TABLE wineries ( + id integer PRIMARY KEY, -- WineryID fra X-Wines + name text NOT NULL, + website text +); + +CREATE TABLE grapes ( + id integer GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + name text NOT NULL UNIQUE +); + +CREATE TABLE foods ( + id integer GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + name text NOT NULL UNIQUE -- verdier fra Harmonize, f.eks. 'Beef', 'Rich Fish' +); + +-- ---------- Viner ---------- + +CREATE TABLE wines ( + id integer PRIMARY KEY, -- WineID fra X-Wines + name text NOT NULL, + type text NOT NULL, -- Red, White, Rosé, Sparkling, Dessert, Dessert/Port + elaborate text, -- f.eks. 'Varietal/100%', 'Assemblage/Blend' + abv numeric(4,1), -- alkoholprosent + body body_level, + acidity acidity_level, + winery_id integer NOT NULL REFERENCES wineries(id), + region_id integer NOT NULL REFERENCES regions(id), + country_code text NOT NULL REFERENCES countries(code), -- bevisst duplisert fra regions: sparer en join ved landfilter + vintages integer[] NOT NULL DEFAULT '{}', -- 'N.V.' hoppes over i importskriptet + avg_rating numeric(3,2), -- forhåndsberegnet i importskriptet + rating_count integer NOT NULL DEFAULT 0 +); + +-- ---------- Mange-til-mange ---------- + +CREATE TABLE wine_grapes ( + wine_id integer NOT NULL REFERENCES wines(id) ON DELETE CASCADE, + grape_id integer NOT NULL REFERENCES grapes(id) ON DELETE CASCADE, + PRIMARY KEY (wine_id, grape_id) +); + +CREATE TABLE wine_foods ( + wine_id integer NOT NULL REFERENCES wines(id) ON DELETE CASCADE, + food_id integer NOT NULL REFERENCES foods(id) ON DELETE CASCADE, + PRIMARY KEY (wine_id, food_id) +); + +-- ---------- Brukere og favoritter (brukergenerert data) ---------- + +CREATE TABLE users ( + id integer GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + username text NOT NULL UNIQUE, + email text NOT NULL UNIQUE, + password_hash text NOT NULL, -- aldri klartekst; hashes med bcrypt/argon2 i backend + created_at timestamptz NOT NULL DEFAULT now() +); + +CREATE TABLE favorites ( + user_id integer NOT NULL REFERENCES users(id) ON DELETE CASCADE, + wine_id integer NOT NULL REFERENCES wines(id) ON DELETE CASCADE, + created_at timestamptz NOT NULL DEFAULT now(), + PRIMARY KEY (user_id, wine_id) -- hindrer duplikater og dekker "mine favoritter" +); + +COMMIT; diff --git a/backend/db/migrations/002_create_indexes.sql b/backend/db/migrations/002_create_indexes.sql new file mode 100644 index 0000000..e9bca08 --- /dev/null +++ b/backend/db/migrations/002_create_indexes.sql @@ -0,0 +1,31 @@ +-- 002_create_indexes.sql +-- Wine not? – indekser for søk, filtrering og sortering +-- Kjør med: psql -d winenot -v ON_ERROR_STOP=1 -f backend/db/migrations/002_create_indexes.sql + +BEGIN; + +CREATE EXTENSION IF NOT EXISTS pg_trgm; -- raskt delstreng-søk på vinnavn + +-- Søk: WHERE name ILIKE '%tekst%' +CREATE INDEX wines_name_trgm_idx ON wines USING gin (name gin_trgm_ops); + +-- Filtre +CREATE INDEX wines_type_idx ON wines (type); +CREATE INDEX wines_country_idx ON wines (country_code); +CREATE INDEX wines_region_idx ON wines (region_id); +CREATE INDEX wines_winery_idx ON wines (winery_id); +CREATE INDEX wines_taste_idx ON wines (body, acidity); -- Explore by taste +CREATE INDEX wines_vintages_idx ON wines USING gin (vintages); -- WHERE vintages @> ARRAY[2018] + +-- Sortering (id som siste ledd gir stabil rekkefølge ved paginering) +CREATE INDEX wines_name_sort_idx ON wines (name, id); +CREATE INDEX wines_rating_idx ON wines (avg_rating DESC NULLS LAST, id); +CREATE INDEX wines_abv_idx ON wines (abv, id); + +-- Primærnøklene dekker oppslag fra vin/bruker. Disse dekker motsatt vei. +CREATE INDEX wine_grapes_grape_idx ON wine_grapes (grape_id); +CREATE INDEX wine_foods_food_idx ON wine_foods (food_id); +CREATE INDEX favorites_wine_idx ON favorites (wine_id); +CREATE INDEX regions_country_idx ON regions (country_code); + +COMMIT;