diff options
Diffstat (limited to 'internal/store/estimate_inference.go')
| -rw-r--r-- | internal/store/estimate_inference.go | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/internal/store/estimate_inference.go b/internal/store/estimate_inference.go new file mode 100644 index 0000000..d0a0034 --- /dev/null +++ b/internal/store/estimate_inference.go @@ -0,0 +1,70 @@ +package store + +import "encoding/json" + +// AverageEstimateForProject returns the rounded average estimated_minutes +// across all user-estimated (estimated_minutes > 0) tasks under projectID. +// ok is false when no such task exists -- there's no signal to infer from. +func (s *Store) AverageEstimateForProject(projectID string) (int, bool, error) { + var sum, count int + rows, err := s.db.Query(`SELECT estimated_minutes FROM native_tasks WHERE project_id = ? AND estimated_minutes > 0`, projectID) + if err != nil { + return 0, false, err + } + defer func() { _ = rows.Close() }() + for rows.Next() { + var minutes int + if err := rows.Scan(&minutes); err != nil { + return 0, false, err + } + sum += minutes + count++ + } + if err := rows.Err(); err != nil { + return 0, false, err + } + if count == 0 { + return 0, false, nil + } + return sum / count, true, nil +} + +// AverageEstimateForLabel returns the rounded average estimated_minutes +// across all user-estimated tasks carrying the given label. Labels are +// stored as a JSON array column, not a joinable table, so this scans every +// estimated task and filters in Go rather than risking a SQL substring +// false-positive (e.g. LIKE '%"run"%' matching a task labeled "running"). +func (s *Store) AverageEstimateForLabel(label string) (int, bool, error) { + rows, err := s.db.Query(`SELECT labels, estimated_minutes FROM native_tasks WHERE estimated_minutes > 0`) + if err != nil { + return 0, false, err + } + defer func() { _ = rows.Close() }() + + var sum, count int + for rows.Next() { + var labelsJSON string + var minutes int + if err := rows.Scan(&labelsJSON, &minutes); err != nil { + return 0, false, err + } + var labels []string + if err := json.Unmarshal([]byte(labelsJSON), &labels); err != nil { + continue + } + for _, l := range labels { + if l == label { + sum += minutes + count++ + break + } + } + } + if err := rows.Err(); err != nil { + return 0, false, err + } + if count == 0 { + return 0, false, nil + } + return sum / count, true, nil +} |
