| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768 |
- """门户跳转用户预置:sys_user.external_id + 软删唯一约束。
- Revision ID: 0016_portal_user_provision
- Revises: 0015_login_ip_restriction
- Create Date: 2026-08-23
- 变更要点:
- 1. sys_user 新增 external_id(对端门户系统的用户唯一标识,NULL=本地原生用户);
- 2. 新增 MySQL 生成列 active_marker(未删=1,已删=NULL)与
- 唯一约束 uq_sys_user_external_id_active,防止同一门户用户重复落库;
- 3. 降级:存在门户用户时拒绝有损降级。
- """
- from __future__ import annotations
- from collections.abc import Sequence
- from alembic import op
- import sqlalchemy as sa
- revision: str = "0016_portal_user_provision"
- down_revision: str | None = "0015_login_ip_restriction"
- branch_labels: str | Sequence[str] | None = None
- depends_on: str | Sequence[str] | None = None
- def upgrade() -> None:
- op.add_column(
- "sys_user",
- sa.Column("external_id", sa.String(length=128), nullable=True),
- )
- op.add_column(
- "sys_user",
- sa.Column(
- "active_marker",
- sa.Integer(),
- sa.Computed("IF(is_deleted = 0, 1, NULL)", persisted=False),
- nullable=True,
- ),
- )
- op.create_unique_constraint(
- "uq_sys_user_external_id_active",
- "sys_user",
- ["external_id", "active_marker"],
- )
- op.create_index(
- "ix_sys_user_external_active",
- "sys_user",
- ["external_id", "is_deleted"],
- )
- def downgrade() -> None:
- bind = op.get_bind()
- portal_users = bind.scalar(
- sa.text("SELECT COUNT(*) FROM sys_user WHERE external_id IS NOT NULL")
- )
- if portal_users:
- raise RuntimeError(
- "0016已存在门户用户(external_id非空),拒绝有损降级;"
- "请先备份并按数据治理流程处理"
- )
- op.drop_index("ix_sys_user_external_active", table_name="sys_user")
- op.drop_constraint(
- "uq_sys_user_external_id_active", "sys_user", type_="unique"
- )
- op.drop_column("sys_user", "active_marker")
- op.drop_column("sys_user", "external_id")
|