package repository import ( "users_management/m/model/entity" "github.com/google/uuid" "gorm.io/gorm" ) type NearestDeviceRepo interface { GetNearestDevices(longitude, latitude, radius float64, limit int, province, city, district *string) ([]entity.DeviceWithDistance, error) GetDeviceByIDWithConnections(id uuid.UUID) (entity.Device, error) GetBackbonesByDeviceID(deviceID uuid.UUID) ([]entity.Backbone, error) GetFishbonesByDeviceID(deviceID uuid.UUID) ([]entity.Fishbone, error) GetTowersByDeviceID(deviceID uuid.UUID) ([]entity.Tower, error) CountConnectionsByDeviceID(deviceID uuid.UUID) (backboneCount, fishboneCount, towerCount int, err error) } type nearestDeviceRepo struct { db *gorm.DB } func NewNearestDeviceRepo(db *gorm.DB) NearestDeviceRepo { return &nearestDeviceRepo{ db: db, } } func (r *nearestDeviceRepo) GetNearestDevices(longitude, latitude, radius float64, limit int, province, city, district *string) ([]entity.DeviceWithDistance, error) { var devices []entity.DeviceWithDistance // Build the subquery first subQuery := r.db.Table("devices"). Select(`id, device_code, device_type, longitude, latitude, port_amount, status, region, province, city, district, image_url, created_at, updated_at, (6371 * acos(cos(radians(?)) * cos(radians(latitude)) * cos(radians(longitude) - radians(?)) + sin(radians(?)) * sin(radians(latitude)))) AS distance`, latitude, longitude, latitude) // Apply location filters to subquery if province != nil && *province != "" { subQuery = subQuery.Where("province = ?", *province) } if city != nil && *city != "" { subQuery = subQuery.Where("city = ?", *city) } if district != nil && *district != "" { subQuery = subQuery.Where("district = ?", *district) } // Use the subquery in the main query err := r.db.Table("(?) as devices_with_distance", subQuery). Where("distance <= ?", radius). Order("distance ASC"). Limit(limit). Scan(&devices).Error return devices, err } func (r *nearestDeviceRepo) GetDeviceByIDWithConnections(id uuid.UUID) (entity.Device, error) { var device entity.Device err := r.db.Where("id = ?", id).First(&device).Error return device, err } func (r *nearestDeviceRepo) GetBackbonesByDeviceID(deviceID uuid.UUID) ([]entity.Backbone, error) { var backbones []entity.Backbone err := r.db.Preload("DeviceStart").Preload("DeviceEnd"). Where("dev_start_id = ? OR dev_end_id = ?", deviceID, deviceID). Find(&backbones).Error return backbones, err } func (r *nearestDeviceRepo) GetFishbonesByDeviceID(deviceID uuid.UUID) ([]entity.Fishbone, error) { var fishbones []entity.Fishbone err := r.db.Preload("Backbone").Preload("DeviceStart").Preload("DeviceEnd"). Where("dev_start_id = ? OR dev_end_id = ?", deviceID, deviceID). Find(&fishbones).Error return fishbones, err } func (r *nearestDeviceRepo) GetTowersByDeviceID(deviceID uuid.UUID) ([]entity.Tower, error) { var towers []entity.Tower err := r.db.Preload("Device"). Where("dev_id = ?", deviceID). Find(&towers).Error return towers, err } func (r *nearestDeviceRepo) CountConnectionsByDeviceID(deviceID uuid.UUID) (backboneCount, fishboneCount, towerCount int, err error) { var backboneCountInt64, fishboneCountInt64, towerCountInt64 int64 // Count backbones err = r.db.Model(&entity.Backbone{}). Where("dev_start_id = ? OR dev_end_id = ?", deviceID, deviceID). Count(&backboneCountInt64).Error if err != nil { return 0, 0, 0, err } // Count fishbones err = r.db.Model(&entity.Fishbone{}). Where("dev_start_id = ? OR dev_end_id = ?", deviceID, deviceID). Count(&fishboneCountInt64).Error if err != nil { return 0, 0, 0, err } // Count towers err = r.db.Model(&entity.Tower{}). Where("dev_id = ?", deviceID). Count(&towerCountInt64).Error if err != nil { return 0, 0, 0, err } return int(backboneCountInt64), int(fishboneCountInt64), int(towerCountInt64), nil }