From d4b70ff9fed325d4281b1a31844f031270384267 Mon Sep 17 00:00:00 2001 From: Raymond Jacobson Date: Wed, 18 Feb 2026 10:03:45 -0800 Subject: [PATCH 1/3] Add trending winners --- api/server.go | 1 + api/server_test.go | 1 + api/swagger/swagger-v1.yaml | 31 ++++++++ api/testdata/trending_results_fixtures.go | 8 +++ api/v1_tracks_trending_winners.go | 87 +++++++++++++++++++++++ api/v1_tracks_trending_winners_test.go | 68 ++++++++++++++++++ database/seed.go | 8 +++ 7 files changed, 204 insertions(+) create mode 100644 api/testdata/trending_results_fixtures.go create mode 100644 api/v1_tracks_trending_winners.go create mode 100644 api/v1_tracks_trending_winners_test.go diff --git a/api/server.go b/api/server.go index d76054e3..69cf4a85 100644 --- a/api/server.go +++ b/api/server.go @@ -456,6 +456,7 @@ func NewApiServer(config config.Config) *ApiServer { g.Get("/tracks/trending", app.v1TracksTrending) g.Get("/tracks/trending/ids", app.v1TracksTrendingIds) + g.Get("/tracks/trending/winners", app.v1TracksTrendingWinners) g.Get("/tracks/trending/underground", app.v1TracksTrendingUnderground) g.Get("/tracks/recommended", app.v1TracksTrending) g.Get("/tracks/recent-premium", app.v1TracksRecentPremium) diff --git a/api/server_test.go b/api/server_test.go index 33e9cf8e..7b713573 100644 --- a/api/server_test.go +++ b/api/server_test.go @@ -99,6 +99,7 @@ func testAppWithFixtures(t *testing.T) *ApiServer { database.SeedTable(app.pool.Replicas[0], "saves", testdata.SaveFixtures) database.SeedTable(app.pool.Replicas[0], "tracks", testdata.TrackFixtures) database.SeedTable(app.pool.Replicas[0], "track_trending_scores", testdata.TrackTrendingScoresFixtures) + database.SeedTable(app.pool.Replicas[0], "trending_results", testdata.TrendingResultsFixtures) database.SeedTable(app.pool.Replicas[0], "track_routes", testdata.TrackRoutesFixtures) database.SeedTable(app.pool.Replicas[0], "usdc_purchases", testdata.UsdcPurchasesFixtures) database.SeedTable(app.pool.Replicas[0], "usdc_transactions_history", testdata.UsdcTransactionsHistoryFixtures) diff --git a/api/swagger/swagger-v1.yaml b/api/swagger/swagger-v1.yaml index 76dd9149..2bec2b56 100644 --- a/api/swagger/swagger-v1.yaml +++ b/api/swagger/swagger-v1.yaml @@ -2420,6 +2420,37 @@ paths: "500": description: Server error content: {} + /tracks/trending/winners: + get: + tags: + - tracks + description: Gets weekly trending winners from the trending_results table. Returns full track objects for the specified week. Defaults to the most recent week with data when no week is provided. + operationId: Get Trending Winners + parameters: + - name: week + in: query + description: Target week in YYYY-MM-DD format. Defaults to the most recent week with data. + schema: + type: string + format: date + - name: user_id + in: query + description: The user ID of the user making the request + schema: + type: string + responses: + "200": + description: Success + content: + application/json: + schema: + $ref: "#/components/schemas/tracks_response" + "400": + description: Bad request + content: {} + "500": + description: Server error + content: {} /tracks/trending/{version}: get: tags: diff --git a/api/testdata/trending_results_fixtures.go b/api/testdata/trending_results_fixtures.go new file mode 100644 index 00000000..45cbca7d --- /dev/null +++ b/api/testdata/trending_results_fixtures.go @@ -0,0 +1,8 @@ +package testdata + +var TrendingResultsFixtures = []map[string]any{ + // Week 2022-01-21 - tracks 300, 202, 200 (rank 1, 2, 3) - matches trending order + {"user_id": 3, "id": "300", "rank": 1, "type": "TrendingType.TRACKS", "version": "TrendingVersion.ML51L", "week": "2022-01-21"}, + {"user_id": 2, "id": "202", "rank": 2, "type": "TrendingType.TRACKS", "version": "TrendingVersion.ML51L", "week": "2022-01-21"}, + {"user_id": 2, "id": "200", "rank": 3, "type": "TrendingType.TRACKS", "version": "TrendingVersion.ML51L", "week": "2022-01-21"}, +} diff --git a/api/v1_tracks_trending_winners.go b/api/v1_tracks_trending_winners.go new file mode 100644 index 00000000..1bf03d29 --- /dev/null +++ b/api/v1_tracks_trending_winners.go @@ -0,0 +1,87 @@ +package api + +import ( + "api.audius.co/api/dbv1" + "github.com/gofiber/fiber/v2" + "github.com/jackc/pgx/v5" +) + +type GetTrendingWinnersTracksParams struct { + Week string `query:"week" default:""` +} + +func (app *ApiServer) v1TracksTrendingWinners(c *fiber.Ctx) error { + var params = GetTrendingWinnersTracksParams{} + if err := app.ParseAndValidateQueryParams(c, ¶ms); err != nil { + return err + } + + myId := app.getMyId(c) + + trackIds, err := app.getTrendingWinnersIds(c, params.Week) + if err != nil { + return err + } + + if len(trackIds) == 0 { + return v1TracksResponse(c, []dbv1.Track{}) + } + + tracks, err := app.queries.Tracks(c.Context(), dbv1.TracksParams{ + GetTracksParams: dbv1.GetTracksParams{ + Ids: trackIds, + MyID: myId, + }, + }) + if err != nil { + return err + } + + return v1TracksResponse(c, tracks) +} + +func (app *ApiServer) getTrendingWinnersIds(c *fiber.Ctx, weekParam string) ([]int32, error) { + args := pgx.NamedArgs{ + "type": "TrendingType.TRACKS", + } + + var weekFilter string + if weekParam != "" { + args["week"] = weekParam + weekFilter = "AND tr.week = @week" + } else { + // Default: use the most recent week in the table that is before today + weekFilter = `AND tr.week = ( + SELECT MAX(tr2.week) + FROM trending_results tr2 + WHERE tr2.type = @type + AND tr2.week < CURRENT_DATE + )` + } + + sql := ` + SELECT tr.id::int + FROM trending_results tr + JOIN tracks t ON t.track_id = tr.id::int + AND t.is_current = true + AND t.is_delete = false + AND t.is_unlisted = false + AND t.is_available = true + WHERE tr.type = @type + ` + weekFilter + ` + ORDER BY tr.rank ASC + ` + + rows, err := app.pool.Query(c.Context(), sql, args) + if err != nil { + return nil, err + } + defer rows.Close() + + trackIds, err := pgx.CollectRows(rows, pgx.RowTo[int32]) + if err != nil { + return nil, err + } + + return trackIds, nil +} diff --git a/api/v1_tracks_trending_winners_test.go b/api/v1_tracks_trending_winners_test.go new file mode 100644 index 00000000..f3a3dedc --- /dev/null +++ b/api/v1_tracks_trending_winners_test.go @@ -0,0 +1,68 @@ +package api + +import ( + "testing" + + "api.audius.co/api/dbv1" + "api.audius.co/trashid" + "github.com/stretchr/testify/assert" +) + +func TestGetTrendingWinnersTracks(t *testing.T) { + app := testAppWithFixtures(t) + + var resp struct { + Data []dbv1.Track + } + + // Test with explicit week - uses trending_results for 2022-01-21 + status, body := testGet(t, app, "/v1/tracks/trending/winners?week=2022-01-21", &resp) + assert.Equal(t, 200, status) + + jsonAssert(t, body, map[string]any{ + "data.#": 3, + }) + + // Verify order: 300 (rank 1), 202 (rank 2), 200 (rank 3) + assert.Equal(t, trashid.MustEncodeHashID(300), resp.Data[0].ID) + assert.Equal(t, "Electronic", resp.Data[0].Genre.String) + + assert.Equal(t, trashid.MustEncodeHashID(202), resp.Data[1].ID) + assert.Equal(t, "Alternative", resp.Data[1].Genre.String) + + assert.Equal(t, trashid.MustEncodeHashID(200), resp.Data[2].ID) + assert.Equal(t, "Electronic", resp.Data[2].Genre.String) +} + +func TestGetTrendingWinnersTracksDefaultWeek(t *testing.T) { + app := testAppWithFixtures(t) + + var resp struct { + Data []dbv1.Track + } + + // Without week param - defaults to most recent week in table before today (2022-01-21) + status, body := testGet(t, app, "/v1/tracks/trending/winners", &resp) + assert.Equal(t, 200, status) + + jsonAssert(t, body, map[string]any{ + "data.#": 3, + }) + + assert.Equal(t, trashid.MustEncodeHashID(300), resp.Data[0].ID) + assert.Equal(t, trashid.MustEncodeHashID(202), resp.Data[1].ID) + assert.Equal(t, trashid.MustEncodeHashID(200), resp.Data[2].ID) +} + +func TestGetTrendingWinnersTracksEmptyWeek(t *testing.T) { + app := testAppWithFixtures(t) + + var resp struct { + Data []dbv1.Track + } + + // Request a week with no data - should return empty + status, _ := testGet(t, app, "/v1/tracks/trending/winners?week=2020-01-01", &resp) + assert.Equal(t, 200, status) + assert.Equal(t, 0, len(resp.Data)) +} diff --git a/database/seed.go b/database/seed.go index 6cc48054..1c7da467 100644 --- a/database/seed.go +++ b/database/seed.go @@ -153,6 +153,14 @@ var ( "score": nil, "created_at": time.Now(), }, + "trending_results": { + "user_id": nil, + "id": nil, + "rank": nil, + "type": "TrendingType.TRACKS", + "version": "TrendingVersion.ML51L", + "week": time.Now(), + }, "playlist_trending_scores": { "playlist_id": nil, "type": "PLAYLISTS", From 86520c86adef62496797ef26f1d233bee96070e0 Mon Sep 17 00:00:00 2001 From: Raymond Jacobson Date: Wed, 18 Feb 2026 10:05:22 -0800 Subject: [PATCH 2/3] Add underground winners --- api/server.go | 1 + api/swagger/swagger-v1.yaml | 31 +++++++ api/testdata/trending_results_fixtures.go | 4 + api/v1_tracks_trending_underground_winners.go | 87 +++++++++++++++++++ ...racks_trending_underground_winners_test.go | 68 +++++++++++++++ 5 files changed, 191 insertions(+) create mode 100644 api/v1_tracks_trending_underground_winners.go create mode 100644 api/v1_tracks_trending_underground_winners_test.go diff --git a/api/server.go b/api/server.go index 69cf4a85..b2e9f2cb 100644 --- a/api/server.go +++ b/api/server.go @@ -458,6 +458,7 @@ func NewApiServer(config config.Config) *ApiServer { g.Get("/tracks/trending/ids", app.v1TracksTrendingIds) g.Get("/tracks/trending/winners", app.v1TracksTrendingWinners) g.Get("/tracks/trending/underground", app.v1TracksTrendingUnderground) + g.Get("/tracks/trending/underground/winners", app.v1TracksTrendingUndergroundWinners) g.Get("/tracks/recommended", app.v1TracksTrending) g.Get("/tracks/recent-premium", app.v1TracksRecentPremium) g.Get("/tracks/usdc-purchase", app.v1TracksUsdcPurchase) diff --git a/api/swagger/swagger-v1.yaml b/api/swagger/swagger-v1.yaml index 2bec2b56..72a0fbd8 100644 --- a/api/swagger/swagger-v1.yaml +++ b/api/swagger/swagger-v1.yaml @@ -2610,6 +2610,37 @@ paths: application/json: schema: $ref: "#/components/schemas/tracks_response" + /tracks/trending/underground/winners: + get: + tags: + - tracks + description: Gets weekly trending underground winners from the trending_results table. Returns full track objects for the specified week. Defaults to the most recent week with data when no week is provided. + operationId: Get Trending Underground Winners + parameters: + - name: week + in: query + description: Target week in YYYY-MM-DD format. Defaults to the most recent week with data. + schema: + type: string + format: date + - name: user_id + in: query + description: The user ID of the user making the request + schema: + type: string + responses: + "200": + description: Success + content: + application/json: + schema: + $ref: "#/components/schemas/tracks_response" + "400": + description: Bad request + content: {} + "500": + description: Server error + content: {} /tracks/trending/underground/{version}: get: tags: diff --git a/api/testdata/trending_results_fixtures.go b/api/testdata/trending_results_fixtures.go index 45cbca7d..e0ed60d5 100644 --- a/api/testdata/trending_results_fixtures.go +++ b/api/testdata/trending_results_fixtures.go @@ -5,4 +5,8 @@ var TrendingResultsFixtures = []map[string]any{ {"user_id": 3, "id": "300", "rank": 1, "type": "TrendingType.TRACKS", "version": "TrendingVersion.ML51L", "week": "2022-01-21"}, {"user_id": 2, "id": "202", "rank": 2, "type": "TrendingType.TRACKS", "version": "TrendingVersion.ML51L", "week": "2022-01-21"}, {"user_id": 2, "id": "200", "rank": 3, "type": "TrendingType.TRACKS", "version": "TrendingVersion.ML51L", "week": "2022-01-21"}, + // Week 2022-01-21 - underground tracks 519, 520, 521 (rank 1, 2, 3) + {"user_id": 8, "id": "519", "rank": 1, "type": "TrendingType.UNDERGROUND_TRACKS", "version": "TrendingVersion.ML51L", "week": "2022-01-21"}, + {"user_id": 11, "id": "520", "rank": 2, "type": "TrendingType.UNDERGROUND_TRACKS", "version": "TrendingVersion.ML51L", "week": "2022-01-21"}, + {"user_id": 1, "id": "521", "rank": 3, "type": "TrendingType.UNDERGROUND_TRACKS", "version": "TrendingVersion.ML51L", "week": "2022-01-21"}, } diff --git a/api/v1_tracks_trending_underground_winners.go b/api/v1_tracks_trending_underground_winners.go new file mode 100644 index 00000000..6645e99b --- /dev/null +++ b/api/v1_tracks_trending_underground_winners.go @@ -0,0 +1,87 @@ +package api + +import ( + "api.audius.co/api/dbv1" + "github.com/gofiber/fiber/v2" + "github.com/jackc/pgx/v5" +) + +type GetTrendingUndergroundWinnersTracksParams struct { + Week string `query:"week" default:""` +} + +func (app *ApiServer) v1TracksTrendingUndergroundWinners(c *fiber.Ctx) error { + var params = GetTrendingUndergroundWinnersTracksParams{} + if err := app.ParseAndValidateQueryParams(c, ¶ms); err != nil { + return err + } + + myId := app.getMyId(c) + + trackIds, err := app.getTrendingUndergroundWinnersIds(c, params.Week) + if err != nil { + return err + } + + if len(trackIds) == 0 { + return v1TracksResponse(c, []dbv1.Track{}) + } + + tracks, err := app.queries.Tracks(c.Context(), dbv1.TracksParams{ + GetTracksParams: dbv1.GetTracksParams{ + Ids: trackIds, + MyID: myId, + }, + }) + if err != nil { + return err + } + + return v1TracksResponse(c, tracks) +} + +func (app *ApiServer) getTrendingUndergroundWinnersIds(c *fiber.Ctx, weekParam string) ([]int32, error) { + args := pgx.NamedArgs{ + "type": "TrendingType.UNDERGROUND_TRACKS", + } + + var weekFilter string + if weekParam != "" { + args["week"] = weekParam + weekFilter = "AND tr.week = @week" + } else { + // Default: use the most recent week in the table that is before today + weekFilter = `AND tr.week = ( + SELECT MAX(tr2.week) + FROM trending_results tr2 + WHERE tr2.type = @type + AND tr2.week < CURRENT_DATE + )` + } + + sql := ` + SELECT tr.id::int + FROM trending_results tr + JOIN tracks t ON t.track_id = tr.id::int + AND t.is_current = true + AND t.is_delete = false + AND t.is_unlisted = false + AND t.is_available = true + WHERE tr.type = @type + ` + weekFilter + ` + ORDER BY tr.rank ASC + ` + + rows, err := app.pool.Query(c.Context(), sql, args) + if err != nil { + return nil, err + } + defer rows.Close() + + trackIds, err := pgx.CollectRows(rows, pgx.RowTo[int32]) + if err != nil { + return nil, err + } + + return trackIds, nil +} diff --git a/api/v1_tracks_trending_underground_winners_test.go b/api/v1_tracks_trending_underground_winners_test.go new file mode 100644 index 00000000..67077264 --- /dev/null +++ b/api/v1_tracks_trending_underground_winners_test.go @@ -0,0 +1,68 @@ +package api + +import ( + "testing" + + "api.audius.co/api/dbv1" + "api.audius.co/trashid" + "github.com/stretchr/testify/assert" +) + +func TestGetTrendingUndergroundWinnersTracks(t *testing.T) { + app := testAppWithFixtures(t) + + var resp struct { + Data []dbv1.Track + } + + // Test with explicit week - uses trending_results for 2022-01-21 + status, body := testGet(t, app, "/v1/tracks/trending/underground/winners?week=2022-01-21", &resp) + assert.Equal(t, 200, status) + + jsonAssert(t, body, map[string]any{ + "data.#": 3, + }) + + // Verify order: 519 (rank 1), 520 (rank 2), 521 (rank 3) + assert.Equal(t, trashid.MustEncodeHashID(519), resp.Data[0].ID) + assert.Equal(t, "Jazz", resp.Data[0].Genre.String) + + assert.Equal(t, trashid.MustEncodeHashID(520), resp.Data[1].ID) + assert.Equal(t, "Classical", resp.Data[1].Genre.String) + + assert.Equal(t, trashid.MustEncodeHashID(521), resp.Data[2].ID) + assert.Equal(t, "Electronic", resp.Data[2].Genre.String) +} + +func TestGetTrendingUndergroundWinnersTracksDefaultWeek(t *testing.T) { + app := testAppWithFixtures(t) + + var resp struct { + Data []dbv1.Track + } + + // Without week param - defaults to most recent week in table before today (2022-01-21) + status, body := testGet(t, app, "/v1/tracks/trending/underground/winners", &resp) + assert.Equal(t, 200, status) + + jsonAssert(t, body, map[string]any{ + "data.#": 3, + }) + + assert.Equal(t, trashid.MustEncodeHashID(519), resp.Data[0].ID) + assert.Equal(t, trashid.MustEncodeHashID(520), resp.Data[1].ID) + assert.Equal(t, trashid.MustEncodeHashID(521), resp.Data[2].ID) +} + +func TestGetTrendingUndergroundWinnersTracksEmptyWeek(t *testing.T) { + app := testAppWithFixtures(t) + + var resp struct { + Data []dbv1.Track + } + + // Request a week with no underground data - should return empty + status, _ := testGet(t, app, "/v1/tracks/trending/underground/winners?week=2020-01-01", &resp) + assert.Equal(t, 200, status) + assert.Equal(t, 0, len(resp.Data)) +} From 0c9bf9062ccbc922bcc121fafd3ba878881c3327 Mon Sep 17 00:00:00 2001 From: Raymond Jacobson Date: Wed, 18 Feb 2026 10:10:42 -0800 Subject: [PATCH 3/3] Add prior week logic --- api/v1_tracks_trending_underground_winners.go | 8 ++++- ...racks_trending_underground_winners_test.go | 31 +++++++++++++++++-- api/v1_tracks_trending_winners.go | 8 ++++- api/v1_tracks_trending_winners_test.go | 31 +++++++++++++++++-- 4 files changed, 70 insertions(+), 8 deletions(-) diff --git a/api/v1_tracks_trending_underground_winners.go b/api/v1_tracks_trending_underground_winners.go index 6645e99b..4cbf579e 100644 --- a/api/v1_tracks_trending_underground_winners.go +++ b/api/v1_tracks_trending_underground_winners.go @@ -48,7 +48,13 @@ func (app *ApiServer) getTrendingUndergroundWinnersIds(c *fiber.Ctx, weekParam s var weekFilter string if weekParam != "" { args["week"] = weekParam - weekFilter = "AND tr.week = @week" + // Nearest row on or after the requested week; if none (e.g. future date), use most recent + weekFilter = `AND tr.week = COALESCE( + (SELECT MIN(tr2.week) FROM trending_results tr2 + WHERE tr2.type = @type AND tr2.week >= @week::date), + (SELECT MAX(tr2.week) FROM trending_results tr2 + WHERE tr2.type = @type) + )` } else { // Default: use the most recent week in the table that is before today weekFilter = `AND tr.week = ( diff --git a/api/v1_tracks_trending_underground_winners_test.go b/api/v1_tracks_trending_underground_winners_test.go index 67077264..a3bb7aab 100644 --- a/api/v1_tracks_trending_underground_winners_test.go +++ b/api/v1_tracks_trending_underground_winners_test.go @@ -54,15 +54,40 @@ func TestGetTrendingUndergroundWinnersTracksDefaultWeek(t *testing.T) { assert.Equal(t, trashid.MustEncodeHashID(521), resp.Data[2].ID) } -func TestGetTrendingUndergroundWinnersTracksEmptyWeek(t *testing.T) { +func TestGetTrendingUndergroundWinnersTracksOldDateUsesEarliestWeek(t *testing.T) { app := testAppWithFixtures(t) var resp struct { Data []dbv1.Track } - // Request a week with no underground data - should return empty + // Query before any data (2020-01-01): nearest row on or after is 2022-01-21 (earliest we have) status, _ := testGet(t, app, "/v1/tracks/trending/underground/winners?week=2020-01-01", &resp) assert.Equal(t, 200, status) - assert.Equal(t, 0, len(resp.Data)) + assert.Equal(t, 3, len(resp.Data)) +} + +func TestGetTrendingUndergroundWinnersTracksNearestWeek(t *testing.T) { + app := testAppWithFixtures(t) + + var resp struct { + Data []dbv1.Track + } + + // Query 2022-01-20: nearest row on or after is 2022-01-21 + status, _ := testGet(t, app, "/v1/tracks/trending/underground/winners?week=2022-01-20", &resp) + assert.Equal(t, 200, status) + assert.Equal(t, 3, len(resp.Data)) + assert.Equal(t, trashid.MustEncodeHashID(519), resp.Data[0].ID) + + // Query 2022-01-21: exact match + status, _ = testGet(t, app, "/v1/tracks/trending/underground/winners?week=2022-01-21", &resp) + assert.Equal(t, 200, status) + assert.Equal(t, 3, len(resp.Data)) + + // Query 2022-01-25: no row after 2022-01-21, use most recent (2022-01-21) + status, _ = testGet(t, app, "/v1/tracks/trending/underground/winners?week=2022-01-25", &resp) + assert.Equal(t, 200, status) + assert.Equal(t, 3, len(resp.Data)) + assert.Equal(t, trashid.MustEncodeHashID(519), resp.Data[0].ID) } diff --git a/api/v1_tracks_trending_winners.go b/api/v1_tracks_trending_winners.go index 1bf03d29..31a477ca 100644 --- a/api/v1_tracks_trending_winners.go +++ b/api/v1_tracks_trending_winners.go @@ -48,7 +48,13 @@ func (app *ApiServer) getTrendingWinnersIds(c *fiber.Ctx, weekParam string) ([]i var weekFilter string if weekParam != "" { args["week"] = weekParam - weekFilter = "AND tr.week = @week" + // Nearest row on or after the requested week; if none (e.g. future date), use most recent + weekFilter = `AND tr.week = COALESCE( + (SELECT MIN(tr2.week) FROM trending_results tr2 + WHERE tr2.type = @type AND tr2.week >= @week::date), + (SELECT MAX(tr2.week) FROM trending_results tr2 + WHERE tr2.type = @type) + )` } else { // Default: use the most recent week in the table that is before today weekFilter = `AND tr.week = ( diff --git a/api/v1_tracks_trending_winners_test.go b/api/v1_tracks_trending_winners_test.go index f3a3dedc..ed9cafe2 100644 --- a/api/v1_tracks_trending_winners_test.go +++ b/api/v1_tracks_trending_winners_test.go @@ -54,15 +54,40 @@ func TestGetTrendingWinnersTracksDefaultWeek(t *testing.T) { assert.Equal(t, trashid.MustEncodeHashID(200), resp.Data[2].ID) } -func TestGetTrendingWinnersTracksEmptyWeek(t *testing.T) { +func TestGetTrendingWinnersTracksOldDateUsesEarliestWeek(t *testing.T) { app := testAppWithFixtures(t) var resp struct { Data []dbv1.Track } - // Request a week with no data - should return empty + // Query before any data (2020-01-01): nearest row on or after is 2022-01-21 (earliest we have) status, _ := testGet(t, app, "/v1/tracks/trending/winners?week=2020-01-01", &resp) assert.Equal(t, 200, status) - assert.Equal(t, 0, len(resp.Data)) + assert.Equal(t, 3, len(resp.Data)) +} + +func TestGetTrendingWinnersTracksNearestWeek(t *testing.T) { + app := testAppWithFixtures(t) + + var resp struct { + Data []dbv1.Track + } + + // Query 2022-01-20: nearest row on or after is 2022-01-21 + status, _ := testGet(t, app, "/v1/tracks/trending/winners?week=2022-01-20", &resp) + assert.Equal(t, 200, status) + assert.Equal(t, 3, len(resp.Data)) + assert.Equal(t, trashid.MustEncodeHashID(300), resp.Data[0].ID) + + // Query 2022-01-21: exact match + status, _ = testGet(t, app, "/v1/tracks/trending/winners?week=2022-01-21", &resp) + assert.Equal(t, 200, status) + assert.Equal(t, 3, len(resp.Data)) + + // Query 2022-01-25: no row after 2022-01-21, use most recent (2022-01-21) + status, _ = testGet(t, app, "/v1/tracks/trending/winners?week=2022-01-25", &resp) + assert.Equal(t, 200, status) + assert.Equal(t, 3, len(resp.Data)) + assert.Equal(t, trashid.MustEncodeHashID(300), resp.Data[0].ID) }