package adminstore import "context" // QualifiedMinScore is the quality_score threshold at or above which a product // counts as "qualified" (合格) in admin and public stats. const QualifiedMinScore = 0.6 // AdminStats summarizes the catalog for the admin overview dashboard. type AdminStats struct { Products int `json:"products"` Qualified int `json:"qualified"` MinScore float64 `json:"min_score"` ByStatus map[string]int `json:"by_status"` Brands int `json:"brands"` Categories int `json:"categories"` Pending int `json:"pending_submissions"` AvgQuality float64 `json:"avg_quality"` } // Stats gathers the dashboard counters in a handful of aggregate queries. func (s *Store) Stats(ctx context.Context) (*AdminStats, error) { out := &AdminStats{MinScore: QualifiedMinScore, ByStatus: map[string]int{}} if err := s.pool.QueryRow(ctx, ` SELECT count(*), count(*) FILTER (WHERE quality_score >= $1 AND status = 'active'), COALESCE(avg(quality_score), 0) FROM product`, QualifiedMinScore).Scan(&out.Products, &out.Qualified, &out.AvgQuality); err != nil { return nil, err } rows, err := s.pool.Query(ctx, "SELECT status, count(*) FROM product GROUP BY status") if err != nil { return nil, err } defer rows.Close() for rows.Next() { var st string var n int if err := rows.Scan(&st, &n); err != nil { return nil, err } out.ByStatus[st] = n } if err := rows.Err(); err != nil { return nil, err } if err := s.pool.QueryRow(ctx, "SELECT count(*) FROM brand").Scan(&out.Brands); err != nil { return nil, err } if err := s.pool.QueryRow(ctx, "SELECT count(*) FROM category").Scan(&out.Categories); err != nil { return nil, err } if err := s.pool.QueryRow(ctx, "SELECT count(*) FROM submission WHERE status = 'pending'").Scan(&out.Pending); err != nil { return nil, err } return out, nil }