Files
dpb/backend/scripts/run_migrations.py
T
34047007@qq.com b95053c52c init: 初始化 dpb 桃育种系统代码库
前后端 + 后端 FastAPI 全量源码、部署脚本与文档。
2026-08-06 00:17:49 +08:00

87 lines
3.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""breeding 迁移套件统一入口(幂等,按依赖顺序执行)。
背景:全系统统一修复产生了多支幂等迁移脚本,分散执行易漏、易错序。
本脚本按「依赖顺序 + 数据库方言矩阵」串起整套迁移,供 deploy migrate 调用。
用法(backend/ 目录):
python scripts/run_migrations.py # 执行整套迁移
python scripts/run_migrations.py --check # 预览(仅支持 --check 的脚本预览,其余跳过)
方言矩阵:
fix_breeding_columns.py ORM↔数据库列补齐 全部方言
schema_align.py 审计列统一新契约 仅 PostgreSQL
add_unique_constraints.py 部分唯一索引(未软删)并发兜底 仅 PostgreSQL
migrate_dict_english.py 字典存量中文 label → 英码 value 全部方言
说明:
- PostgreSQL 专属迁移(部分唯一索引、gen_random_uuid 等)仅在
postgres 方言下运行,其余方言自动跳过并提示;
- 每支脚本均幂等,可重复执行;--check 仅对声明支持的脚本生效(不支持的跳过,
避免 --check 误触发 DDL)。
"""
import dataclasses
import os
import subprocess
import sys
from pathlib import Path
BACKEND_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if BACKEND_DIR not in sys.path:
sys.path.insert(0, BACKEND_DIR)
SCRIPTS_DIR = Path(__file__).resolve().parent
@dataclasses.dataclass
class Migration:
name: str
dialects: set[str] # 适用方言;"*" 表示全部
desc: str
check: bool # 是否支持 --check 预览
SUITE: list[Migration] = [
Migration("fix_breeding_columns.py", {"*"}, "ORM 与数据库列补齐(生成器改字段后同步)", True),
Migration("schema_align.py", {"postgres"}, "审计列统一新契约(uuid/is_deleted bool/审计 FK", False),
Migration("align_columns.py", {"postgres"}, "业务必填列 NOT NULL 对齐(无 NULL 才收紧)", True),
Migration("add_unique_constraints.py", {"postgres"}, "业务唯一约束落库(部分唯一索引,未软删)", True),
Migration("migrate_dict_english.py", {"*"}, "字典存量值中文 label 到英码 value(与 bre_dict.sql 对齐)", True),
Migration("supplement_tree_status_dict.py", {"*"}, "补充单株状态字典 tree_status 初选/重点/保存 三态", True),
Migration("create_v_trait_value.py", {"postgres"}, "统一性状值视图 v_trait_value(统计消费)", True),
]
def main() -> None:
from app.config.setting import settings
check = "--check" in sys.argv
dialect = settings.DATABASE_TYPE
print(f"[run_migrations] 数据库方言: {dialect} 模式: {'预览 --check' if check else '执行'}")
failed: list[str] = []
for mig in SUITE:
if "*" not in mig.dialects and dialect not in mig.dialects:
print(f"[run_migrations] 跳过 {mig.name}{mig.desc}: 方言 {dialect} 不支持")
continue
if check and not mig.check:
print(f"[run_migrations] 跳过 {mig.name}{mig.desc}): 该脚本不支持 --check 预览")
continue
cmd = [sys.executable, str(SCRIPTS_DIR / mig.name)]
if check:
cmd.append("--check")
print(f"[run_migrations] 执行 {mig.name}{mig.desc}...")
r = subprocess.run(cmd)
if r.returncode != 0:
failed.append(mig.name)
print(f"[run_migrations] {mig.name} 失败,退出码 {r.returncode}")
if failed:
print(f"[run_migrations] 有 {len(failed)} 个迁移失败: {', '.join(failed)}")
sys.exit(1)
print("[run_migrations] 全部迁移完成")
if __name__ == "__main__":
main()