// observations_read.go executes observation and present-weather queries. // Layer: adapters/outbound/postgres observations feature. package postgres import ( "context" "database/sql" "errors" "fmt" "gitea.maximumdirect.net/ejr/weatherfeeder/model" ) func (r *Repository) LatestObservation(ctx context.Context) (*model.WeatherObservation, error) { if r == nil || r.db == nil { return nil, fmt.Errorf("postgres repository is not configured") } var row observationParentRow err := r.db.QueryRowContext(ctx, queryLatestObservation).Scan( &row.EventID, &row.StationID, &row.StationName, &row.ObservedAt, &row.ConditionCode, &row.IsDay, &row.TextDescription, &row.TemperatureC, &row.DewpointC, &row.WindDirectionDegrees, &row.WindSpeedKmh, &row.WindGustKmh, &row.BarometricPressurePa, &row.VisibilityMeters, &row.RelativeHumidityPercent, &row.ApparentTemperatureC, ) if errors.Is(err, sql.ErrNoRows) { return nil, nil } if err != nil { return nil, fmt.Errorf("query latest observation: %w", err) } obs := mapObservationParentRow(row) presentWeather, err := r.loadObservationPresentWeather(ctx, row.EventID) if err != nil { return nil, err } obs.PresentWeather = presentWeather return &obs, nil } func (r *Repository) loadObservationPresentWeather(ctx context.Context, eventID string) ([]model.PresentWeather, error) { rows, err := r.db.QueryContext(ctx, queryObservationPresentWeather, eventID) if err != nil { return nil, fmt.Errorf("query observation present weather: %w", err) } defer rows.Close() out := make([]model.PresentWeather, 0) for rows.Next() { var row observationPresentWeatherRow if err := rows.Scan(&row.WeatherIndex, &row.RawText); err != nil { return nil, fmt.Errorf("scan observation present weather row: %w", err) } pw, err := mapObservationPresentWeatherRow(row) if err != nil { return nil, fmt.Errorf("decode observation present weather row (index=%d): %w", row.WeatherIndex, err) } out = append(out, pw) } if err := rows.Err(); err != nil { return nil, fmt.Errorf("iterate observation present weather rows: %w", err) } return out, nil }