From 2f225fc1507a3682c05f4466b7883191ee38b5f3 Mon Sep 17 00:00:00 2001 From: Raymond Jacobson Date: Thu, 10 Apr 2025 16:48:09 -0700 Subject: [PATCH 1/3] basic trending --- api/dbv1/queries/get_trending_tracks.sql | 0 api/server.go | 2 + api/v1_trending.go | 64 ++++++++++++++++++++++++ 3 files changed, 66 insertions(+) delete mode 100644 api/dbv1/queries/get_trending_tracks.sql create mode 100644 api/v1_trending.go diff --git a/api/dbv1/queries/get_trending_tracks.sql b/api/dbv1/queries/get_trending_tracks.sql deleted file mode 100644 index e69de29b..00000000 diff --git a/api/server.go b/api/server.go index 25a191c3..35fbbc4d 100644 --- a/api/server.go +++ b/api/server.go @@ -145,6 +145,8 @@ func NewApiServer(config Config) *ApiServer { // Tracks g.Get("/tracks", app.v1Tracks) + g.Get("/tracks/trending", app.v1Trending) + g.Use("/tracks/:trackId", app.requireTrackIdMiddleware) g.Get("/tracks/:trackId", app.v1Track) g.Get("/tracks/:trackId/reposts", app.v1TracksReposts) diff --git a/api/v1_trending.go b/api/v1_trending.go new file mode 100644 index 00000000..330e9bc1 --- /dev/null +++ b/api/v1_trending.go @@ -0,0 +1,64 @@ +package api + +import ( + "bridgerton.audius.co/api/dbv1" + "github.com/gofiber/fiber/v2" + "github.com/jackc/pgx/v5" +) + +func (app *ApiServer) v1Trending(c *fiber.Ctx) error { + myId := c.Locals("myId") + + sql := ` + SELECT track_trending_scores.track_id + FROM track_trending_scores + LEFT JOIN tracks + ON tracks.track_id = track_trending_scores.track_id + AND tracks.is_delete = false + AND tracks.is_unlisted = false + AND tracks.is_available = true + WHERE type = 'TRACKS' + AND version = 'pnagD' + AND time_range = 'week' + ORDER BY + score DESC, + track_id DESC + LIMIT @limit + OFFSET @offset + ` + + args := pgx.NamedArgs{ + "limit": 100, + "offset": 0, + } + + rows, err := app.pool.Query(c.Context(), sql, args) + if err != nil { + return err + } + + type trackTrendingRow struct { + TrackId int32 `json:"track_id"` + } + + trackTrendingRows, err := pgx.CollectRows(rows, pgx.RowToStructByName[trackTrendingRow]) + if err != nil { + return err + } + + trackIds := []int32{} + for _, t := range trackTrendingRows { + trackIds = append(trackIds, t.TrackId) + } + + tracks, err := app.queries.FullTracks(c.Context(), dbv1.GetTracksParams{ + Ids: trackIds, + MyID: myId, + }) + + if err != nil { + return err + } + + return v1TracksResponse(c, tracks) +} From 38727e437507d92f30d17fe7655c6e1a0eb0ad64 Mon Sep 17 00:00:00 2001 From: Raymond Jacobson Date: Thu, 10 Apr 2025 18:05:18 -0700 Subject: [PATCH 2/3] Add trending tests --- api/fixture_test.go | 10 ++++ api/server_test.go | 1 + api/testdata/track_fixtures.csv | 13 ++--- .../track_trending_scores_fixtures.csv | 7 +++ api/v1_trending.go | 13 +++-- api/v1_trending_test.go | 54 +++++++++++++++++++ 6 files changed, 87 insertions(+), 11 deletions(-) create mode 100644 api/testdata/track_trending_scores_fixtures.csv create mode 100644 api/v1_trending_test.go diff --git a/api/fixture_test.go b/api/fixture_test.go index db3a821c..432f0c7f 100644 --- a/api/fixture_test.go +++ b/api/fixture_test.go @@ -105,6 +105,16 @@ var ( "updated_at": time.Now(), "image_url": nil, } + + trackTrendingScoreBaseRow = map[string]any{ + "track_id": nil, + "type": "TRACKS", + "genre": nil, + "version": "pnagD", + "time_range": nil, + "score": nil, + "created_at": time.Now(), + } ) func insertFixtures(table string, baseRow map[string]any, csvFile string) { diff --git a/api/server_test.go b/api/server_test.go index 9c04fb49..9344ca23 100644 --- a/api/server_test.go +++ b/api/server_test.go @@ -67,6 +67,7 @@ func TestMain(m *testing.M) { insertFixtures("follows", followBaseRow, "testdata/follow_fixtures.csv") insertFixtures("reposts", repostBaseRow, "testdata/repost_fixtures.csv") insertFixtures("developer_apps", developerAppBaseRow, "testdata/developer_app_fixtures.csv") + insertFixtures("track_trending_scores", trackTrendingScoreBaseRow, "testdata/track_trending_scores_fixtures.csv") // index to es / os diff --git a/api/testdata/track_fixtures.csv b/api/testdata/track_fixtures.csv index 91e526b8..555a5eca 100644 --- a/api/testdata/track_fixtures.csv +++ b/api/testdata/track_fixtures.csv @@ -1,6 +1,7 @@ -track_id,owner_id,title,is_unlisted,stream_conditions,download_conditions -200,2,Culca Canyon,f,, -201,2,Turkey Time DEMO,t,, -300,3,Follow Gated Download,f,,"{""follow_user_id"": 3}" -301,3,Pay Gated Download,f,,"{""usdc_purchase"": {""price"": 135, ""splits"": [{""user_id"": 3, ""percentage"": 100.0}]}}" -302,3,Tip Gated Stream,f," {""tip_user_id"": 859175075}", +track_id,genre,owner_id,title,is_unlisted,stream_conditions,download_conditions +200,Electronic,2,Culca Canyon,f,, +201,Alternative,2,Turkey Time DEMO,t,, +202,Alternative,2,Turkey Time (live),f,, +300,Electronic,3,Follow Gated Download,f,,"{""follow_user_id"": 3}" +301,Electronic,3,Pay Gated Download,f,,"{""usdc_purchase"": {""price"": 135, ""splits"": [{""user_id"": 3, ""percentage"": 100.0}]}}" +302,Electronic,3,Tip Gated Stream,f," {""tip_user_id"": 859175075}", diff --git a/api/testdata/track_trending_scores_fixtures.csv b/api/testdata/track_trending_scores_fixtures.csv new file mode 100644 index 00000000..439d99b0 --- /dev/null +++ b/api/testdata/track_trending_scores_fixtures.csv @@ -0,0 +1,7 @@ +track_id,genre,time_range,score +200,Electronic,week,1.0 +200,Electronic,allTime,5.0 +201,Alternative,week,2.0 +202,Alternative,week,2.0 +300,Electronic,week,3.0 +300,Electronic,allTime,3.0 \ No newline at end of file diff --git a/api/v1_trending.go b/api/v1_trending.go index 330e9bc1..796b9577 100644 --- a/api/v1_trending.go +++ b/api/v1_trending.go @@ -9,6 +9,7 @@ import ( func (app *ApiServer) v1Trending(c *fiber.Ctx) error { myId := c.Locals("myId") + // SQL query with conditional genre filter sql := ` SELECT track_trending_scores.track_id FROM track_trending_scores @@ -19,7 +20,8 @@ func (app *ApiServer) v1Trending(c *fiber.Ctx) error { AND tracks.is_available = true WHERE type = 'TRACKS' AND version = 'pnagD' - AND time_range = 'week' + AND time_range = @timeRange + AND (@genre = '' OR track_trending_scores.genre = @genre) ORDER BY score DESC, track_id DESC @@ -27,10 +29,11 @@ func (app *ApiServer) v1Trending(c *fiber.Ctx) error { OFFSET @offset ` - args := pgx.NamedArgs{ - "limit": 100, - "offset": 0, - } + args := pgx.NamedArgs{} + args["limit"] = c.Query("limit", "100") + args["offset"] = c.Query("offset", "0") + args["timeRange"] = c.Query("timeRange", "week") + args["genre"] = c.Query("genre", "") rows, err := app.pool.Query(c.Context(), sql, args) if err != nil { diff --git a/api/v1_trending_test.go b/api/v1_trending_test.go new file mode 100644 index 00000000..a048dc89 --- /dev/null +++ b/api/v1_trending_test.go @@ -0,0 +1,54 @@ +package api + +import ( + "testing" + + "bridgerton.audius.co/api/dbv1" + "bridgerton.audius.co/trashid" + "github.com/stretchr/testify/assert" +) + +func TestGetTrending(t *testing.T) { + var resp struct { + Data []dbv1.FullTrack + } + status, _ := testGet(t, "/v1/tracks/trending", &resp) + assert.Equal(t, 200, status) + + 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 TestGetTrendingElectronic(t *testing.T) { + var resp struct { + Data []dbv1.FullTrack + } + status, _ := testGet(t, "/v1/tracks/trending?genre=Electronic", &resp) + assert.Equal(t, 200, status) + + assert.Equal(t, "eYRWn", resp.Data[0].ID) + assert.Equal(t, "Electronic", resp.Data[0].Genre.String) + + assert.Equal(t, "eYJyn", resp.Data[1].ID) + assert.Equal(t, "Electronic", resp.Data[1].Genre.String) +} + +func TestGetTrendingAllTime(t *testing.T) { + var resp struct { + Data []dbv1.FullTrack + } + status, _ := testGet(t, "/v1/tracks/trending?timeRange=allTime", &resp) + assert.Equal(t, 200, status) + + assert.Equal(t, "eYJyn", resp.Data[0].ID) + assert.Equal(t, "Electronic", resp.Data[0].Genre.String) + + assert.Equal(t, "eYRWn", resp.Data[1].ID) + assert.Equal(t, "Electronic", resp.Data[1].Genre.String) +} From 6bce26f98e72954200b1b0ca6178acc6442beb52 Mon Sep 17 00:00:00 2001 From: Raymond Jacobson Date: Fri, 11 Apr 2025 16:03:21 -0700 Subject: [PATCH 3/3] Simplify --- api/v1_trending.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/api/v1_trending.go b/api/v1_trending.go index 796b9577..82c3651f 100644 --- a/api/v1_trending.go +++ b/api/v1_trending.go @@ -44,16 +44,11 @@ func (app *ApiServer) v1Trending(c *fiber.Ctx) error { TrackId int32 `json:"track_id"` } - trackTrendingRows, err := pgx.CollectRows(rows, pgx.RowToStructByName[trackTrendingRow]) + trackIds, err := pgx.CollectRows(rows, pgx.RowTo[int32]) if err != nil { return err } - trackIds := []int32{} - for _, t := range trackTrendingRows { - trackIds = append(trackIds, t.TrackId) - } - tracks, err := app.queries.FullTracks(c.Context(), dbv1.GetTracksParams{ Ids: trackIds, MyID: myId,