diff --git a/alembic/versions/0026_add_briefing_tables.py b/alembic/versions/0026_add_briefing_tables.py new file mode 100644 index 0000000..00120ff --- /dev/null +++ b/alembic/versions/0026_add_briefing_tables.py @@ -0,0 +1,75 @@ +"""Add briefing tables: rss_feeds, rss_items, weather_cache, conversation briefing columns.""" + +from alembic import op + +revision = "0026" +down_revision = "0025" + + +def upgrade() -> None: + # Extend conversations table + op.execute(""" + ALTER TABLE conversations + ADD COLUMN IF NOT EXISTS conversation_type TEXT NOT NULL DEFAULT 'chat', + ADD COLUMN IF NOT EXISTS briefing_date DATE + """) + op.execute("CREATE INDEX IF NOT EXISTS ix_conversations_type ON conversations(conversation_type)") + + # RSS feeds + op.execute(""" + CREATE TABLE IF NOT EXISTS rss_feeds ( + id SERIAL PRIMARY KEY, + user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, + url TEXT NOT NULL, + title TEXT NOT NULL DEFAULT '', + category TEXT, + last_fetched_at TIMESTAMPTZ, + CONSTRAINT uq_rss_feeds_user_url UNIQUE (user_id, url) + ) + """) + op.execute("CREATE INDEX IF NOT EXISTS ix_rss_feeds_user_id ON rss_feeds(user_id)") + + # RSS items + op.execute(""" + CREATE TABLE IF NOT EXISTS rss_items ( + id SERIAL PRIMARY KEY, + feed_id INTEGER NOT NULL REFERENCES rss_feeds(id) ON DELETE CASCADE, + guid TEXT NOT NULL, + title TEXT NOT NULL DEFAULT '', + url TEXT NOT NULL DEFAULT '', + published_at TIMESTAMPTZ, + content TEXT NOT NULL DEFAULT '', + fetched_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + CONSTRAINT uq_rss_items_feed_guid UNIQUE (feed_id, guid) + ) + """) + op.execute("CREATE INDEX IF NOT EXISTS ix_rss_items_feed_id ON rss_items(feed_id)") + op.execute("CREATE INDEX IF NOT EXISTS ix_rss_items_published_at ON rss_items(published_at)") + + # Weather cache + op.execute(""" + CREATE TABLE IF NOT EXISTS weather_cache ( + id SERIAL PRIMARY KEY, + user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, + location_key TEXT NOT NULL, + location_label TEXT NOT NULL DEFAULT '', + forecast_json JSONB, + previous_json JSONB, + fetched_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + CONSTRAINT uq_weather_cache_user_location UNIQUE (user_id, location_key) + ) + """) + op.execute("CREATE INDEX IF NOT EXISTS ix_weather_cache_user_id ON weather_cache(user_id)") + + +def downgrade() -> None: + op.execute("DROP INDEX IF EXISTS ix_weather_cache_user_id") + op.execute("DROP TABLE IF EXISTS weather_cache") + op.execute("DROP INDEX IF EXISTS ix_rss_items_published_at") + op.execute("DROP INDEX IF EXISTS ix_rss_items_feed_id") + op.execute("DROP TABLE IF EXISTS rss_items") + op.execute("DROP INDEX IF EXISTS ix_rss_feeds_user_id") + op.execute("DROP TABLE IF EXISTS rss_feeds") + op.execute("DROP INDEX IF EXISTS ix_conversations_type") + op.execute("ALTER TABLE conversations DROP COLUMN IF EXISTS briefing_date") + op.execute("ALTER TABLE conversations DROP COLUMN IF EXISTS conversation_type")