diff --git a/internal/app/flow/flow.go b/internal/app/flow/flow.go index 014ba22..0e10f62 100644 --- a/internal/app/flow/flow.go +++ b/internal/app/flow/flow.go @@ -4,6 +4,8 @@ import ( "context" "errors" "fmt" + "sort" + "time" "github.com/neatflowcv/seven-skies/internal/pkg/domain" "github.com/neatflowcv/seven-skies/internal/pkg/repository" @@ -45,3 +47,86 @@ func (f *Flow) CreateWeather(ctx context.Context, weather *Weather) error { return nil } + +func (f *Flow) ListDailyWeathers( + ctx context.Context, + timezone string, + now time.Time, +) ([]*DailyWeather, error) { + location, err := time.LoadLocation(timezone) + if err != nil { + return nil, fmt.Errorf("error in load location: %w", err) + } + + const aWeek = 7 + + localNow := now.In(location) + + from := time.Date(localNow.Year(), localNow.Month(), localNow.Day(), 0, 0, 0, 0, location) + to := from.AddDate(0, 0, aWeek).Add(-time.Nanosecond) + + weathers, err := f.repo.ListWeathers(ctx, from, to) + if err != nil { + return nil, fmt.Errorf("error in list daily weathers: %w", err) + } + + weathersByDate := f.groupByDate(weathers, location) + + var dailyWeathers []*DailyWeather + + for dateKey, weathers := range weathersByDate { + newVar := f.mergeWeathers(dateKey, location, weathers) + dailyWeathers = append(dailyWeathers, newVar) + } + + sort.Slice(dailyWeathers, func(i, j int) bool { + return dailyWeathers[i].Date.Before(dailyWeathers[j].Date) + }) + + return dailyWeathers, nil +} + +func (*Flow) mergeWeathers(dateKey string, location *time.Location, weathers []*domain.Weather) *DailyWeather { + date, _ := time.Parse("2006-01-02", dateKey) + date = time.Date(date.Year(), date.Month(), date.Day(), 0, 0, 0, 0, location) + + high := float64(weathers[0].Temperature().Value) + low := float64(weathers[0].Temperature().Value) + worstCondition := weathers[0].Condition() + + for _, w := range weathers { + temp := float64(w.Temperature().Value) + if temp > high { + high = temp + } + + if temp < low { + low = temp + } + + if w.Condition().IsWorseThan(worstCondition) { + worstCondition = w.Condition() + } + } + + newVar := &DailyWeather{ + Date: date, + High: high, + Low: low, + Condition: string(worstCondition), + } + + return newVar +} + +func (*Flow) groupByDate(weathers []*domain.Weather, location *time.Location) map[string][]*domain.Weather { + weathersByDate := make(map[string][]*domain.Weather) + + for _, weather := range weathers { + localDate := weather.TargetDate().In(location) + dateKey := time.Date(localDate.Year(), localDate.Month(), localDate.Day(), 0, 0, 0, 0, location).Format("2006-01-02") + weathersByDate[dateKey] = append(weathersByDate[dateKey], weather) + } + + return weathersByDate +} diff --git a/internal/app/flow/weather.go b/internal/app/flow/weather.go index 324e494..7d498a3 100644 --- a/internal/app/flow/weather.go +++ b/internal/app/flow/weather.go @@ -9,3 +9,10 @@ type Weather struct { Condition string Temperature float64 // Celsius } + +type DailyWeather struct { + Date time.Time + High float64 // Celsius + Low float64 // Celsius + Condition string +} diff --git a/internal/pkg/repository/gorm/repository.go b/internal/pkg/repository/gorm/repository.go index b3f1181..f0fb0d4 100644 --- a/internal/pkg/repository/gorm/repository.go +++ b/internal/pkg/repository/gorm/repository.go @@ -3,6 +3,7 @@ package gorm import ( "context" "fmt" + "time" "github.com/neatflowcv/seven-skies/internal/pkg/domain" "github.com/neatflowcv/seven-skies/internal/pkg/repository" @@ -42,3 +43,17 @@ func (r *Repository) CreateWeather(ctx context.Context, weather *domain.Weather) return nil } + +func (r *Repository) ListWeathers(ctx context.Context, from, to time.Time) ([]*domain.Weather, error) { + weathers, err := gorm.G[*Weather](r.db).Where("target_date BETWEEN ? AND ?", from, to).Find(ctx) + if err != nil { + return nil, fmt.Errorf("failed to list weathers: %w", err) + } + + var ret []*domain.Weather + for _, weather := range weathers { + ret = append(ret, weather.toDomain()) + } + + return ret, nil +} diff --git a/internal/pkg/repository/gorm/weather.go b/internal/pkg/repository/gorm/weather.go index a27da21..6e84927 100644 --- a/internal/pkg/repository/gorm/weather.go +++ b/internal/pkg/repository/gorm/weather.go @@ -25,3 +25,14 @@ func newModelWeather(weather *domain.Weather) *Weather { Temperature: float64(weather.Temperature().Value), } } + +func (w *Weather) toDomain() *domain.Weather { + return domain.NewWeather( + w.ID, + domain.WeatherSource(w.Source), + w.TargetDate, + w.ForecastDate, + domain.WeatherCondition(w.Condition), + domain.Temperature{Value: domain.Celsius(w.Temperature)}, + ) +} diff --git a/internal/pkg/repository/repository.go b/internal/pkg/repository/repository.go index 266945f..af0cfbb 100644 --- a/internal/pkg/repository/repository.go +++ b/internal/pkg/repository/repository.go @@ -2,10 +2,12 @@ package repository import ( "context" + "time" "github.com/neatflowcv/seven-skies/internal/pkg/domain" ) type Repository interface { CreateWeather(ctx context.Context, weather *domain.Weather) error + ListWeathers(ctx context.Context, from, to time.Time) ([]*domain.Weather, error) }