fix(database): 修复空库基线迁移因索引命名不一致而失败

GORM 1.30 AutoMigrate 对已存在表的唯一索引执行 `DROP INDEX uni_<表>_<列>`,
而建表阶段用的是 idx_ 前缀,索引名永不匹配,空库执行基线必然以
Error 1091 (Can't DROP ...; check that column/key exists) 失败。

- 新增 indexNamedNaming,令 UniqueName 复用 IndexName 的 idx_ 命名
- BootstrapSchema 改为一次性 AutoMigrate(allModels...),
  让 GORM 在外键依赖排序生效(如 asset_cloud_regions 先于 asset_servers)

// Logan.Li
This commit is contained in:
Logan.Li committed 2026-09-14 07:59:36 +00:00
1 parent 0996d8a839
commit 93abf81e40
1 file changed
+20 -5
+20 -5
View File
@@ -14,6 +14,7 @@ import (
"gorm.io/driver/postgres"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"gorm.io/gorm/schema"
)
// New 创建数据库连接
@@ -50,7 +51,8 @@ func New(cfg config.DatabaseConfig) (*gorm.DB, error) {
}
db, err := gorm.Open(dialector, &gorm.Config{
Logger: logger.Default.LogMode(logger.Silent),
Logger: logger.Default.LogMode(logger.Silent),
NamingStrategy: indexNamedNaming{},
})
if err != nil {
return nil, err
@@ -69,6 +71,19 @@ func New(cfg config.DatabaseConfig) (*gorm.DB, error) {
return db, nil
}
// indexNamedNaming 让唯一索引与普通索引使用同一套命名规则(idx_ 前缀)。
// GORM 1.30 的 AutoMigrate 在表已存在时会对唯一索引列执行 `DROP INDEX uni_<表>_<列>`
// (NamingStrategy.UniqueName 用 uni_ 前缀),而建表实际使用 `idx_<表>_<列>`,
// 索引名永远不匹配,空库执行基线必然以 1091 失败。 // Logan.Li
type indexNamedNaming struct {
schema.NamingStrategy
}
// UniqueName 保持与 IndexName 一致,避免 AutoMigrate 误删不存在的唯一索引。
func (n indexNamedNaming) UniqueName(table, column string) string {
return n.NamingStrategy.IndexName(table, column)
}
// BootstrapSchema 为空数据库创建初始基线结构。
// 该函数只能由显式的 `aiops migrate up` 调用,服务启动路径禁止调用。 // Logan.Li
func BootstrapSchema(db *gorm.DB) error {
@@ -177,10 +192,10 @@ func BootstrapSchema(db *gorm.DB) error {
&model.TraceDataSource{}, // 链路追踪数据源 Jaeger/Tempo // Logan.Li
}
for _, m := range allModels {
if err := db.AutoMigrate(m); err != nil {
return fmt.Errorf("创建初始基线表失败 (%T): %w", m, err)
}
// 必须一次性传入全部模型:GORM 只在单次调用内做外键依赖排序
// (如 asset_cloud_regions 必须在 asset_servers 之前建表),逐个建表会踩外键顺序问题。 // Logan.Li
if err := db.AutoMigrate(allModels...); err != nil {
return fmt.Errorf("创建初始基线表失败: %w", err)
}
return nil
}