178 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			178 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package repository
 | 
						||
 | 
						||
import (
 | 
						||
	"fmt"
 | 
						||
	"strconv"
 | 
						||
 | 
						||
	"git.huangwc.com/pig/pig-farm-controller/internal/infra/models"
 | 
						||
	"gorm.io/gorm"
 | 
						||
)
 | 
						||
 | 
						||
// DeviceRepository 定义了与设备模型相关的数据库操作接口
 | 
						||
// 这一层抽象使得上层业务逻辑无需关心底层数据库的具体实现。
 | 
						||
type DeviceRepository interface {
 | 
						||
	// Create 创建一个新设备记录
 | 
						||
	Create(device *models.Device) error
 | 
						||
 | 
						||
	// FindByID 根据主键 ID 查找设备
 | 
						||
	FindByID(id uint) (*models.Device, error)
 | 
						||
 | 
						||
	// FindByIDString 根据字符串形式的主键 ID 查找设备
 | 
						||
	FindByIDString(id string) (*models.Device, error)
 | 
						||
 | 
						||
	// ListAll 获取所有设备的列表
 | 
						||
	ListAll() ([]*models.Device, error)
 | 
						||
 | 
						||
	// ListAllSensors 获取所有传感器类型的设备列表
 | 
						||
	ListAllSensors() ([]*models.Device, error)
 | 
						||
 | 
						||
	// ListByAreaControllerID 根据区域主控 ID 列出所有子设备
 | 
						||
	ListByAreaControllerID(areaControllerID uint) ([]*models.Device, error)
 | 
						||
 | 
						||
	// FindByDeviceTemplateID 根据设备模板ID查找所有使用该模板的设备
 | 
						||
	FindByDeviceTemplateID(deviceTemplateID uint) ([]*models.Device, error)
 | 
						||
 | 
						||
	// Update 更新一个已有的设备信息
 | 
						||
	Update(device *models.Device) error
 | 
						||
 | 
						||
	// Delete 根据主键 ID 删除一个设备
 | 
						||
	Delete(id uint) error
 | 
						||
 | 
						||
	// FindByAreaControllerAndPhysicalAddress 根据区域主控ID和物理地址(总线号、总线地址)查找设备
 | 
						||
	FindByAreaControllerAndPhysicalAddress(areaControllerID uint, busNumber int, busAddress int) (*models.Device, error)
 | 
						||
 | 
						||
	// GetDevicesByIDsTx 在指定事务中根据ID列表获取设备
 | 
						||
	GetDevicesByIDsTx(tx *gorm.DB, ids []uint) ([]models.Device, error)
 | 
						||
 | 
						||
	// IsDeviceInUse 检查设备是否被任何任务使用
 | 
						||
	IsDeviceInUse(deviceID uint) (bool, error)
 | 
						||
}
 | 
						||
 | 
						||
// gormDeviceRepository 是 DeviceRepository 的 GORM 实现
 | 
						||
type gormDeviceRepository struct {
 | 
						||
	db *gorm.DB
 | 
						||
}
 | 
						||
 | 
						||
// NewGormDeviceRepository 创建一个新的 DeviceRepository GORM 实现实例
 | 
						||
func NewGormDeviceRepository(db *gorm.DB) DeviceRepository {
 | 
						||
	return &gormDeviceRepository{db: db}
 | 
						||
}
 | 
						||
 | 
						||
// Create 创建一个新的设备记录
 | 
						||
func (r *gormDeviceRepository) Create(device *models.Device) error {
 | 
						||
	return r.db.Create(device).Error
 | 
						||
}
 | 
						||
 | 
						||
// FindByID 根据 ID 查找设备
 | 
						||
func (r *gormDeviceRepository) FindByID(id uint) (*models.Device, error) {
 | 
						||
	var device models.Device
 | 
						||
	if err := r.db.Preload("AreaController").Preload("DeviceTemplate").First(&device, id).Error; err != nil {
 | 
						||
		return nil, err
 | 
						||
	}
 | 
						||
	return &device, nil
 | 
						||
}
 | 
						||
 | 
						||
// GetDevicesByIDsTx 在指定事务中根据ID列表获取设备
 | 
						||
func (r *gormDeviceRepository) GetDevicesByIDsTx(tx *gorm.DB, ids []uint) ([]models.Device, error) {
 | 
						||
	var devices []models.Device
 | 
						||
	if len(ids) == 0 {
 | 
						||
		return devices, nil
 | 
						||
	}
 | 
						||
	if err := tx.Where("id IN ?", ids).Find(&devices).Error; err != nil {
 | 
						||
		return nil, err
 | 
						||
	}
 | 
						||
	return devices, nil
 | 
						||
}
 | 
						||
 | 
						||
// FindByIDString 根据字符串形式的主键 ID 查找设备
 | 
						||
func (r *gormDeviceRepository) FindByIDString(id string) (*models.Device, error) {
 | 
						||
	// 将字符串ID转换为uint64
 | 
						||
	idInt, err := strconv.ParseUint(id, 10, 64)
 | 
						||
	if err != nil {
 | 
						||
		// 如果转换失败,说明ID格式不正确,返回一个明确的错误
 | 
						||
		return nil, fmt.Errorf("无效的设备ID格式: %w", err)
 | 
						||
	}
 | 
						||
	// 调用已有的 FindByID 方法
 | 
						||
	return r.FindByID(uint(idInt))
 | 
						||
}
 | 
						||
 | 
						||
// ListAll 获取所有设备的列表
 | 
						||
func (r *gormDeviceRepository) ListAll() ([]*models.Device, error) {
 | 
						||
	var devices []*models.Device
 | 
						||
	if err := r.db.Preload("AreaController").Preload("DeviceTemplate").Find(&devices).Error; err != nil {
 | 
						||
		return nil, err
 | 
						||
	}
 | 
						||
	return devices, nil
 | 
						||
}
 | 
						||
 | 
						||
// ListAllSensors 检索归类为传感器的所有设备
 | 
						||
func (r *gormDeviceRepository) ListAllSensors() ([]*models.Device, error) {
 | 
						||
	var sensors []*models.Device
 | 
						||
	err := r.db.Preload("AreaController").Preload("DeviceTemplate").
 | 
						||
		Joins("JOIN device_templates ON device_templates.id = devices.device_template_id").
 | 
						||
		Where("device_templates.category = ?", models.CategorySensor).
 | 
						||
		Find(&sensors).Error
 | 
						||
	if err != nil {
 | 
						||
		return nil, fmt.Errorf("查询所有传感器失败: %w", err)
 | 
						||
	}
 | 
						||
	return sensors, nil
 | 
						||
}
 | 
						||
 | 
						||
// ListByAreaControllerID 根据区域主控 ID 列出所有子设备
 | 
						||
func (r *gormDeviceRepository) ListByAreaControllerID(areaControllerID uint) ([]*models.Device, error) {
 | 
						||
	var devices []*models.Device
 | 
						||
	err := r.db.Preload("AreaController").Preload("DeviceTemplate").Where("area_controller_id = ?", areaControllerID).Find(&devices).Error
 | 
						||
	if err != nil {
 | 
						||
		return nil, err
 | 
						||
	}
 | 
						||
	return devices, nil
 | 
						||
}
 | 
						||
 | 
						||
// FindByDeviceTemplateID 根据设备模板ID查找所有使用该模板的设备
 | 
						||
func (r *gormDeviceRepository) FindByDeviceTemplateID(deviceTemplateID uint) ([]*models.Device, error) {
 | 
						||
	var devices []*models.Device
 | 
						||
	err := r.db.Where("device_template_id = ?", deviceTemplateID).Find(&devices).Error
 | 
						||
	if err != nil {
 | 
						||
		return nil, fmt.Errorf("查询使用设备模板ID %d 的设备失败: %w", deviceTemplateID, err)
 | 
						||
	}
 | 
						||
	return devices, nil
 | 
						||
}
 | 
						||
 | 
						||
// Update 更新一个已有的设备信息
 | 
						||
// GORM 的 Save 方法会自动处理主键存在时更新,不存在时创建的逻辑,但这里我们明确用于更新。
 | 
						||
func (r *gormDeviceRepository) Update(device *models.Device) error {
 | 
						||
	return r.db.Save(device).Error
 | 
						||
}
 | 
						||
 | 
						||
// Delete 根据 ID 删除一个设备
 | 
						||
// GORM 使用软删除,记录不会从数据库中物理移除,而是设置 DeletedAt 字段。
 | 
						||
func (r *gormDeviceRepository) Delete(id uint) error {
 | 
						||
	return r.db.Delete(&models.Device{}, id).Error
 | 
						||
}
 | 
						||
 | 
						||
// FindByAreaControllerAndPhysicalAddress 根据区域主控ID和物理地址(总线号、总线地址)查找设备
 | 
						||
func (r *gormDeviceRepository) FindByAreaControllerAndPhysicalAddress(areaControllerID uint, busNumber int, busAddress int) (*models.Device, error) {
 | 
						||
	var device models.Device
 | 
						||
	err := r.db.Preload("AreaController").Preload("DeviceTemplate").
 | 
						||
		Where("area_controller_id = ?", areaControllerID).
 | 
						||
		Where("properties->>'bus_number' = ?", strconv.Itoa(busNumber)).
 | 
						||
		Where("properties->>'bus_address' = ?", strconv.Itoa(busAddress)).
 | 
						||
		First(&device).Error
 | 
						||
 | 
						||
	if err != nil {
 | 
						||
		return nil, fmt.Errorf("根据区域主控ID %d 和物理地址 (总线号: %d, 总线地址: %d) 查找设备失败: %w", areaControllerID, busNumber, busAddress, err)
 | 
						||
	}
 | 
						||
	return &device, nil
 | 
						||
}
 | 
						||
 | 
						||
// IsDeviceInUse 检查设备是否被任何任务使用
 | 
						||
func (r *gormDeviceRepository) IsDeviceInUse(deviceID uint) (bool, error) {
 | 
						||
	var count int64
 | 
						||
	// 直接对 device_tasks 关联表进行 COUNT 操作,性能最高
 | 
						||
	err := r.db.Model(&models.DeviceTask{}).Where("device_id = ?", deviceID).Count(&count).Error
 | 
						||
	if err != nil {
 | 
						||
		return false, fmt.Errorf("查询设备任务关联失败: %w", err)
 | 
						||
	}
 | 
						||
	return count > 0, nil
 | 
						||
}
 |