From ef27dce5e3572738632c2a03d2cc3e9eec001d9f Mon Sep 17 00:00:00 2001 From: Gabe Farrell Date: Mon, 29 Dec 2025 16:02:55 -0500 Subject: [PATCH] chore: update counts to allow unix timeframe --- engine/handlers/stats.go | 10 +++--- engine/import_test.go | 6 ++-- internal/db/db.go | 10 +++--- internal/db/period.go | 6 ++++ internal/db/psql/counts.go | 60 ++++++++++++++++++++++++--------- internal/db/psql/counts_test.go | 10 +++--- 6 files changed, 69 insertions(+), 33 deletions(-) diff --git a/engine/handlers/stats.go b/engine/handlers/stats.go index 7dbfc29..0bc7c8a 100644 --- a/engine/handlers/stats.go +++ b/engine/handlers/stats.go @@ -42,35 +42,35 @@ func StatsHandler(store db.DB) http.HandlerFunc { l.Debug().Msgf("StatsHandler: Fetching statistics for period '%s'", period) - listens, err := store.CountListens(r.Context(), period) + listens, err := store.CountListens(r.Context(), db.Timeframe{Period: period}) if err != nil { l.Err(err).Msg("StatsHandler: Failed to fetch listen count") utils.WriteError(w, "failed to get listens: "+err.Error(), http.StatusInternalServerError) return } - tracks, err := store.CountTracks(r.Context(), period) + tracks, err := store.CountTracks(r.Context(), db.Timeframe{Period: period}) if err != nil { l.Err(err).Msg("StatsHandler: Failed to fetch track count") utils.WriteError(w, "failed to get tracks: "+err.Error(), http.StatusInternalServerError) return } - albums, err := store.CountAlbums(r.Context(), period) + albums, err := store.CountAlbums(r.Context(), db.Timeframe{Period: period}) if err != nil { l.Err(err).Msg("StatsHandler: Failed to fetch album count") utils.WriteError(w, "failed to get albums: "+err.Error(), http.StatusInternalServerError) return } - artists, err := store.CountArtists(r.Context(), period) + artists, err := store.CountArtists(r.Context(), db.Timeframe{Period: period}) if err != nil { l.Err(err).Msg("StatsHandler: Failed to fetch artist count") utils.WriteError(w, "failed to get artists: "+err.Error(), http.StatusInternalServerError) return } - timeListenedS, err := store.CountTimeListened(r.Context(), period) + timeListenedS, err := store.CountTimeListened(r.Context(), db.Timeframe{Period: period}) if err != nil { l.Err(err).Msg("StatsHandler: Failed to fetch time listened") utils.WriteError(w, "failed to get time listened: "+err.Error(), http.StatusInternalServerError) diff --git a/engine/import_test.go b/engine/import_test.go index 1d7bf60..6a84d7b 100644 --- a/engine/import_test.go +++ b/engine/import_test.go @@ -326,13 +326,13 @@ func TestImportKoito(t *testing.T) { _, err = store.GetTrack(ctx, db.GetTrackOpts{Title: "GIRI GIRI", ArtistIDs: []int32{artist.ID}}) require.NoError(t, err) - count, err := store.CountTracks(ctx, db.PeriodAllTime) + count, err := store.CountTracks(ctx, db.Timeframe{Period: db.PeriodAllTime}) require.NoError(t, err) assert.EqualValues(t, 4, count) - count, err = store.CountAlbums(ctx, db.PeriodAllTime) + count, err = store.CountAlbums(ctx, db.Timeframe{Period: db.PeriodAllTime}) require.NoError(t, err) assert.EqualValues(t, 3, count) - count, err = store.CountArtists(ctx, db.PeriodAllTime) + count, err = store.CountArtists(ctx, db.Timeframe{Period: db.PeriodAllTime}) require.NoError(t, err) assert.EqualValues(t, 6, count) diff --git a/internal/db/db.go b/internal/db/db.go index f87a3b2..71e64f9 100644 --- a/internal/db/db.go +++ b/internal/db/db.go @@ -63,11 +63,11 @@ type DB interface { DeleteSession(ctx context.Context, sessionId uuid.UUID) error DeleteApiKey(ctx context.Context, id int32) error // Count - CountListens(ctx context.Context, period Period) (int64, error) - CountTracks(ctx context.Context, period Period) (int64, error) - CountAlbums(ctx context.Context, period Period) (int64, error) - CountArtists(ctx context.Context, period Period) (int64, error) - CountTimeListened(ctx context.Context, period Period) (int64, error) + CountListens(ctx context.Context, timeframe Timeframe) (int64, error) + CountTracks(ctx context.Context, timeframe Timeframe) (int64, error) + CountAlbums(ctx context.Context, timeframe Timeframe) (int64, error) + CountArtists(ctx context.Context, timeframe Timeframe) (int64, error) + CountTimeListened(ctx context.Context, timeframe Timeframe) (int64, error) CountTimeListenedToItem(ctx context.Context, opts TimeListenedOpts) (int64, error) CountUsers(ctx context.Context) (int64, error) // Search diff --git a/internal/db/period.go b/internal/db/period.go index 5711d05..e7609fc 100644 --- a/internal/db/period.go +++ b/internal/db/period.go @@ -6,6 +6,12 @@ import ( // should this be in db package ??? +type Timeframe struct { + Period Period + T1u int64 + T2u int64 +} + type Period string const ( diff --git a/internal/db/psql/counts.go b/internal/db/psql/counts.go index cecdd8d..821e05b 100644 --- a/internal/db/psql/counts.go +++ b/internal/db/psql/counts.go @@ -10,9 +10,15 @@ import ( "github.com/gabehf/koito/internal/repository" ) -func (p *Psql) CountListens(ctx context.Context, period db.Period) (int64, error) { - t2 := time.Now() - t1 := db.StartTimeFromPeriod(period) +func (p *Psql) CountListens(ctx context.Context, timeframe db.Timeframe) (int64, error) { + var t1, t2 time.Time + if timeframe.T1u == 0 && timeframe.T2u == 0 { + t2 = time.Now() + t1 = db.StartTimeFromPeriod(timeframe.Period) + } else { + t1 = time.Unix(timeframe.T1u, 0) + t2 = time.Unix(timeframe.T2u, 0) + } count, err := p.q.CountListens(ctx, repository.CountListensParams{ ListenedAt: t1, ListenedAt_2: t2, @@ -23,9 +29,15 @@ func (p *Psql) CountListens(ctx context.Context, period db.Period) (int64, error return count, nil } -func (p *Psql) CountTracks(ctx context.Context, period db.Period) (int64, error) { - t2 := time.Now() - t1 := db.StartTimeFromPeriod(period) +func (p *Psql) CountTracks(ctx context.Context, timeframe db.Timeframe) (int64, error) { + var t1, t2 time.Time + if timeframe.T1u == 0 && timeframe.T2u == 0 { + t2 = time.Now() + t1 = db.StartTimeFromPeriod(timeframe.Period) + } else { + t1 = time.Unix(timeframe.T1u, 0) + t2 = time.Unix(timeframe.T2u, 0) + } count, err := p.q.CountTopTracks(ctx, repository.CountTopTracksParams{ ListenedAt: t1, ListenedAt_2: t2, @@ -36,9 +48,15 @@ func (p *Psql) CountTracks(ctx context.Context, period db.Period) (int64, error) return count, nil } -func (p *Psql) CountAlbums(ctx context.Context, period db.Period) (int64, error) { - t2 := time.Now() - t1 := db.StartTimeFromPeriod(period) +func (p *Psql) CountAlbums(ctx context.Context, timeframe db.Timeframe) (int64, error) { + var t1, t2 time.Time + if timeframe.T1u == 0 && timeframe.T2u == 0 { + t2 = time.Now() + t1 = db.StartTimeFromPeriod(timeframe.Period) + } else { + t1 = time.Unix(timeframe.T1u, 0) + t2 = time.Unix(timeframe.T2u, 0) + } count, err := p.q.CountTopReleases(ctx, repository.CountTopReleasesParams{ ListenedAt: t1, ListenedAt_2: t2, @@ -49,9 +67,15 @@ func (p *Psql) CountAlbums(ctx context.Context, period db.Period) (int64, error) return count, nil } -func (p *Psql) CountArtists(ctx context.Context, period db.Period) (int64, error) { - t2 := time.Now() - t1 := db.StartTimeFromPeriod(period) +func (p *Psql) CountArtists(ctx context.Context, timeframe db.Timeframe) (int64, error) { + var t1, t2 time.Time + if timeframe.T1u == 0 && timeframe.T2u == 0 { + t2 = time.Now() + t1 = db.StartTimeFromPeriod(timeframe.Period) + } else { + t1 = time.Unix(timeframe.T1u, 0) + t2 = time.Unix(timeframe.T2u, 0) + } count, err := p.q.CountTopArtists(ctx, repository.CountTopArtistsParams{ ListenedAt: t1, ListenedAt_2: t2, @@ -62,9 +86,15 @@ func (p *Psql) CountArtists(ctx context.Context, period db.Period) (int64, error return count, nil } -func (p *Psql) CountTimeListened(ctx context.Context, period db.Period) (int64, error) { - t2 := time.Now() - t1 := db.StartTimeFromPeriod(period) +func (p *Psql) CountTimeListened(ctx context.Context, timeframe db.Timeframe) (int64, error) { + var t1, t2 time.Time + if timeframe.T1u == 0 && timeframe.T2u == 0 { + t2 = time.Now() + t1 = db.StartTimeFromPeriod(timeframe.Period) + } else { + t1 = time.Unix(timeframe.T1u, 0) + t2 = time.Unix(timeframe.T2u, 0) + } count, err := p.q.CountTimeListened(ctx, repository.CountTimeListenedParams{ ListenedAt: t1, ListenedAt_2: t2, diff --git a/internal/db/psql/counts_test.go b/internal/db/psql/counts_test.go index 414ebbc..8686571 100644 --- a/internal/db/psql/counts_test.go +++ b/internal/db/psql/counts_test.go @@ -15,7 +15,7 @@ func TestCountListens(t *testing.T) { // Test CountListens period := db.PeriodWeek - count, err := store.CountListens(ctx, period) + count, err := store.CountListens(ctx, db.Timeframe{Period: period}) require.NoError(t, err) assert.Equal(t, int64(1), count, "expected listens count to match inserted data") @@ -28,7 +28,7 @@ func TestCountTracks(t *testing.T) { // Test CountTracks period := db.PeriodMonth - count, err := store.CountTracks(ctx, period) + count, err := store.CountTracks(ctx, db.Timeframe{Period: period}) require.NoError(t, err) assert.Equal(t, int64(2), count, "expected tracks count to match inserted data") @@ -41,7 +41,7 @@ func TestCountAlbums(t *testing.T) { // Test CountAlbums period := db.PeriodYear - count, err := store.CountAlbums(ctx, period) + count, err := store.CountAlbums(ctx, db.Timeframe{Period: period}) require.NoError(t, err) assert.Equal(t, int64(3), count, "expected albums count to match inserted data") @@ -54,7 +54,7 @@ func TestCountArtists(t *testing.T) { // Test CountArtists period := db.PeriodAllTime - count, err := store.CountArtists(ctx, period) + count, err := store.CountArtists(ctx, db.Timeframe{Period: period}) require.NoError(t, err) assert.Equal(t, int64(4), count, "expected artists count to match inserted data") @@ -67,7 +67,7 @@ func TestCountTimeListened(t *testing.T) { // Test CountTimeListened period := db.PeriodMonth - count, err := store.CountTimeListened(ctx, period) + count, err := store.CountTimeListened(ctx, db.Timeframe{Period: period}) require.NoError(t, err) // 3 listens in past month, each 100 seconds assert.Equal(t, int64(300), count, "expected total time listened to match inserted data")