CREATE TABLE IF NOT EXISTS keywords ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), keyword text NOT NULL, interval_minutes int NOT NULL DEFAULT 60, is_active boolean NOT NULL DEFAULT true, last_scraped_at timestamptz, initial_loaded boolean NOT NULL DEFAULT false, created_at timestamptz NOT NULL DEFAULT now() ); CREATE UNIQUE INDEX IF NOT EXISTS idx_keywords_unique_lower ON keywords (LOWER(keyword)); CREATE TABLE IF NOT EXISTS keyword_subscriptions ( keyword_id uuid NOT NULL REFERENCES keywords(id) ON DELETE CASCADE, user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE, subscribed_at timestamptz NOT NULL DEFAULT now(), PRIMARY KEY (keyword_id, user_id) ); CREATE INDEX IF NOT EXISTS idx_keyword_subscriptions_user ON keyword_subscriptions(user_id); ALTER TABLE ads ADD COLUMN IF NOT EXISTS postcode TEXT; ALTER TABLE ads ADD COLUMN IF NOT EXISTS modified_at TIMESTAMPTZ; DO $$ DECLARE sq_record RECORD; kw_id uuid; BEGIN FOR sq_record IN SELECT DISTINCT LOWER(keyword) AS keyword, interval_minutes, is_active, last_scraped_at FROM search_queries LOOP INSERT INTO keywords (keyword, interval_minutes, is_active, last_scraped_at) VALUES (sq_record.keyword, sq_record.interval_minutes, sq_record.is_active, sq_record.last_scraped_at) ON CONFLICT DO NOTHING; END LOOP; FOR sq_record IN SELECT user_id, LOWER(keyword) AS keyword FROM search_queries LOOP SELECT id INTO kw_id FROM keywords WHERE LOWER(keyword) = sq_record.keyword LIMIT 1; IF kw_id IS NOT NULL THEN INSERT INTO keyword_subscriptions (keyword_id, user_id) VALUES (kw_id, sq_record.user_id) ON CONFLICT DO NOTHING; END IF; END LOOP; END $$; UPDATE keywords SET initial_loaded = true WHERE id IN ( SELECT DISTINCT kw.id FROM keywords kw INNER JOIN search_queries sq ON LOWER(sq.keyword) = LOWER(kw.keyword) WHERE EXISTS ( SELECT 1 FROM scrape_logs sl WHERE sl.search_query_id = sq.id AND sl.status = 'success' ) ); ALTER TABLE scrape_logs DROP CONSTRAINT IF EXISTS scrape_logs_search_query_id_fkey; ALTER TABLE scrape_logs RENAME COLUMN search_query_id TO keyword_id; UPDATE scrape_logs sl SET keyword_id = kw.id FROM search_queries sq, keywords kw WHERE sl.keyword_id = sq.id AND LOWER(sq.keyword) = LOWER(kw.keyword); DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM information_schema.table_constraints WHERE constraint_name = 'fk_scrape_logs_keyword') THEN ALTER TABLE scrape_logs ADD CONSTRAINT fk_scrape_logs_keyword FOREIGN KEY (keyword_id) REFERENCES keywords(id) ON DELETE CASCADE; END IF; END $$; DROP TABLE IF EXISTS query_ads CASCADE; DROP TABLE IF EXISTS search_queries CASCADE;