Files
pig-farm-controller/internal/infra/models/models.go

199 lines
4.7 KiB
Go
Raw Normal View History

2025-09-13 15:14:08 +08:00
package models
import (
"database/sql/driver"
"errors"
"fmt"
"strconv"
"strings"
"go.uber.org/zap/zapcore"
)
2025-09-13 15:14:08 +08:00
// GetAllModels 返回一个包含所有数据库模型实例的切片。
// 这个函数用于在数据库初始化时自动迁移所有的表结构。
func GetAllModels() []interface{} {
return []interface{}{
// Core Models
2025-09-13 15:14:08 +08:00
&User{},
&UserActionLog{},
// Device Models
2025-09-13 15:14:08 +08:00
&Device{},
&AreaController{},
&DeviceTemplate{},
&SensorData{},
&DeviceCommandLog{},
&DeviceTask{},
// Plan & Task Models
2025-09-13 15:14:08 +08:00
&Plan{},
&SubPlan{},
&Task{},
2025-09-17 16:17:36 +08:00
&PlanExecutionLog{},
&TaskExecutionLog{},
&PendingTask{},
&PendingCollection{},
// Farm Asset Models
&PigHouse{},
&Pen{},
// Pig & Batch Models
&PigBatch{},
&PigBatchLog{},
2025-10-03 20:32:34 +08:00
&WeighingBatch{},
&WeighingRecord{},
2025-10-05 21:20:22 +08:00
&PigTransferLog{},
2025-10-06 15:35:20 +08:00
&PigSickLog{},
2025-10-05 22:09:25 +08:00
// Pig Buy & Sell
&PigPurchase{},
&PigSale{},
// Feed Models
&RawMaterial{},
&RawMaterialPurchase{},
&RawMaterialStockLog{},
&FeedFormula{},
&FeedFormulaComponent{},
&FeedUsageRecord{},
// Medication Models
&Medication{},
2025-10-06 15:35:20 +08:00
&MedicationLog{},
2025-10-25 13:28:19 +08:00
// Notification Models
&Notification{},
}
}
// 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
2025-09-13 15:14:08 +08:00
}
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
2025-09-13 15:14:08 +08:00
}
// SeverityLevel 定义了系统中告警、通知、日志的统一级别枚举。
// 它以中文形式存储在数据库中,提高了可读性。
type SeverityLevel string
const (
// DebugLevel 调试级别,用于开发和诊断问题。
DebugLevel SeverityLevel = "Debug"
// InfoLevel 信息级别,用于记录常规操作。
InfoLevel SeverityLevel = "Info"
// WarnLevel 警告级别,表示出现潜在问题,需要关注。
WarnLevel SeverityLevel = "Warn"
// ErrorLevel 错误级别,表示发生了需要处理的错误。
ErrorLevel SeverityLevel = "Error"
// DPanicLevel 开发时崩溃级别,在开发模式下会触发 panic。
DPanicLevel SeverityLevel = "DPanic"
// PanicLevel 崩溃级别,记录日志后会立即触发 panic。
PanicLevel SeverityLevel = "Panic"
// FatalLevel 致命级别,记录日志后会调用 os.Exit(1) 退出程序。
FatalLevel SeverityLevel = "Fatal"
)
// ToZapLevel 将我们的自定义级别转换为 zapcore.Level以便与日志记录器兼容。
func (al SeverityLevel) ToZapLevel() zapcore.Level {
switch al {
case DebugLevel:
return zapcore.DebugLevel
case InfoLevel:
return zapcore.InfoLevel
case WarnLevel:
return zapcore.WarnLevel
case ErrorLevel:
return zapcore.ErrorLevel
case DPanicLevel:
return zapcore.DPanicLevel
case PanicLevel:
return zapcore.PanicLevel
case FatalLevel:
return zapcore.FatalLevel
default:
// 默认情况下返回 Info 级别,保证程序健壮性
return zapcore.InfoLevel
}
}
// Scan 实现了 sql.Scanner 接口GORM 在从数据库读取数据时会调用此方法。
func (al *SeverityLevel) Scan(value interface{}) error {
bytes, ok := value.([]byte)
if !ok {
// 尝试处理其他可能的类型,例如字符串
s, ok := value.(string)
if !ok {
return fmt.Errorf("无法将值 %v (类型 %T) 扫描为 SeverityLevel", value, value)
}
*al = SeverityLevel(s)
return nil
}
*al = SeverityLevel(bytes)
return nil
}
// Value 实现了 driver.Valuer 接口GORM 在将数据写入数据库时会调用此方法。
func (al SeverityLevel) Value() (driver.Value, error) {
return string(al), nil
}