"""news tables: scraped articles + LLM article_summaries Revision ID: 003_news Revises: 002_cameras Create Date: 2026-08-24 """ from alembic import op import sqlalchemy as sa # noqa: F401 # revision identifiers, used by Alembic. revision = '003_news' down_revision = '002_cameras' branch_labels = None depends_on = None def upgrade() -> None: # Idempotent DDL: the news scraper's Scrapy pipeline also issues # `CREATE TABLE IF NOT EXISTS articles`, so either the scraper or the app # may create these first depending on container startup order. IF NOT # EXISTS makes both orders safe — whichever runs first wins, the other # no-ops. Same table shapes as the upstream newsPipeline services. op.execute( """ CREATE TABLE IF NOT EXISTS articles ( id SERIAL PRIMARY KEY, title TEXT, url TEXT UNIQUE, content TEXT, domain TEXT, timestamp TIMESTAMPTZ ) """ ) op.execute( "CREATE INDEX IF NOT EXISTS ix_articles_timestamp ON articles (timestamp)" ) op.execute( """ CREATE TABLE IF NOT EXISTS article_summaries ( id SERIAL PRIMARY KEY, summary_text TEXT NOT NULL, batch_timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW() ) """ ) op.execute( "CREATE INDEX IF NOT EXISTS ix_article_summaries_batch_timestamp " "ON article_summaries (batch_timestamp)" ) def downgrade() -> None: op.execute("DROP TABLE IF EXISTS article_summaries") op.execute("DROP TABLE IF EXISTS articles")