"""normalize plex JSONB tag columns: scalar `null` -> SQL NULL (R6 S3a) Pre-0.53.1 rows persisted a genre-less show/movie's genres/directors/cast_names/collection_keys as a JSONB scalar `null` (SQLAlchemy wrote a Python None as JSON null before none_as_null=True). The 0.53.1 hotfix added none_as_null=True (new writes are SQL NULL) + jsonb_typeof read-guards, but the existing rows stayed JSON `null`, which kept those read-guards load-bearing rather than belt-only. This one-time data fixup rewrites those scalars to SQL NULL so the columns are uniform. Data-only, forward-only: a SQL NULL is indistinguishable from the old JSON `null` to every reader (the guards treat both as "not an array"), so there is nothing meaningful to downgrade. No schema change. """ from typing import Sequence, Union from alembic import op revision: str = "0060_plex_jsonb_null_normalize" down_revision: Union[str, None] = "0059_dl_link_pw_version" branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None _TABLES = ("plex_items", "plex_shows") _COLS = ("genres", "directors", "cast_names", "collection_keys") def upgrade() -> None: for table in _TABLES: for col in _COLS: op.execute( f"UPDATE {table} SET {col} = NULL WHERE jsonb_typeof({col}) = 'null'" ) def downgrade() -> None: pass # forward-only: SQL NULL == the old JSON null for every reader