"""per-user saved smart views Revision ID: 0035_saved_views Revises: 0034_blocked_channels Create Date: 2026-07-01 Adds the `saved_views` table: per-user named snapshots of the feed's filter/sort state. Each row stores the serialized FeedFilters (JSON), a sidebar `position` for drag-reorder, and an `is_default` flag (at most one per user, enforced by the API) for the view applied on load. """ from typing import Sequence, Union import sqlalchemy as sa from alembic import op revision: str = "0035_saved_views" down_revision: Union[str, None] = "0034_blocked_channels" branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: op.create_table( "saved_views", sa.Column("id", sa.Integer(), nullable=False), sa.Column("user_id", sa.Integer(), nullable=False), sa.Column("name", sa.String(length=80), nullable=False), sa.Column("filters", sa.JSON(), nullable=False), sa.Column( "position", sa.Integer(), server_default=sa.text("0"), nullable=False ), sa.Column( "is_default", sa.Boolean(), server_default=sa.text("false"), nullable=False, ), sa.Column( "created_at", sa.DateTime(timezone=True), server_default=sa.text("now()"), nullable=False, ), sa.Column( "updated_at", sa.DateTime(timezone=True), server_default=sa.text("now()"), nullable=False, ), sa.ForeignKeyConstraint(["user_id"], ["users.id"], ondelete="CASCADE"), sa.PrimaryKeyConstraint("id"), sa.UniqueConstraint("user_id", "name", name="uq_user_saved_view"), ) op.create_index("ix_saved_views_user_id", "saved_views", ["user_id"]) def downgrade() -> None: op.drop_index("ix_saved_views_user_id", table_name="saved_views") op.drop_table("saved_views")