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

215 lines
5.0 KiB
Go
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.

package models
import (
"database/sql/driver"
"errors"
"fmt"
"strconv"
"strings"
"time"
"go.uber.org/zap/zapcore"
"gorm.io/gorm"
)
// Model 用于代替gorm.Model, 使用uint32以节约空间
type Model struct {
ID uint32 `gorm:"primarykey"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
}
// GetAllModels 返回一个包含所有数据库模型实例的切片。
// 这个函数用于在数据库初始化时自动迁移所有的表结构。
func GetAllModels() []interface{} {
return []interface{}{
// Core Models
&User{},
&UserActionLog{},
// Device Models
&Device{},
&AreaController{},
&DeviceTemplate{},
&SensorData{},
&DeviceCommandLog{},
&DeviceTask{},
// Plan & Task Models
&Plan{},
&SubPlan{},
&Task{},
&PlanExecutionLog{},
&TaskExecutionLog{},
&PendingTask{},
&PendingCollection{},
// Farm Asset Models
&PigHouse{},
&Pen{},
// Pig & Batch Models
&PigBatch{},
&PigBatchLog{},
&WeighingBatch{},
&WeighingRecord{},
&PigTransferLog{},
&PigSickLog{},
&PigBreed{},
&PigAgeStage{},
&PigType{},
&PigNutrientRequirement{},
// Pig Buy & Sell
&PigPurchase{},
&PigSale{},
// Feed Models
&RawMaterial{},
&Nutrient{},
&RawMaterialNutrient{},
&RawMaterialStockLog{},
// Medication Models
&Medication{},
&MedicationLog{},
// Alarm Models
&ActiveAlarm{},
&HistoricalAlarm{},
// Notification Models
&Notification{},
}
}
// UintArray 是一个自定义类型,代表 uint32 的切片。
// 它实现了 gorm.Scanner 和 driver.Valuer 接口,
// 以便能与数据库的 bigint[] 类型进行原生映射。
type UintArray []uint32
// 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("无法将值 %v (类型 %T) 扫描为 UintArray")
}
// 去掉花括号
srcStr = strings.Trim(srcStr, "{}")
if srcStr == "" {
*a = []uint32{}
return nil
}
// 按逗号分割
parts := strings.Split(srcStr, ",")
arr := make([]uint32, 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] = uint32(val)
}
*a = arr
return nil
}
// 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
}