diff --git a/src/lib/database_pgsql.sql b/src/lib/database_pgsql.sql new file mode 100644 index 0000000..1761f82 --- /dev/null +++ b/src/lib/database_pgsql.sql @@ -0,0 +1,150 @@ +-- PostgreSQL Schema Definition for Eurovision 25 Homereview Backend +-- Converted from DuckDB schema +-- Target Database: PostgreSQL +-- Note: Timestamps default to creation time; application logic should handle 'updated_at' updates. + +-- Drop objects in reverse order of dependency and existence check +DROP TABLE IF EXISTS Review; +DROP TABLE IF EXISTS Song; +DROP TABLE IF EXISTS "User"; -- Quoted because USER is a reserved keyword +DROP TABLE IF EXISTS Team; +DROP TABLE IF EXISTS CountryCodes; + +-- ============================================================================= +-- Table: Group +-- Stores information about the different households or groups participating. +-- ============================================================================= +CREATE TABLE "Team" ( + id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, -- Use IDENTITY for auto-increment + name VARCHAR(255) UNIQUE NOT NULL, -- The name of the household/group + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- Timestamp when the group was created + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -- Timestamp when the group was last updated +); + +-- ============================================================================= +-- Table: User +-- Stores information about individual users (players and admins). +-- ============================================================================= +CREATE TABLE "User" ( + id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, -- Use IDENTITY for auto-increment + username VARCHAR(255) UNIQUE NOT NULL, -- The user's login name + hashed_password VARCHAR(255) NOT NULL, -- The securely hashed password + email VARCHAR(255) UNIQUE, -- User's email address (nullable) + team_id INTEGER NOT NULL, -- Foreign Key -> Group.id + avatar_id INTEGER DEFAULT 0 NOT NULL, -- Identifier for the user's avatar + is_active BOOLEAN DEFAULT TRUE NOT NULL, -- Flag indicating if the user account is active + is_admin BOOLEAN DEFAULT FALSE NOT NULL, -- Flag indicating if the user has admin privileges + last_login TIMESTAMP DEFAULT '1970-01-01 00:00:00', -- Timestamp when the user was last logged in. Epoch (1970-01-01) means "never logged in" + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- Timestamp when the user was created + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- Timestamp when the user was last updated + + FOREIGN KEY (team_id) REFERENCES "Team"(id) -- Link to the Team table +); + +-- ============================================================================= +-- Table: Song +-- Stores information about each participating song in the contest. +-- ============================================================================= +CREATE TABLE Song ( + id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, -- Use IDENTITY for auto-increment + year INTEGER NOT NULL, -- The year of the Eurovision contest + country VARCHAR(255) NOT NULL, -- The participating country name + artist VARCHAR(255) NOT NULL, -- The name of the performing artist(s) + title VARCHAR(255) NOT NULL, -- The title of the song + running_order INTEGER NOT NULL, -- Official order in the show (nullable) + lyrics_url VARCHAR(255), -- URL to the original lyrics (nullable) + artist_url VARCHAR(255), -- URL to the artist's page (nullable) + flag_url VARCHAR(255), -- URL to the country flag (nullable) + lyrics_original TEXT, -- Original lyrics (nullable) + lyrics_translation_fi TEXT, -- Finnish translation (nullable) + tags TEXT[], -- Array of tags (PostgreSQL array type) + confidence FLOAT NOT NULL DEFAULT 0.0, -- Confidence level of the translation (nullable) + language VARCHAR(50) NOT NULL, -- Language of the song (nullable) + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- Timestamp when the song entry was created + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -- Timestamp when the song entry was last updated +); + +-- Add index for faster lookups by year as specified in documentation +CREATE INDEX idx_song_year ON Song (year); + +-- ============================================================================= +-- Table: Review +-- Stores the scores and comments submitted by a user for a specific song. +-- ============================================================================= +CREATE TABLE Review ( + id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, -- Use IDENTITY for auto-increment + user_id INTEGER NOT NULL, -- Foreign Key -> User.id + song_id INTEGER NOT NULL, -- Foreign Key -> Song.id + score_song INTEGER NOT NULL, -- Score (1-100) for song quality + score_show INTEGER NOT NULL, -- Score (1-100) for the stage show + score_costume INTEGER NOT NULL, -- Score (1-100) for wardrobe/costumes + text_review TEXT, -- Optional textual comments (nullable) + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- Timestamp when the review was created + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- Timestamp when the review was last modified + + FOREIGN KEY (user_id) REFERENCES "User"(id), -- Link to the User table + FOREIGN KEY (song_id) REFERENCES Song(id), -- Link to the Song table + + -- Ensure scores are within the valid range (1-100) + CHECK (score_song >= 1 AND score_song <= 100), + CHECK (score_show >= 1 AND score_show <= 100), + CHECK (score_costume >= 1 AND score_costume <= 100), + + -- Ensure each user can only submit one review per song + UNIQUE (user_id, song_id) +); + +CREATE TABLE CountryCodes ( + code VARCHAR(10) PRIMARY KEY, + name_en VARCHAR(255) NOT NULL, + name_fi VARCHAR(255) NOT NULL, + name_sv VARCHAR(255) NOT NULL +); + +-- Insert country codes data +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('ALB', 'Albania', 'Albania', 'Albanien'); +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('ARM', 'Armenia', 'Armenia', 'Armenien'); +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('AUS', 'Australia', 'Australia', 'Australien'); +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('AUT', 'Austria', 'Itävalta', 'Österrike'); +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('AZE', 'Azerbaijan', 'Azerbaidžan', 'Azerbajdzjan'); +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('BEL', 'Belgium', 'Belgia', 'Belgien'); +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('HRV', 'Croatia', 'Kroatia', 'Kroatien'); +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('CYP', 'Cyprus', 'Kypros', 'Cypern'); +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('CZE', 'Czechia', 'Tšekki', 'Tjeckien'); +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('DNK', 'Denmark', 'Tanska', 'Danmark'); +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('EST', 'Estonia', 'Viro', 'Estland'); +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('FIN', 'Finland', 'Suomi', 'Finland'); +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('FRA', 'France', 'Ranska', 'Frankrike'); +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('GEO', 'Georgia', 'Georgia', 'Georgien'); +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('DEU', 'Germany', 'Saksa', 'Tyskland'); +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('GRC', 'Greece', 'Kreikka', 'Grekland'); +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('ISL', 'Iceland', 'Islanti', 'Island'); +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('IRL', 'Ireland', 'Irlanti', 'Irland'); +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('ISR', 'Israel', 'Israel', 'Israel'); +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('ITA', 'Italy', 'Italia', 'Italien'); +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('LVA', 'Latvia', 'Latvia', 'Lettland'); +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('LTU', 'Lithuania', 'Liettua', 'Litauen'); +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('LUX', 'Luxembourg', 'Luxemburg', 'Luxemburg'); +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('MLT', 'Malta', 'Malta', 'Malta'); +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('MNE', 'Montenegro', 'Montenegro', 'Montenegro'); +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('NLD', 'Netherlands', 'Alankomaat', 'Nederländerna'); +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('NOR', 'Norway', 'Norja', 'Norge'); +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('POL', 'Poland', 'Puola', 'Polen'); +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('PRT', 'Portugal', 'Portugali', 'Portugal'); +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('SMR', 'San Marino', 'San Marino', 'San Marino'); +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('SRB', 'Serbia', 'Serbia', 'Serbien'); +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('SVN', 'Slovenia', 'Slovenia', 'Slovenien'); +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('ESP', 'Spain', 'Espanja', 'Spanien'); +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('SWE', 'Sweden', 'Ruotsi', 'Sverige'); +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('CHE', 'Switzerland', 'Sveitsi', 'Schweiz'); +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('UKR', 'Ukraine', 'Ukraina', 'Ukraina'); +INSERT INTO CountryCodes (code, name_en, name_fi, name_sv) VALUES ('GBR', 'United Kingdom', 'Englanti', 'Storbritannien'); + +-- ============================================================================= +-- Views (Optional - Not Created Here Based on Documentation Decision) +-- ============================================================================= +-- The documentation suggests performing result aggregations in the application +-- layer. No CREATE VIEW statements are included. +-- ============================================================================= + +-- End of Schema Definition