Add convective outlook application filtering
This commit is contained in:
@@ -4,6 +4,8 @@ package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gitea.maximumdirect.net/ejr/weatherfeeder/model"
|
||||
)
|
||||
@@ -17,9 +19,18 @@ type Repository interface {
|
||||
LatestWeatherStoryRun(ctx context.Context) (*model.WeatherStoryRun, error)
|
||||
LatestWeatherStory(ctx context.Context) (*model.WeatherStory, error)
|
||||
LatestAlertRun(ctx context.Context) (*model.WeatherAlertRun, error)
|
||||
LatestConvectiveOutlookRun(ctx context.Context) (*model.WeatherOutlookRun, error)
|
||||
CurrentConditions(ctx context.Context, observationWindowMinutes int) (*CurrentConditions, error)
|
||||
}
|
||||
|
||||
// OutlookFilter selects outlook entries from the latest convective outlook run.
|
||||
type OutlookFilter struct {
|
||||
Day *int
|
||||
OutlookType string
|
||||
ContainsLocation *bool
|
||||
ActiveAt *time.Time
|
||||
}
|
||||
|
||||
// Service provides weather read use-cases.
|
||||
type Service struct {
|
||||
repo Repository
|
||||
@@ -57,6 +68,93 @@ func (s *Service) LatestAlertRun(ctx context.Context) (*model.WeatherAlertRun, e
|
||||
return s.repo.LatestAlertRun(ctx)
|
||||
}
|
||||
|
||||
func (s *Service) LatestConvectiveOutlook(ctx context.Context, filter OutlookFilter) (*model.WeatherOutlookRun, error) {
|
||||
run, err := s.repo.LatestConvectiveOutlookRun(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if run == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
out := cloneOutlookRun(run)
|
||||
outlooks := out.Outlooks[:0]
|
||||
for _, outlook := range out.Outlooks {
|
||||
if matchesOutlookFilter(outlook, filter) {
|
||||
outlooks = append(outlooks, outlook)
|
||||
}
|
||||
}
|
||||
out.Outlooks = outlooks
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (s *Service) CurrentConditions(ctx context.Context) (*CurrentConditions, error) {
|
||||
return s.repo.CurrentConditions(ctx, ObservationWindowMinutesDefault)
|
||||
}
|
||||
|
||||
func matchesOutlookFilter(outlook model.WeatherOutlook, filter OutlookFilter) bool {
|
||||
if filter.Day != nil && outlook.Day != *filter.Day {
|
||||
return false
|
||||
}
|
||||
if filter.OutlookType != "" && outlook.OutlookType != normalizeOutlookType(filter.OutlookType) {
|
||||
return false
|
||||
}
|
||||
if filter.ContainsLocation != nil && outlook.ContainsLocation != *filter.ContainsLocation {
|
||||
return false
|
||||
}
|
||||
if filter.ActiveAt != nil && (filter.ActiveAt.Before(outlook.ValidFrom) || !filter.ActiveAt.Before(outlook.ValidTo)) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func normalizeOutlookType(value string) string {
|
||||
return strings.ToLower(strings.TrimSpace(value))
|
||||
}
|
||||
|
||||
func cloneOutlookRun(run *model.WeatherOutlookRun) *model.WeatherOutlookRun {
|
||||
out := *run
|
||||
out.Latitude = copyFloat64(run.Latitude)
|
||||
out.Longitude = copyFloat64(run.Longitude)
|
||||
out.IssuedAt = copyTime(run.IssuedAt)
|
||||
if run.Outlooks != nil {
|
||||
out.Outlooks = make([]model.WeatherOutlook, len(run.Outlooks))
|
||||
for i := range run.Outlooks {
|
||||
out.Outlooks[i] = cloneOutlook(run.Outlooks[i])
|
||||
}
|
||||
}
|
||||
return &out
|
||||
}
|
||||
|
||||
func cloneOutlook(outlook model.WeatherOutlook) model.WeatherOutlook {
|
||||
out := outlook
|
||||
out.SeverityRank = copyInt(outlook.SeverityRank)
|
||||
if outlook.Geometry != nil {
|
||||
out.Geometry = append([]byte(nil), outlook.Geometry...)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func copyFloat64(value *float64) *float64 {
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
out := *value
|
||||
return &out
|
||||
}
|
||||
|
||||
func copyInt(value *int) *int {
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
out := *value
|
||||
return &out
|
||||
}
|
||||
|
||||
func copyTime(value *time.Time) *time.Time {
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
out := *value
|
||||
return &out
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user