package models import ( "database/sql/driver" "errors" "fmt" "strconv" "strings" ) // GetAllModels 返回一个包含所有数据库模型实例的切片。 // 这个函数用于在数据库初始化时自动迁移所有的表结构。 func GetAllModels() []interface{} { return []interface{}{ &User{}, &Device{}, &Plan{}, &SubPlan{}, &Task{}, &PlanExecutionLog{}, &TaskExecutionLog{}, &PendingTask{}, &SensorData{}, &DeviceCommandLog{}, &PendingCollection{}, &AreaController{}, &DeviceTemplate{}, &UserActionLog{}, } } // UintArray 是一个自定义类型,代表 uint 的切片。 // 它实现了 gorm.Scanner 和 driver.Valuer 接口, // 以便能与数据库的 bigint[] 类型进行原生映射。 type UintArray []uint // Value 实现了 driver.Valuer 接口。 // 它告诉 GORM 如何将 UintArray ([]) 转换为数据库能够理解的格式。 func (a UintArray) Value() (driver.Value, error) { if a == nil { return "{}", nil } var b strings.Builder b.WriteString("{") for i, v := range a { if i > 0 { b.WriteString(",") } b.WriteString(strconv.FormatUint(uint64(v), 10)) } b.WriteString("}") return b.String(), nil } // Scan 实现了 gorm.Scanner 接口。 // 它告诉 GORM 如何将从数据库读取的数据转换为我们的 UintArray ([])。 func (a *UintArray) Scan(src interface{}) error { if src == nil { *a = nil return nil } var srcStr string switch v := src.(type) { case []byte: srcStr = string(v) case string: srcStr = v default: return errors.New("无法扫描非字符串或字节类型的源到 UintArray") } // 去掉花括号 srcStr = strings.Trim(srcStr, "{}") if srcStr == "" { *a = []uint{} return nil } // 按逗号分割 parts := strings.Split(srcStr, ",") arr := make([]uint, len(parts)) for i, p := range parts { val, err := strconv.ParseUint(p, 10, 64) if err != nil { return fmt.Errorf("解析 UintArray 元素失败: %w", err) } arr[i] = uint(val) } *a = arr return nil }