package diyanetcitydb import ( "context" "database/sql" "errors" "fmt" "strings" "github.com/doug-martin/goqu/v9" "prayertimes/pkg/prayer" ) var ErrLocationNotFound = errors.New("location not found") type Provider struct { db *goqu.Database } func New(conn *sql.DB) Provider { return Provider{db: goqu.New("sqlite3", conn)} } type locationRow struct { ID int `db:"id"` Country string `db:"country"` City string `db:"city"` Region string `db:"region"` Latitude float64 `db:"latitude"` Longitude float64 `db:"longitude"` Timezone string `db:"timezone"` } func (p Provider) SearchLocations(ctx context.Context, query string) ([]prayer.LegacyLocation, error) { query = strings.TrimSpace(query) if query == "" { return nil, nil } pattern := "%" + query + "%" q := p.db. From("diyanet_cities"). Select( goqu.I("id"), goqu.I("country"), goqu.I("city"), goqu.COALESCE(goqu.I("region"), "").As("region"), goqu.I("latitude"), goqu.I("longitude"), goqu.COALESCE(goqu.I("timezone"), "").As("timezone"), ). Where( goqu.Or( goqu.L("country LIKE ? COLLATE NOCASE", pattern), goqu.L("city LIKE ? COLLATE NOCASE", pattern), goqu.L("COALESCE(region, '') LIKE ? COLLATE NOCASE", pattern), ), ). Order( goqu.I("country").Asc(), goqu.I("city").Asc(), goqu.I("region").Asc(), goqu.I("id").Asc(), ). Limit(100) rows := make([]locationRow, 0) if err := q.ScanStructsContext(ctx, &rows); err != nil { return nil, fmt.Errorf("failed to query diyanet locations: %w", err) } locations := make([]prayer.LegacyLocation, 0, len(rows)) for _, row := range rows { locations = append(locations, prayer.LegacyLocation{ ID: row.ID, Country: row.Country, City: row.City, Region: row.Region, Latitude: row.Latitude, Longitude: row.Longitude, Timezone: row.Timezone, }) } return locations, nil } func (p Provider) GetLocationByID(ctx context.Context, id int) (prayer.LegacyLocation, error) { q := p.db. From("diyanet_cities"). Select( goqu.I("id"), goqu.I("country"), goqu.I("city"), goqu.COALESCE(goqu.I("region"), "").As("region"), goqu.I("latitude"), goqu.I("longitude"), goqu.COALESCE(goqu.I("timezone"), "").As("timezone"), ). Where(goqu.I("id").Eq(id)). Limit(1) var rows []locationRow if err := q.ScanStructsContext(ctx, &rows); err != nil { return prayer.LegacyLocation{}, fmt.Errorf("failed to query location by id: %w", err) } if len(rows) == 0 { return prayer.LegacyLocation{}, ErrLocationNotFound } row := rows[0] location := prayer.LegacyLocation{ ID: row.ID, Country: row.Country, City: row.City, Region: row.Region, Latitude: row.Latitude, Longitude: row.Longitude, Timezone: row.Timezone, } return location, nil }