Files
video-gen/video-gen-api/alembic/versions/20260814_subscription_business_no.py
T
2026-08-14 15:23:46 +08:00

93 lines
3.2 KiB
Python

"""订阅实例业务流水号
Revision ID: 20260814_subscription_no
Revises: 20260814_restore_renewal
Create Date: 2026-08-14 14:23:00
说明:
- 每张 user_credit_subscriptions 增加永久唯一 subscription_no。
- 个人订阅前缀 PS,团队订阅前缀 TS。
- 全局共用 PostgreSQL Sequence,避免 COUNT/MAX 并发冲突。
- 历史记录按原 created_at 日期生成业务编号;编号只用于展示/客服定位,不参与业务排序和结算。
"""
from alembic import op
import sqlalchemy as sa
revision = "20260814_subscription_no"
down_revision = "20260814_restore_renewal"
branch_labels = None
depends_on = None
def _columns(table_name: str) -> set[str]:
inspector = sa.inspect(op.get_bind())
if table_name not in inspector.get_table_names():
return set()
return {item["name"] for item in inspector.get_columns(table_name)}
def _indexes(table_name: str) -> set[str]:
inspector = sa.inspect(op.get_bind())
if table_name not in inspector.get_table_names():
return set()
return {item["name"] for item in inspector.get_indexes(table_name)}
def upgrade() -> None:
bind = op.get_bind()
if bind.dialect.name != "postgresql":
raise RuntimeError("订阅实例流水号迁移当前仅支持 PostgreSQL")
op.execute("CREATE SEQUENCE IF NOT EXISTS credit_subscription_no_seq START WITH 1 INCREMENT BY 1")
if "subscription_no" not in _columns("user_credit_subscriptions"):
op.add_column(
"user_credit_subscriptions",
sa.Column(
"subscription_no",
sa.String(length=32),
nullable=True,
comment="订阅业务实例编号,供用户/客服/开发定位",
),
)
# 历史数据一次性补号。日期使用东八区业务日期;Sequence 只保证唯一,不要求无跳号。
op.execute(
"""
UPDATE user_credit_subscriptions
SET subscription_no =
CASE
WHEN product_type_snapshot = 'team_subscription' THEN 'TS'
ELSE 'PS'
END
|| to_char(COALESCE(created_at, start_at, now()) AT TIME ZONE 'Asia/Shanghai', 'YYYYMMDD')
|| lpad(nextval('credit_subscription_no_seq')::text, 6, '0')
WHERE subscription_no IS NULL OR btrim(subscription_no) = ''
"""
)
op.alter_column(
"user_credit_subscriptions",
"subscription_no",
existing_type=sa.String(length=32),
nullable=False,
)
if "uq_user_credit_subscriptions_no" not in _indexes("user_credit_subscriptions"):
op.create_index(
"uq_user_credit_subscriptions_no",
"user_credit_subscriptions",
["subscription_no"],
unique=True,
)
def downgrade() -> None:
if "uq_user_credit_subscriptions_no" in _indexes("user_credit_subscriptions"):
op.drop_index("uq_user_credit_subscriptions_no", table_name="user_credit_subscriptions")
if "subscription_no" in _columns("user_credit_subscriptions"):
op.drop_column("user_credit_subscriptions", "subscription_no")
op.execute("DROP SEQUENCE IF EXISTS credit_subscription_no_seq")