mirror of
https://github.com/SamyRai/turash.git
synced 2025-12-26 23:01:33 +00:00
140 lines
4.2 KiB
Go
140 lines
4.2 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
|
|
"bugulma/backend/internal/domain"
|
|
|
|
"bugulma/backend/internal/geospatial"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// AddressRepository implements domain.AddressRepository with GORM
|
|
type AddressRepository struct {
|
|
*BaseRepository[domain.Address]
|
|
}
|
|
|
|
// NewAddressRepository creates a new GORM-based address repository
|
|
func NewAddressRepository(db *gorm.DB) domain.AddressRepository {
|
|
return &AddressRepository{
|
|
BaseRepository: NewBaseRepository[domain.Address](db),
|
|
}
|
|
}
|
|
|
|
// GetByID retrieves an address by ID with preloaded associations
|
|
func (r *AddressRepository) GetByID(ctx context.Context, id string) (*domain.Address, error) {
|
|
var address domain.Address
|
|
err := r.DB().WithContext(ctx).
|
|
Preload("Organizations").
|
|
Preload("Sites").
|
|
First(&address, "id = ?", id).Error
|
|
if err != nil {
|
|
return nil, handleError(err)
|
|
}
|
|
return &address, nil
|
|
}
|
|
|
|
// GetAll retrieves all addresses with preloaded associations
|
|
func (r *AddressRepository) GetAll(ctx context.Context) ([]*domain.Address, error) {
|
|
var addresses []*domain.Address
|
|
err := r.DB().WithContext(ctx).
|
|
Preload("Organizations").
|
|
Preload("Sites").
|
|
Find(&addresses).Error
|
|
return addresses, err
|
|
}
|
|
|
|
// GetWithinRadius retrieves addresses within a geographic radius
|
|
func (r *AddressRepository) GetWithinRadius(ctx context.Context, lat, lng, radiusKm float64) ([]*domain.Address, error) {
|
|
dialector := r.DB().Dialector.Name()
|
|
|
|
var addresses []*domain.Address
|
|
|
|
if dialector == "postgres" {
|
|
// Use PostGIS for PostgreSQL
|
|
geo := geospatial.NewGeoHelper(r.DB())
|
|
query := `
|
|
SELECT * FROM addresses
|
|
WHERE latitude IS NOT NULL AND longitude IS NOT NULL
|
|
AND ` + geo.DWithinExpr("ST_SetSRID(ST_MakePoint(longitude, latitude), 4326)") + `
|
|
ORDER BY ST_Distance(
|
|
ST_SetSRID(ST_MakePoint(longitude, latitude), 4326)::geography,
|
|
` + geo.PointExpr() + `::geography
|
|
)
|
|
`
|
|
// Use includeOrderBy=true so PointRadiusArgs returns args in the order
|
|
// [lng, lat, radiusKm, lng, lat] matching DWithin + ORDER BY placeholders
|
|
args := geo.PointRadiusArgs(lng, lat, radiusKm, true)
|
|
result := r.DB().WithContext(ctx).Raw(query, args...).Scan(&addresses)
|
|
if result.Error != nil {
|
|
return nil, result.Error
|
|
}
|
|
} else {
|
|
// Fallback to bounding box for non-PostgreSQL databases
|
|
query := `
|
|
SELECT * FROM addresses
|
|
WHERE latitude IS NOT NULL AND longitude IS NOT NULL
|
|
AND abs(latitude - ?) <= 0.09
|
|
AND abs(longitude - ?) <= 0.15
|
|
`
|
|
result := r.DB().WithContext(ctx).Raw(query, lat, lng).Scan(&addresses)
|
|
if result.Error != nil {
|
|
return nil, result.Error
|
|
}
|
|
}
|
|
|
|
return addresses, nil
|
|
}
|
|
|
|
// GetByOrganizationID retrieves all addresses for a specific organization
|
|
func (r *AddressRepository) GetByOrganizationID(ctx context.Context, orgID string) ([]*domain.Address, error) {
|
|
var addresses []*domain.Address
|
|
|
|
err := r.DB().WithContext(ctx).
|
|
Joins("JOIN organization_addresses ON organization_addresses.address_id = addresses.id").
|
|
Where("organization_addresses.organization_id = ?", orgID).
|
|
Find(&addresses).Error
|
|
|
|
return addresses, err
|
|
}
|
|
|
|
// GetBySiteID retrieves all addresses for a specific site
|
|
func (r *AddressRepository) GetBySiteID(ctx context.Context, siteID string) ([]*domain.Address, error) {
|
|
var addresses []*domain.Address
|
|
|
|
err := r.DB().WithContext(ctx).
|
|
Joins("JOIN site_addresses ON site_addresses.address_id = addresses.id").
|
|
Where("site_addresses.site_id = ?", siteID).
|
|
Find(&addresses).Error
|
|
|
|
return addresses, err
|
|
}
|
|
|
|
// FindOrCreate finds an existing address or creates a new one (deduplication)
|
|
func (r *AddressRepository) FindOrCreate(ctx context.Context, address *domain.Address) (*domain.Address, error) {
|
|
var existing domain.Address
|
|
|
|
// Try to find existing address by formatted address or coordinates
|
|
err := r.DB().WithContext(ctx).
|
|
Where("formatted_ru = ? OR (latitude = ? AND longitude = ?)",
|
|
address.FormattedRu, address.Latitude, address.Longitude).
|
|
First(&existing).Error
|
|
|
|
if err == nil {
|
|
// Found existing address
|
|
return &existing, nil
|
|
}
|
|
|
|
if err == gorm.ErrRecordNotFound {
|
|
// Address doesn't exist, create it
|
|
if err := r.DB().WithContext(ctx).Create(address).Error; err != nil {
|
|
return nil, handleError(err)
|
|
}
|
|
return address, nil
|
|
}
|
|
|
|
// Actual error occurred
|
|
return nil, handleError(err)
|
|
}
|