| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384 |
- """站内通知表 sys_notification(契约 1.34)。
- Revision ID: 0036_notification
- Revises: 0035_drop_audit_action_check
- Create Date: 2026-09-15
- 变更要点:
- 1. 新建 sys_notification:用户站内通知(审批待办等),追加型表,
- 不含业务表 mixin 的软删/乐观锁列;
- 2. 双引擎幂等:先探测表存在再建(MySQL 与达梦升级互不冲突);
- 3. 降级保护:存在通知记录时拒绝有损降级。
- """
- from __future__ import annotations
- from collections.abc import Sequence
- import sqlalchemy as sa
- from alembic import op
- from sqlalchemy.dialects import mysql
- revision: str = "0036_notification"
- down_revision: str | None = "0035_drop_audit_action_check"
- branch_labels: str | Sequence[str] | None = None
- depends_on: str | Sequence[str] | None = None
- def _table_exists(table: str) -> bool:
- # 达梦 inspector 返回大写表名,统一小写比较
- inspector = sa.inspect(op.get_bind())
- return table.lower() in {name.lower() for name in inspector.get_table_names()}
- def upgrade() -> None:
- if _table_exists("sys_notification"):
- return
- op.create_table(
- "sys_notification",
- sa.Column("id", sa.BigInteger(), autoincrement=True, nullable=False),
- sa.Column("user_id", sa.BigInteger(), nullable=False),
- sa.Column("title", sa.String(length=200), nullable=False),
- sa.Column("content", sa.String(length=1000), nullable=True),
- sa.Column("notify_type", sa.String(length=32), nullable=False),
- sa.Column("action", sa.String(length=16), nullable=False),
- sa.Column("status", sa.String(length=16), nullable=False),
- sa.Column(
- "created_at",
- mysql.DATETIME(fsp=3),
- server_default=sa.text("CURRENT_TIMESTAMP(3)"),
- nullable=False,
- ),
- sa.Column("handled_at", mysql.DATETIME(fsp=3), nullable=True),
- sa.PrimaryKeyConstraint("id"),
- sa.CheckConstraint(
- "notify_type IN ('APPROVAL')",
- name="notification_notify_type",
- ),
- sa.CheckConstraint(
- "action IN ('NONE', 'PENDING', 'AGREE', 'REJECT')",
- name="notification_action",
- ),
- sa.CheckConstraint(
- "status IN ('UNREAD', 'READ')",
- name="notification_status",
- ),
- )
- op.create_index(
- "ix_sys_notification_user_id",
- "sys_notification",
- ["user_id", "id"],
- )
- def downgrade() -> None:
- if not _table_exists("sys_notification"):
- return
- rows = op.get_bind().scalar(sa.text("SELECT COUNT(*) FROM sys_notification"))
- if rows:
- raise RuntimeError(
- "0036已存在通知记录,拒绝有损降级;请先备份并按数据治理流程处理"
- )
- op.drop_index("ix_sys_notification_user_id", table_name="sys_notification")
- op.drop_table("sys_notification")
|