diff --git a/database/versions/9caa49cb3e10_2_2_6.py b/database/versions/9caa49cb3e10_2_2_6.py index 13b94090..be9f6c7f 100644 --- a/database/versions/9caa49cb3e10_2_2_6.py +++ b/database/versions/9caa49cb3e10_2_2_6.py @@ -22,14 +22,31 @@ def _has_column(inspector: sa.Inspector, table_name: str, column_name: str) -> b return any(column["name"] == column_name for column in inspector.get_columns(table_name)) -def upgrade() -> None: - inspector = sa.inspect(op.get_bind()) - if _has_column(inspector, "subscribe", "episode_priority") is False: - op.add_column("subscribe", sa.Column("episode_priority", sa.JSON(), nullable=True)) +def _ensure_json_column(bind, table_name: str, column_name: str) -> None: + """Add the column as JSON, or fix it if it already exists with the wrong type (PostgreSQL only).""" + inspector = sa.inspect(bind) + if not _has_column(inspector, table_name, column_name): + op.add_column(table_name, sa.Column(column_name, sa.JSON(), nullable=True)) + return + if bind.dialect.name != "postgresql": + return + for col in inspector.get_columns(table_name): + if col["name"] != column_name: + continue + type_name = type(col["type"]).__name__.upper() + if type_name in ("JSON", "JSONB"): + return + # Column exists with wrong type (e.g., INTEGER from an intermediate build); replace it. + # Existing values are non-functional garbage so data loss is acceptable. + op.drop_column(table_name, column_name) + op.add_column(table_name, sa.Column(column_name, sa.JSON(), nullable=True)) + return - inspector = sa.inspect(op.get_bind()) - if _has_column(inspector, "subscribehistory", "episode_priority") is False: - op.add_column("subscribehistory", sa.Column("episode_priority", sa.JSON(), nullable=True)) + +def upgrade() -> None: + bind = op.get_bind() + _ensure_json_column(bind, "subscribe", "episode_priority") + _ensure_json_column(bind, "subscribehistory", "episode_priority") def downgrade() -> None: diff --git a/database/versions/d5e6f7a8b9c0_2_2_8.py b/database/versions/d5e6f7a8b9c0_2_2_8.py new file mode 100644 index 00000000..294e54b6 --- /dev/null +++ b/database/versions/d5e6f7a8b9c0_2_2_8.py @@ -0,0 +1,50 @@ +"""2.2.8 +修复 episode_priority 列类型:PostgreSQL 下若列为 INTEGER 则重建为 JSON + +Revision ID: d5e6f7a8b9c0 +Revises: 1f0d2c3b4a5e +Create Date: 2026-06-04 +""" + +from alembic import op +import sqlalchemy as sa + +revision = "d5e6f7a8b9c0" +down_revision = "1f0d2c3b4a5e" +branch_labels = None +depends_on = None + + +def _has_column(inspector: sa.Inspector, table_name: str, column_name: str) -> bool: + if table_name not in inspector.get_table_names(): + return False + return any(column["name"] == column_name for column in inspector.get_columns(table_name)) + + +def _fix_episode_priority_type(bind, table_name: str) -> None: + """On PostgreSQL, if episode_priority exists but is not JSON/JSONB, drop and re-add it as JSON.""" + if bind.dialect.name != "postgresql": + return + inspector = sa.inspect(bind) + if not _has_column(inspector, table_name, "episode_priority"): + op.add_column(table_name, sa.Column("episode_priority", sa.JSON(), nullable=True)) + return + for col in inspector.get_columns(table_name): + if col["name"] != "episode_priority": + continue + type_name = type(col["type"]).__name__.upper() + if type_name in ("JSON", "JSONB"): + return + op.drop_column(table_name, "episode_priority") + op.add_column(table_name, sa.Column("episode_priority", sa.JSON(), nullable=True)) + return + + +def upgrade() -> None: + bind = op.get_bind() + _fix_episode_priority_type(bind, "subscribe") + _fix_episode_priority_type(bind, "subscribehistory") + + +def downgrade() -> None: + pass