"""A file's "Added" is when it became done Revision ID: 0104_job_ready_at Revises: 0103_files_sha256 Create Date: 2026-10-12 `download_jobs.ready_at` is when a job became done, and the Files library sorts and dates by it: a download that failed for days and then went through used to sit days down the list, under its request date. Every path to done stamps it, held by `ck_download_jobs_ready_at`. A done job from before has no record of that moment, except where its "ready to watch" notice is still in the owner's inbox (read notices are pruned past a cap): that notice was written the moment it finished. The rest take the request date, which is where they already sat. """ import sqlalchemy as sa from alembic import op revision: str = "0104_job_ready_at" down_revision: str | None = "0103_files_sha256" branch_labels: str | None = None depends_on: str | None = None def upgrade() -> None: op.add_column("download_jobs", sa.Column("ready_at", sa.DateTime(timezone=True))) op.execute( """ UPDATE download_jobs j SET ready_at = COALESCE( (SELECT max(n.created_at) FROM notifications n WHERE n.type = 'download_done' AND n.user_id = j.user_id AND n.data->>'job_id' = j.id::text), j.created_at) WHERE j.status = 'done' """ ) op.create_check_constraint( "ck_download_jobs_ready_at", "download_jobs", "status <> 'done' OR ready_at IS NOT NULL" ) def downgrade() -> None: op.drop_constraint("ck_download_jobs_ready_at", "download_jobs", type_="check") op.drop_column("download_jobs", "ready_at")