// outlooks_read.go executes outlook-run and outlook queries. // Layer: adapters/outbound/postgres outlook feature. package postgres import ( "context" "database/sql" "errors" "fmt" "gitea.maximumdirect.net/ejr/weatherfeeder/model" ) func (r *Repository) LatestConvectiveOutlookRun(ctx context.Context) (*model.WeatherOutlookRun, error) { if r == nil || r.db == nil { return nil, fmt.Errorf("postgres repository is not configured") } var row outlookRunParentRow err := r.db.QueryRowContext(ctx, queryLatestConvectiveOutlookRun).Scan( &row.EventID, &row.LocationID, &row.LocationName, &row.Latitude, &row.Longitude, &row.AsOf, &row.IssuedAt, ) if errors.Is(err, sql.ErrNoRows) { return nil, nil } if err != nil { return nil, fmt.Errorf("query latest convective outlook run: %w", err) } run := mapOutlookRunParentRow(row) outlooks, err := r.loadOutlooks(ctx, row.EventID) if err != nil { return nil, err } run.Outlooks = outlooks discussions, err := r.loadOutlookDiscussions(ctx, row.EventID) if err != nil { return nil, err } run.Discussions = discussions return &run, nil } func (r *Repository) loadOutlooks(ctx context.Context, eventID string) ([]model.WeatherOutlook, error) { rows, err := r.db.QueryContext(ctx, queryOutlooksForRun, eventID) if err != nil { return nil, fmt.Errorf("query outlooks: %w", err) } defer rows.Close() out := make([]model.WeatherOutlook, 0) for rows.Next() { var row outlookRow if err := rows.Scan( &row.OutlookIndex, &row.OutlookID, &row.Provider, &row.Product, &row.Day, &row.OutlookType, &row.Label, &row.LabelText, &row.SeverityRank, &row.ValidFrom, &row.ValidTo, &row.IssuedAt, &row.ExpiresAt, &row.Forecaster, &row.SourceURL, &row.ImageURL, &row.ContainsLocation, &row.GeometryJSON, ); err != nil { return nil, fmt.Errorf("scan outlook row: %w", err) } outlook, err := mapOutlookRow(row) if err != nil { return nil, fmt.Errorf("map outlook row: %w", err) } out = append(out, outlook) } if err := rows.Err(); err != nil { return nil, fmt.Errorf("iterate outlook rows: %w", err) } return out, nil } func (r *Repository) loadOutlookDiscussions(ctx context.Context, eventID string) ([]model.WeatherOutlookDiscussion, error) { rows, err := r.db.QueryContext(ctx, queryOutlookDiscussionsForRun, eventID) if err != nil { return nil, fmt.Errorf("query outlook discussions: %w", err) } defer rows.Close() out := make([]model.WeatherOutlookDiscussion, 0) for rows.Next() { var row outlookDiscussionRow if err := rows.Scan( &row.DiscussionIndex, &row.Day, &row.Headline, &row.Summary, &row.Discussion, &row.UpdatedAt, ); err != nil { return nil, fmt.Errorf("scan outlook discussion row: %w", err) } out = append(out, mapOutlookDiscussionRow(row)) } if err := rows.Err(); err != nil { return nil, fmt.Errorf("iterate outlook discussion rows: %w", err) } return out, nil }