"""refresh_tokens:轮换 lineage(replaced_by_token_id + rotated_at) Revision ID: 0020_refresh_rt_lineage Revises: 0019_align_legacy_schema """ from typing import Sequence, Union import sqlalchemy as sa from alembic import op revision: str = "0020_refresh_rt_lineage" down_revision: Union[str, None] = "0019_align_legacy_schema" branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None def _column_names(table_name: str) -> set[str]: bind = op.get_bind() inspector = sa.inspect(bind) return {column["name"] for column in inspector.get_columns(table_name)} def upgrade() -> None: columns = _column_names("refresh_tokens") if "replaced_by_token_id" not in columns: op.add_column( "refresh_tokens", sa.Column("replaced_by_token_id", sa.String(), nullable=True), ) op.create_index( "ix_refresh_tokens_replaced_by_token_id", "refresh_tokens", ["replaced_by_token_id"], unique=False, ) op.create_foreign_key( "fk_refresh_tokens_replaced_by_token_id", "refresh_tokens", "refresh_tokens", ["replaced_by_token_id"], ["id"], ondelete="SET NULL", ) if "rotated_at" not in columns: op.add_column( "refresh_tokens", sa.Column("rotated_at", sa.DateTime(timezone=True), nullable=True), ) def downgrade() -> None: columns = _column_names("refresh_tokens") if "replaced_by_token_id" in columns: op.drop_constraint( "fk_refresh_tokens_replaced_by_token_id", "refresh_tokens", type_="foreignkey", ) op.drop_index("ix_refresh_tokens_replaced_by_token_id", table_name="refresh_tokens") op.drop_column("refresh_tokens", "replaced_by_token_id") if "rotated_at" in columns: op.drop_column("refresh_tokens", "rotated_at")