package sql import ( "context" "math" "tercul/internal/domain" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/trace" "gorm.io/gorm" ) type placeRepository struct { domain.BaseRepository[domain.Place] db *gorm.DB tracer trace.Tracer } // NewPlaceRepository creates a new PlaceRepository. func NewPlaceRepository(db *gorm.DB) domain.PlaceRepository { return &placeRepository{ BaseRepository: NewBaseRepositoryImpl[domain.Place](db), db: db, tracer: otel.Tracer("place.repository"), } } // ListByCountryID finds places by country ID func (r *placeRepository) ListByCountryID(ctx context.Context, countryID uint) ([]domain.Place, error) { ctx, span := r.tracer.Start(ctx, "ListByCountryID") defer span.End() var places []domain.Place if err := r.db.WithContext(ctx).Where("country_id = ?", countryID).Find(&places).Error; err != nil { return nil, err } return places, nil } // ListByCityID finds places by city ID func (r *placeRepository) ListByCityID(ctx context.Context, cityID uint) ([]domain.Place, error) { ctx, span := r.tracer.Start(ctx, "ListByCityID") defer span.End() var places []domain.Place if err := r.db.WithContext(ctx).Where("city_id = ?", cityID).Find(&places).Error; err != nil { return nil, err } return places, nil } // FindNearby finds places within a certain radius (in kilometers) of a point func (r *placeRepository) FindNearby(ctx context.Context, latitude, longitude float64, radiusKm float64) ([]domain.Place, error) { ctx, span := r.tracer.Start(ctx, "FindNearby") defer span.End() // This is a simplified implementation that would need to be replaced with // a proper geospatial query based on the database being used var places []domain.Place // For PostgreSQL with PostGIS, you might use something like: // query := `SELECT * FROM places // WHERE ST_DWithin( // ST_MakePoint(longitude, latitude)::geography, // ST_MakePoint(?, ?)::geography, // ? * 1000)` // if err := r.db.WithContext(ctx).Raw(query, longitude, latitude, radiusKm).Scan(&places).Error; err != nil { // return nil, err // } // For a simple approximation without geospatial extensions: // This is not accurate for large distances or near the poles latDelta := radiusKm / 111.0 // Approx. 111km per degree of latitude lonDelta := radiusKm / (111.0 * math.Cos(latitude*(math.Pi/180.0))) // Adjust for longitude if err := r.db.WithContext(ctx).Where("latitude BETWEEN ? AND ? AND longitude BETWEEN ? AND ?", latitude-latDelta, latitude+latDelta, longitude-lonDelta, longitude+lonDelta). Find(&places).Error; err != nil { return nil, err } return places, nil }