"""folders + photos is_hidden flag Revision ID: 0007_folder_hidden Revises: 0006_face_512d Create Date: 2026-04-11 Adds an "exclude from cross-cutting views" flag: folders.is_hidden — user-toggled on a folder or source root. When true, photos in that subtree are hidden from library-wide views (All Photos, Map, Tags, People, Search, Duplicates, sidebar counts) but remain indexed and visible when the user navigates into the folder directly. photos.is_hidden — denormalized: true iff any ancestor folder in the photo's folder chain has is_hidden=true. Kept as a real column (rather than a recursive query per read) because the filter runs on essentially every photo query in the app, and the toggle operation that recomputes it is rare. Indexed so `WHERE NOT is_hidden` doesn't fall off the rating/taken_at indexes. Both columns default to false so existing rows need no backfill. """ from typing import Sequence, Union from alembic import op import sqlalchemy as sa revision: str = "0007_folder_hidden" down_revision: Union[str, None] = "0006_face_512d" branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: op.add_column( "folders", sa.Column( "is_hidden", sa.Boolean(), nullable=False, server_default=sa.false(), ), ) op.add_column( "photos", sa.Column( "is_hidden", sa.Boolean(), nullable=False, server_default=sa.false(), ), ) op.create_index( "ix_photos_is_hidden", "photos", ["is_hidden"], ) def downgrade() -> None: op.drop_index("ix_photos_is_hidden", table_name="photos") op.drop_column("photos", "is_hidden") op.drop_column("folders", "is_hidden")