package wages import ( "context" "errors" "time" "github.com/missionworkforce/missionmatch/internal/platform/database/dbgen" "github.com/missionworkforce/missionmatch/internal/platform/tenant" ) // ErrNoDatabase is returned when no pool is configured. var ErrNoDatabase = errors.New("wages: no database configured") // Service reads the cached BLS wage baseline. type Service struct{ db *tenant.DB } // NewService builds the service. db may be nil (then calls return ErrNoDatabase). func NewService(db *tenant.DB) *Service { return &Service{db: db} } // Baseline returns the wage baseline grouped by occupation, each with its Hawaii and New Mexico // annual mean and median wages. func (s *Service) Baseline(ctx context.Context) ([]WageBaseline, error) { if s.db == nil || s.db.Pool == nil { return nil, ErrNoDatabase } rows, err := dbgen.New(s.db.Pool).ListBlsWages(ctx) if err != nil { return nil, err } order := []string{} // preserve first seen occupation order byOcc := map[string]*WageBaseline{} // occupation_code to baseline areaIdx := map[string]map[string]int{} // occupation_code to area to index in Areas syncedAt := time.Time{} for _, r := range rows { wb, ok := byOcc[r.OccupationCode] if !ok { wb = &WageBaseline{ OccupationCode: r.OccupationCode, OccupationTitle: r.OccupationTitle, Role: r.Role, Year: r.PeriodYear, Source: "BLS OEWS", } byOcc[r.OccupationCode] = wb areaIdx[r.OccupationCode] = map[string]int{} order = append(order, r.OccupationCode) } ai, ok := areaIdx[r.OccupationCode][r.Area] if !ok { wb.Areas = append(wb.Areas, AreaWage{Area: r.Area, AreaName: r.AreaName}) ai = len(wb.Areas) - 1 areaIdx[r.OccupationCode][r.Area] = ai } val := "" if r.Value != nil { val = r.Value.StringFixed(0) } switch r.Metric { case "annual_mean": wb.Areas[ai].AnnualMean = val case "annual_median": wb.Areas[ai].AnnualMedian = val } if r.SyncedAt.After(syncedAt) { syncedAt = r.SyncedAt } } out := make([]WageBaseline, 0, len(order)) for _, code := range order { wb := byOcc[code] if !syncedAt.IsZero() { wb.SyncedAt = syncedAt.Format(time.RFC3339) } out = append(out, *wb) } return out, nil }