| |
| |
|
|
| CREATE TABLE IF NOT EXISTS topics ( |
| id SERIAL PRIMARY KEY, |
| name VARCHAR(100) NOT NULL UNIQUE, |
| description TEXT, |
| difficulty VARCHAR(20) DEFAULT 'medium' CHECK (difficulty IN ('easy', 'medium', 'hard')), |
| word_count INTEGER DEFAULT 0, |
| created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, |
| updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP |
| ); |
|
|
| CREATE TABLE IF NOT EXISTS words ( |
| id SERIAL PRIMARY KEY, |
| word VARCHAR(50) NOT NULL, |
| length INTEGER NOT NULL, |
| topic_id INTEGER REFERENCES topics(id) ON DELETE CASCADE, |
| difficulty VARCHAR(20) DEFAULT 'medium' CHECK (difficulty IN ('easy', 'medium', 'hard')), |
| created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, |
| CONSTRAINT unique_word_topic UNIQUE (word, topic_id) |
| ); |
|
|
| CREATE TABLE IF NOT EXISTS clues ( |
| id SERIAL PRIMARY KEY, |
| word_id INTEGER REFERENCES words(id) ON DELETE CASCADE, |
| clue_text TEXT NOT NULL, |
| difficulty VARCHAR(20) DEFAULT 'medium' CHECK (difficulty IN ('easy', 'medium', 'hard')), |
| is_primary BOOLEAN DEFAULT true, |
| created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP |
| ); |
|
|
| CREATE TABLE IF NOT EXISTS generated_puzzles ( |
| id SERIAL PRIMARY KEY, |
| grid_data JSONB NOT NULL, |
| clues_data JSONB NOT NULL, |
| metadata JSONB, |
| topics TEXT[] NOT NULL, |
| difficulty VARCHAR(20) DEFAULT 'medium', |
| word_count INTEGER, |
| grid_size INTEGER, |
| created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, |
| expires_at TIMESTAMP WITH TIME ZONE DEFAULT (CURRENT_TIMESTAMP + INTERVAL '24 hours') |
| ); |
|
|
| |
| CREATE INDEX IF NOT EXISTS idx_words_topic_id ON words(topic_id); |
| CREATE INDEX IF NOT EXISTS idx_words_length ON words(length); |
| CREATE INDEX IF NOT EXISTS idx_words_difficulty ON words(difficulty); |
| CREATE INDEX IF NOT EXISTS idx_clues_word_id ON clues(word_id); |
| CREATE INDEX IF NOT EXISTS idx_clues_primary ON clues(is_primary); |
| CREATE INDEX IF NOT EXISTS idx_puzzles_topics ON generated_puzzles USING GIN(topics); |
| CREATE INDEX IF NOT EXISTS idx_puzzles_difficulty ON generated_puzzles(difficulty); |
| CREATE INDEX IF NOT EXISTS idx_puzzles_expires ON generated_puzzles(expires_at); |
|
|
| |
| CREATE OR REPLACE FUNCTION update_topic_word_count() |
| RETURNS TRIGGER AS $$ |
| BEGIN |
| IF TG_OP = 'INSERT' THEN |
| UPDATE topics |
| SET word_count = word_count + 1, updated_at = CURRENT_TIMESTAMP |
| WHERE id = NEW.topic_id; |
| RETURN NEW; |
| ELSIF TG_OP = 'DELETE' THEN |
| UPDATE topics |
| SET word_count = word_count - 1, updated_at = CURRENT_TIMESTAMP |
| WHERE id = OLD.topic_id; |
| RETURN OLD; |
| END IF; |
| RETURN NULL; |
| END; |
| $$ LANGUAGE plpgsql; |
|
|
| |
| CREATE TRIGGER trigger_update_word_count |
| AFTER INSERT OR DELETE ON words |
| FOR EACH ROW |
| EXECUTE FUNCTION update_topic_word_count(); |
|
|
| |
| CREATE OR REPLACE FUNCTION cleanup_expired_puzzles() |
| RETURNS INTEGER AS $$ |
| DECLARE |
| deleted_count INTEGER; |
| BEGIN |
| DELETE FROM generated_puzzles WHERE expires_at < CURRENT_TIMESTAMP; |
| GET DIAGNOSTICS deleted_count = ROW_COUNT; |
| RETURN deleted_count; |
| END; |
| $$ LANGUAGE plpgsql; |