da9014831a
asyncpg+alembic keeps a transaction open via begin_transaction(); calling execution_options(isolation_level=AUTOCOMMIT) on an already-begun connection raises InvalidRequestError. Replace with explicit COMMIT before ALTER TYPE and BEGIN before the backfill UPDATE. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
50 lines
1.9 KiB
Python
50 lines
1.9 KiB
Python
"""Extend UserRole enum: add global_admin and tenant_admin.
|
|
|
|
Existing 'admin' users are backfilled to 'global_admin'.
|
|
The legacy 'admin' value is kept in the enum so existing tokens/sessions
|
|
remain valid during the transition period. It will be removed in a later
|
|
cleanup migration once all call sites are updated.
|
|
|
|
Revision ID: 049
|
|
Revises: 048
|
|
"""
|
|
from alembic import op
|
|
import sqlalchemy as sa
|
|
|
|
revision = "049"
|
|
down_revision = "048"
|
|
branch_labels = None
|
|
depends_on = None
|
|
|
|
|
|
def upgrade() -> None:
|
|
# PostgreSQL requires ALTER TYPE ADD VALUE to be committed before the new value
|
|
# can be referenced in the same session. With asyncpg + alembic the connection
|
|
# already has an open transaction (begin_transaction), so we cannot change
|
|
# isolation level via execution_options. Instead we manually COMMIT the outer
|
|
# transaction, run the DDL, then open a new transaction for the DML backfill.
|
|
conn = op.get_bind()
|
|
|
|
# Commit the alembic-managed transaction so ALTER TYPE runs outside a tx block
|
|
conn.execute(sa.text("COMMIT"))
|
|
conn.execute(sa.text("ALTER TYPE userrole ADD VALUE IF NOT EXISTS 'global_admin'"))
|
|
conn.execute(sa.text("ALTER TYPE userrole ADD VALUE IF NOT EXISTS 'tenant_admin'"))
|
|
|
|
# Start a new transaction for the backfill DML
|
|
conn.execute(sa.text("BEGIN"))
|
|
conn.execute(
|
|
sa.text("UPDATE users SET role = 'global_admin'::userrole WHERE role = 'admin'::userrole")
|
|
)
|
|
|
|
|
|
def downgrade() -> None:
|
|
# Restore global_admin/tenant_admin back to admin (for rollback)
|
|
op.execute(
|
|
"UPDATE users SET role = 'admin'::userrole WHERE role = 'global_admin'::userrole"
|
|
)
|
|
op.execute(
|
|
"UPDATE users SET role = 'client'::userrole WHERE role = 'tenant_admin'::userrole"
|
|
)
|
|
# Note: cannot DROP enum values in PostgreSQL without recreating the type
|
|
# The values will remain in the enum but unused after downgrade
|