diff --git a/store/stats.go b/store/stats.go new file mode 100644 index 0000000..57e58a1 --- /dev/null +++ b/store/stats.go @@ -0,0 +1,48 @@ +package store + +import ( + "encoding/json" + "time" + + bolt "go.etcd.io/bbolt" +) + +// GetTodayRunCount returns the number of daily challenge runs for today. +func (d *DB) GetTodayRunCount() (int, error) { + today := time.Now().Format("2006-01-02") + count := 0 + err := d.db.View(func(tx *bolt.Tx) error { + b := tx.Bucket(bucketDailyRuns) + c := b.Cursor() + prefix := []byte(today + ":") + for k, _ := c.Seek(prefix); k != nil && len(k) >= len(prefix) && string(k[:len(prefix)]) == string(prefix); k, _ = c.Next() { + count++ + } + return nil + }) + return count, err +} + +// GetTodayAvgFloor returns the average floor reached in today's daily runs. +func (d *DB) GetTodayAvgFloor() (float64, error) { + today := time.Now().Format("2006-01-02") + total := 0 + count := 0 + err := d.db.View(func(tx *bolt.Tx) error { + b := tx.Bucket(bucketDailyRuns) + c := b.Cursor() + prefix := []byte(today + ":") + for k, v := c.Seek(prefix); k != nil && len(k) >= len(prefix) && string(k[:len(prefix)]) == string(prefix); k, v = c.Next() { + var r DailyRecord + if json.Unmarshal(v, &r) == nil { + total += r.FloorReached + count++ + } + } + return nil + }) + if count == 0 { + return 0, err + } + return float64(total) / float64(count), err +} diff --git a/store/stats_test.go b/store/stats_test.go new file mode 100644 index 0000000..c90109a --- /dev/null +++ b/store/stats_test.go @@ -0,0 +1,69 @@ +package store + +import ( + "path/filepath" + "testing" + "time" +) + +func TestGetTodayRunCount(t *testing.T) { + tmpDir := t.TempDir() + db, err := Open(filepath.Join(tmpDir, "test.db")) + if err != nil { + t.Fatalf("open: %v", err) + } + defer db.Close() + + today := time.Now().Format("2006-01-02") + + count, err := db.GetTodayRunCount() + if err != nil { + t.Fatalf("GetTodayRunCount: %v", err) + } + if count != 0 { + t.Fatalf("expected 0, got %d", count) + } + + db.SaveDaily(DailyRecord{Date: today, Player: "fp1", PlayerName: "A", FloorReached: 10, GoldEarned: 100}) + db.SaveDaily(DailyRecord{Date: today, Player: "fp2", PlayerName: "B", FloorReached: 15, GoldEarned: 200}) + yesterday := time.Now().AddDate(0, 0, -1).Format("2006-01-02") + db.SaveDaily(DailyRecord{Date: yesterday, Player: "fp3", PlayerName: "C", FloorReached: 5, GoldEarned: 50}) + + count, err = db.GetTodayRunCount() + if err != nil { + t.Fatalf("GetTodayRunCount: %v", err) + } + if count != 2 { + t.Fatalf("expected 2, got %d", count) + } +} + +func TestGetTodayAvgFloor(t *testing.T) { + tmpDir := t.TempDir() + db, err := Open(filepath.Join(tmpDir, "test.db")) + if err != nil { + t.Fatalf("open: %v", err) + } + defer db.Close() + + today := time.Now().Format("2006-01-02") + + avg, err := db.GetTodayAvgFloor() + if err != nil { + t.Fatalf("GetTodayAvgFloor: %v", err) + } + if avg != 0 { + t.Fatalf("expected 0, got %f", avg) + } + + db.SaveDaily(DailyRecord{Date: today, Player: "fp1", PlayerName: "A", FloorReached: 10, GoldEarned: 100}) + db.SaveDaily(DailyRecord{Date: today, Player: "fp2", PlayerName: "B", FloorReached: 20, GoldEarned: 200}) + + avg, err = db.GetTodayAvgFloor() + if err != nil { + t.Fatalf("GetTodayAvgFloor: %v", err) + } + if avg != 15.0 { + t.Fatalf("expected 15.0, got %f", avg) + } +}