issue_25 #26
@@ -240,13 +240,13 @@ func (ps *PostgresStorage) creatingIndex() error {
|
||||
ps.logger.Info("成功为 tasks 的 parameters 字段创建 GIN 索引 (或已存在)")
|
||||
|
||||
// 为 devices 表的 properties 字段创建 GIN 索引
|
||||
ps.logger.Info("正在为 devices 表的 properties 字段创建 GIN 索引")
|
||||
ginDevicePropertiesIndexSQL := "CREATE INDEX IF NOT EXISTS idx_devices_properties_gin ON devices USING GIN (properties);"
|
||||
if err := ps.db.Exec(ginDevicePropertiesIndexSQL).Error; err != nil {
|
||||
ps.logger.Errorw("为 devices 的 properties 字段创建 GIN 索引失败", "error", err)
|
||||
return fmt.Errorf("为 devices 的 properties 字段创建 GIN 索引失败: %w", err)
|
||||
}
|
||||
ps.logger.Info("成功为 devices 的 properties 字段创建 GIN 索引 (或已存在)")
|
||||
//ps.logger.Info("正在为 devices 表的 properties 字段创建 GIN 索引")
|
||||
//ginDevicePropertiesIndexSQL := "CREATE INDEX IF NOT EXISTS idx_devices_properties_gin ON devices USING GIN (properties);"
|
||||
//if err := ps.db.Exec(ginDevicePropertiesIndexSQL).Error; err != nil {
|
||||
// ps.logger.Errorw("为 devices 的 properties 字段创建 GIN 索引失败", "error", err)
|
||||
// return fmt.Errorf("为 devices 的 properties 字段创建 GIN 索引失败: %w", err)
|
||||
//}
|
||||
//ps.logger.Info("成功为 devices 的 properties 字段创建 GIN 索引 (或已存在)")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package models
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"gorm.io/datatypes"
|
||||
"gorm.io/gorm"
|
||||
@@ -31,7 +32,6 @@ type LoraProperties struct {
|
||||
type BusProperties struct {
|
||||
BusID int `json:"bus_id"` // 485 总线号
|
||||
BusAddress int `json:"bus_address"` // 485 总线地址
|
||||
RelayChannel int `json:"relay_channel"` // 继电器通道号
|
||||
}
|
||||
|
||||
// AreaController 是一个LoRa转总线(如485)的通信网关
|
||||
@@ -55,6 +55,14 @@ type AreaController struct {
|
||||
Properties datatypes.JSON `json:"properties"`
|
||||
}
|
||||
|
||||
// SelfCheck 对 AreaController 的关键字段进行业务逻辑验证。
|
||||
func (ac *AreaController) SelfCheck() error {
|
||||
if strings.TrimSpace(ac.NetworkID) == "" {
|
||||
return errors.New("区域主控的 NetworkID 不能为空")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TableName 自定义 GORM 使用的数据库表名
|
||||
func (AreaController) TableName() string {
|
||||
return "area_controllers"
|
||||
@@ -68,9 +76,6 @@ type Device struct {
|
||||
// Name 是设备的业务名称,应清晰可读,例如 "1号猪舍温度传感器"
|
||||
Name string `gorm:"not null" json:"name"`
|
||||
|
||||
// Location 描述了设备的物理安装位置,例如 "1号猪舍东侧",方便运维。建立索引以优化按位置查询。
|
||||
Location string `gorm:"index" json:"location"`
|
||||
|
||||
// DeviceTemplateID 是设备模板的外键
|
||||
DeviceTemplateID uint `gorm:"not null;index" json:"device_template_id"`
|
||||
|
||||
@@ -83,11 +88,40 @@ type Device struct {
|
||||
// AreaController 是设备所属的区域主控
|
||||
AreaController AreaController `json:"area_controller"`
|
||||
|
||||
// Location 描述了设备的物理安装位置,例如 "1号猪舍东侧",方便运维。建立索引以优化按位置查询。
|
||||
Location string `gorm:"index" json:"location"`
|
||||
|
||||
// Properties 用于存储特定类型设备的独有属性,采用JSON格式。
|
||||
// 建议在应用层为不同子类型的设备定义专用的属性结构体(如 LoraProperties, BusProperties),以保证数据一致性。
|
||||
Properties datatypes.JSON `json:"properties"`
|
||||
}
|
||||
|
||||
// SelfCheck 对 Device 的关键字段和属性进行业务逻辑验证。
|
||||
func (d *Device) SelfCheck() error {
|
||||
if d.AreaControllerID == 0 {
|
||||
return errors.New("设备必须关联一个区域主控 (AreaControllerID不能为0)")
|
||||
}
|
||||
if d.DeviceTemplateID == 0 {
|
||||
return errors.New("设备必须关联一个设备模板 (DeviceTemplateID不能为0)")
|
||||
}
|
||||
|
||||
// 验证 Properties 是否包含必要的总线地址信息
|
||||
if d.Properties == nil {
|
||||
return errors.New("设备属性 (Properties) 不能为空")
|
||||
}
|
||||
|
||||
var props map[string]interface{}
|
||||
if err := json.Unmarshal(d.Properties, &props); err != nil {
|
||||
return errors.New("无法解析设备属性 (Properties)")
|
||||
}
|
||||
|
||||
if _, ok := props[BusAddress]; !ok {
|
||||
return errors.New("设备属性 (Properties) 中缺少总线地址 (bus_address)")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// TableName 自定义 GORM 使用的数据库表名
|
||||
func (Device) TableName() string {
|
||||
return "devices"
|
||||
|
||||
Reference in New Issue
Block a user