Skip to content

Commit 1608034

Browse files
[API-87] Add trending ids route (#41)
1 parent 07aab14 commit 1608034

7 files changed

Lines changed: 177 additions & 32 deletions

api/server.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ func NewApiServer(config config.Config) *ApiServer {
200200
g.Get("/tracks", app.v1Tracks)
201201

202202
g.Get("/tracks/trending", app.v1TracksTrending)
203+
g.Get("/tracks/trending/ids", app.v1TracksTrendingIds)
203204
g.Get("/tracks/recommended", app.v1TracksTrending)
204205

205206
g.Use("/tracks/:trackId", app.requireTrackIdMiddleware)

api/testdata/track_fixtures.csv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ track_id,genre,owner_id,title,is_unlisted,stream_conditions,download_conditions
77
300,Electronic,3,Follow Gated Download,f,,"{""follow_user_id"": 3}"
88
301,Electronic,3,Pay Gated Download,f,,"{""usdc_purchase"": {""price"": 135, ""splits"": [{""user_id"": 3, ""percentage"": 100.0}]}}"
99
302,Electronic,3,Tip Gated Stream,f," {""tip_user_id"": 3}"," {""tip_user_id"": 3}"
10+
400,Folk,5,Trending Month Folk,f,,

api/testdata/track_trending_scores_fixtures.csv

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ track_id,genre,time_range,score
44
201,Alternative,week,2.0
55
202,Alternative,week,2.0
66
300,Electronic,week,3.0
7-
300,Electronic,allTime,3.0
7+
300,Electronic,allTime,3.0
8+
400,Folk,month,10.0

api/testdata/user_fixtures.csv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ user_id,handle,handle_lc,is_deactivated,wallet,playlist_library
33
2,stereosteve,stereosteve,f,0x1234567890abcdef,
44
3,someseller,someseller,f,0x234567890abcdef1,
55
4,accesstester,accesstester,f,0x34567890abcdef12,
6+
5,guyintrending,guyintrending,f,0x34567890abcdef13,
67
91,badguy,badguy,t,0x4567890abcdef123,

api/v1_tracks_trending.go

Lines changed: 7 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,43 +3,19 @@ package api
33
import (
44
"bridgerton.audius.co/api/dbv1"
55
"github.com/gofiber/fiber/v2"
6-
"github.com/jackc/pgx/v5"
76
)
87

98
func (app *ApiServer) v1TracksTrending(c *fiber.Ctx) error {
109
myId := app.getMyId(c)
1110

12-
sql := `
13-
SELECT track_trending_scores.track_id
14-
FROM track_trending_scores
15-
LEFT JOIN tracks
16-
ON tracks.track_id = track_trending_scores.track_id
17-
AND tracks.is_delete = false
18-
AND tracks.is_unlisted = false
19-
AND tracks.is_available = true
20-
WHERE type = 'TRACKS'
21-
AND version = 'pnagD'
22-
AND time_range = @time
23-
AND (@genre = '' OR track_trending_scores.genre = @genre)
24-
ORDER BY
25-
score DESC,
26-
track_id DESC
27-
LIMIT @limit
28-
OFFSET @offset
29-
`
11+
trackIds, err := app.getTrendingIds(
12+
c,
13+
c.Query("time", "week"),
14+
c.Query("genre", ""),
15+
c.QueryInt("limit", 100),
16+
c.QueryInt("offset", 0),
17+
)
3018

31-
args := pgx.NamedArgs{}
32-
args["limit"] = c.Query("limit", "100")
33-
args["offset"] = c.Query("offset", "0")
34-
args["time"] = c.Query("time", "week")
35-
args["genre"] = c.Query("genre", "")
36-
37-
rows, err := app.pool.Query(c.Context(), sql, args)
38-
if err != nil {
39-
return err
40-
}
41-
42-
trackIds, err := pgx.CollectRows(rows, pgx.RowTo[int32])
4319
if err != nil {
4420
return err
4521
}

api/v1_tracks_trending_ids.go

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
package api
2+
3+
import (
4+
"bridgerton.audius.co/trashid"
5+
"github.com/gofiber/fiber/v2"
6+
"github.com/jackc/pgx/v5"
7+
)
8+
9+
func (app *ApiServer) getTrendingIds(c *fiber.Ctx, timeRange string, genre string, limit int, offset int) ([]int32, error) {
10+
sql := `
11+
SELECT track_trending_scores.track_id
12+
FROM track_trending_scores
13+
LEFT JOIN tracks
14+
ON tracks.track_id = track_trending_scores.track_id
15+
AND tracks.is_delete = false
16+
AND tracks.is_unlisted = false
17+
AND tracks.is_available = true
18+
WHERE type = 'TRACKS'
19+
AND version = 'pnagD'
20+
AND time_range = @time
21+
AND (@genre = '' OR track_trending_scores.genre = @genre)
22+
ORDER BY
23+
score DESC,
24+
track_id DESC
25+
LIMIT @limit
26+
OFFSET @offset
27+
`
28+
29+
args := pgx.NamedArgs{}
30+
args["limit"] = limit
31+
args["offset"] = offset
32+
args["time"] = timeRange
33+
args["genre"] = genre
34+
35+
rows, err := app.pool.Query(c.Context(), sql, args)
36+
if err != nil {
37+
return nil, err
38+
}
39+
40+
trackIds, err := pgx.CollectRows(rows, pgx.RowTo[int32])
41+
if err != nil {
42+
return nil, err
43+
}
44+
45+
return trackIds, nil
46+
}
47+
48+
type hashIdResponse struct {
49+
ID string `json:"id"`
50+
}
51+
52+
func encodeIds(ids []int32) ([]hashIdResponse, error) {
53+
result := make([]hashIdResponse, len(ids))
54+
for i, id := range ids {
55+
encoded, err := trashid.EncodeHashId(int(id))
56+
if err != nil {
57+
return nil, err
58+
}
59+
result[i] = hashIdResponse{ID: encoded}
60+
}
61+
return result, nil
62+
}
63+
64+
func (app *ApiServer) v1TracksTrendingIds(c *fiber.Ctx) error {
65+
limit := c.QueryInt("limit", 100)
66+
offset := c.QueryInt("offset", 0)
67+
genre := ""
68+
69+
weekChan := make(chan []int32)
70+
monthChan := make(chan []int32)
71+
yearChan := make(chan []int32)
72+
errChan := make(chan error)
73+
74+
go func() {
75+
ids, err := app.getTrendingIds(c, "week", genre, limit, offset)
76+
if err != nil {
77+
errChan <- err
78+
return
79+
}
80+
weekChan <- ids
81+
}()
82+
83+
go func() {
84+
ids, err := app.getTrendingIds(c, "month", genre, limit, offset)
85+
if err != nil {
86+
errChan <- err
87+
return
88+
}
89+
monthChan <- ids
90+
}()
91+
92+
go func() {
93+
ids, err := app.getTrendingIds(c, "allTime", genre, limit, offset)
94+
if err != nil {
95+
errChan <- err
96+
return
97+
}
98+
yearChan <- ids
99+
}()
100+
101+
var weekIds, monthIds, yearIds []int32
102+
103+
for i := 0; i < 3; i++ {
104+
select {
105+
case weekIds = <-weekChan:
106+
case monthIds = <-monthChan:
107+
case yearIds = <-yearChan:
108+
case err := <-errChan:
109+
return err
110+
}
111+
}
112+
113+
weekHashedIds, err := encodeIds(weekIds)
114+
if err != nil {
115+
return err
116+
}
117+
118+
monthHashedIds, err := encodeIds(monthIds)
119+
if err != nil {
120+
return err
121+
}
122+
123+
yearHashedIds, err := encodeIds(yearIds)
124+
if err != nil {
125+
return err
126+
}
127+
128+
return c.JSON(fiber.Map{
129+
"data": fiber.Map{
130+
"week": weekHashedIds,
131+
"month": monthHashedIds,
132+
// Note that this is technically all time, but is set as
133+
// year for backwards compatibility
134+
"year": yearHashedIds,
135+
},
136+
})
137+
}

api/v1_tracks_trending_ids_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package api
2+
3+
import (
4+
"testing"
5+
6+
"bridgerton.audius.co/trashid"
7+
"github.com/stretchr/testify/assert"
8+
)
9+
10+
func TestGetTrendingIds(t *testing.T) {
11+
var resp struct {
12+
Data struct {
13+
Week []hashIdResponse `json:"week"`
14+
Month []hashIdResponse `json:"month"`
15+
Year []hashIdResponse `json:"year"`
16+
} `json:"data"`
17+
}
18+
status, _ := testGet(t, "/v1/tracks/trending/ids", &resp)
19+
assert.Equal(t, 200, status)
20+
21+
assert.Equal(t, trashid.MustEncodeHashID(300), resp.Data.Week[0].ID)
22+
assert.Equal(t, trashid.MustEncodeHashID(202), resp.Data.Week[1].ID)
23+
assert.Equal(t, trashid.MustEncodeHashID(201), resp.Data.Week[2].ID)
24+
assert.Equal(t, trashid.MustEncodeHashID(200), resp.Data.Week[3].ID)
25+
assert.Equal(t, trashid.MustEncodeHashID(400), resp.Data.Month[0].ID)
26+
assert.Equal(t, trashid.MustEncodeHashID(200), resp.Data.Year[0].ID)
27+
assert.Equal(t, trashid.MustEncodeHashID(300), resp.Data.Year[1].ID)
28+
}

0 commit comments

Comments
 (0)