Skip to content
This repository was archived by the owner on Jan 29, 2025. It is now read-only.

Commit 3d9104f

Browse files
authored
feat: filter catalog using variadic function (#5)
1 parent 9d35a90 commit 3d9104f

File tree

4 files changed

+339
-38
lines changed

4 files changed

+339
-38
lines changed

monstercat/browse.go

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package monstercat
2+
3+
import (
4+
"fmt"
5+
"net/url"
6+
)
7+
8+
// BrowseOption is a function that can be used to modify the query parameters of the catalog endpoint.
9+
type BrowseOption func(parameters *url.Values)
10+
11+
// Default returns the default query parameters for the catalog endpoint.
12+
func Default() url.Values {
13+
defaultOptions := []BrowseOption{
14+
IncludeGold(true),
15+
IncludeUnreleased(true),
16+
WithSort("-date"),
17+
WithLimit(10),
18+
WithOffset(0),
19+
}
20+
21+
parameters := url.Values{}
22+
for _, option := range defaultOptions {
23+
option(&parameters)
24+
}
25+
return parameters
26+
}
27+
28+
// WithSearch limits the results to the tracks, albums or artists matching the given search query.
29+
func WithSearch(query string) BrowseOption {
30+
return func(parameters *url.Values) {
31+
parameters.Set("search", query)
32+
}
33+
}
34+
35+
// WithBrand limits the results to the tracks released under the given brands.
36+
// 1: Uncaged
37+
// 2: Instinct
38+
// 3: Call of the Wild
39+
// 4: Silk
40+
// 5: Silk Showcase
41+
func WithBrand(brandID int) BrowseOption {
42+
return func(parameters *url.Values) {
43+
parameters.Add("brands[]", fmt.Sprintf("%d", brandID))
44+
}
45+
}
46+
47+
// WithGenre limits the results to the tracks matching the given genre.
48+
// Examples are "dubstep", "acoustic" or "melodic house & techno". See the Monstercat Player for a full list of genres.
49+
func WithGenre(genre string) BrowseOption {
50+
return func(parameters *url.Values) {
51+
parameters.Add("genres[]", genre)
52+
}
53+
}
54+
55+
// WithReleaseType limits the results to the tracks matching the given release type.
56+
// Either "Single", "EP" or "Album".
57+
func WithReleaseType(releaseType string) BrowseOption {
58+
return func(parameters *url.Values) {
59+
parameters.Add("types[]", releaseType)
60+
}
61+
}
62+
63+
// WithTag limits the results to the tracks matching the given tag.
64+
// Examples are "chill", "badass" or "funky". See the Monstercat Player for a full list of genres.
65+
func WithTag(tag string) BrowseOption {
66+
return func(parameters *url.Values) {
67+
parameters.Add("tags[]", tag)
68+
}
69+
}
70+
71+
// IncludeGold decides whether to include gold tracks or not.
72+
func IncludeGold(include bool) BrowseOption {
73+
return func(parameters *url.Values) {
74+
parameters.Set("nogold", fmt.Sprintf("%t", !include))
75+
}
76+
}
77+
78+
// IncludeUnreleased decides whether to include unreleased tracks or not.
79+
func IncludeUnreleased(include bool) BrowseOption {
80+
return func(parameters *url.Values) {
81+
parameters.Set("onlyReleased", fmt.Sprintf("%t", !include))
82+
}
83+
}
84+
85+
// WithSort sorts the results by the given field.
86+
// Adding a minus sign to the field name will sort in descending order.
87+
// Either "title", "artists", "release", "genre", "date", "bpm", "duration" or "brand".
88+
func WithSort(sortBy string) BrowseOption {
89+
return func(parameters *url.Values) {
90+
parameters.Set("sort", sortBy)
91+
}
92+
}
93+
94+
// WithLimit limits the results to the given number of items.
95+
func WithLimit(limit int) BrowseOption {
96+
return func(parameters *url.Values) {
97+
parameters.Set("limit", fmt.Sprintf("%d", limit))
98+
}
99+
}
100+
101+
// WithOffset allows to skip the given number of items.
102+
func WithOffset(offset int) BrowseOption {
103+
return func(parameters *url.Values) {
104+
parameters.Set("offset", fmt.Sprintf("%d", offset))
105+
}
106+
}

monstercat/browse_test.go

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
package monstercat
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func TestBrowseOptions_Default(t *testing.T) {
10+
assert.Equal(t, "limit=10&nogold=false&offset=0&onlyReleased=false&sort=-date", Default().Encode())
11+
}
12+
13+
func TestBrowseOptions_Complete(t *testing.T) {
14+
parameters := Default()
15+
WithSearch("mix")(&parameters)
16+
WithBrand(1)(&parameters)
17+
WithBrand(2)(&parameters)
18+
WithGenre("dubstep")(&parameters)
19+
WithGenre("acoustic")(&parameters)
20+
WithReleaseType("Single")(&parameters)
21+
WithReleaseType("EP")(&parameters)
22+
WithTag("chill")(&parameters)
23+
WithTag("badass")(&parameters)
24+
IncludeGold(false)(&parameters)
25+
IncludeUnreleased(false)(&parameters)
26+
WithSort("title")(&parameters)
27+
WithLimit(10)(&parameters)
28+
WithOffset(5)(&parameters)
29+
30+
assert.Equal(t, "brands%5B%5D=1&brands%5B%5D=2&genres%5B%5D=dubstep&genres%5B%5D=acoustic&limit=10&nogold=true&offset=5&onlyReleased=true&search=mix&sort=title&tags%5B%5D=chill&tags%5B%5D=badass&types%5B%5D=Single&types%5B%5D=EP", parameters.Encode())
31+
}
32+
33+
func TestBrowseOptions_WithSearch(t *testing.T) {
34+
parameters := Default()
35+
WithSearch("mix")(&parameters)
36+
37+
assert.Equal(t, "limit=10&nogold=false&offset=0&onlyReleased=false&search=mix&sort=-date", parameters.Encode())
38+
}
39+
40+
func TestBrowseOptions_WithSearchMultiple(t *testing.T) {
41+
parameters := Default()
42+
WithSearch("mix")(&parameters)
43+
WithSearch("contest")(&parameters)
44+
45+
assert.Equal(t, "limit=10&nogold=false&offset=0&onlyReleased=false&search=contest&sort=-date", parameters.Encode())
46+
}
47+
48+
func TestBrowseOptions_WithBrand(t *testing.T) {
49+
parameters := Default()
50+
WithBrand(1)(&parameters)
51+
52+
assert.Equal(t, "brands%5B%5D=1&limit=10&nogold=false&offset=0&onlyReleased=false&sort=-date", parameters.Encode())
53+
}
54+
55+
func TestBrowseOptions_WithBrand_Multiple(t *testing.T) {
56+
parameters := Default()
57+
WithBrand(1)(&parameters)
58+
WithBrand(2)(&parameters)
59+
60+
assert.Equal(t, "brands%5B%5D=1&brands%5B%5D=2&limit=10&nogold=false&offset=0&onlyReleased=false&sort=-date", parameters.Encode())
61+
}
62+
63+
func TestBrowseOptions_WithGenre(t *testing.T) {
64+
parameters := Default()
65+
WithGenre("dubstep")(&parameters)
66+
67+
assert.Equal(t, "genres%5B%5D=dubstep&limit=10&nogold=false&offset=0&onlyReleased=false&sort=-date", parameters.Encode())
68+
}
69+
70+
func TestBrowseOptions_WithGenre_Multiple(t *testing.T) {
71+
parameters := Default()
72+
WithGenre("dubstep")(&parameters)
73+
WithGenre("acoustic")(&parameters)
74+
75+
assert.Equal(t, "genres%5B%5D=dubstep&genres%5B%5D=acoustic&limit=10&nogold=false&offset=0&onlyReleased=false&sort=-date", parameters.Encode())
76+
}
77+
78+
func TestBrowseOptions_WithReleaseType(t *testing.T) {
79+
parameters := Default()
80+
WithReleaseType("Single")(&parameters)
81+
82+
assert.Equal(t, "limit=10&nogold=false&offset=0&onlyReleased=false&sort=-date&types%5B%5D=Single", parameters.Encode())
83+
}
84+
85+
func TestBrowseOptions_WithReleaseType_Multiple(t *testing.T) {
86+
parameters := Default()
87+
WithReleaseType("Single")(&parameters)
88+
WithReleaseType("EP")(&parameters)
89+
90+
assert.Equal(t, "limit=10&nogold=false&offset=0&onlyReleased=false&sort=-date&types%5B%5D=Single&types%5B%5D=EP", parameters.Encode())
91+
}
92+
93+
func TestBrowseOptions_WithTag(t *testing.T) {
94+
parameters := Default()
95+
WithTag("chill")(&parameters)
96+
97+
assert.Equal(t, "limit=10&nogold=false&offset=0&onlyReleased=false&sort=-date&tags%5B%5D=chill", parameters.Encode())
98+
}
99+
100+
func TestBrowseOptions_WithTag_Multiple(t *testing.T) {
101+
parameters := Default()
102+
WithTag("chill")(&parameters)
103+
WithTag("badass")(&parameters)
104+
105+
assert.Equal(t, "limit=10&nogold=false&offset=0&onlyReleased=false&sort=-date&tags%5B%5D=chill&tags%5B%5D=badass", parameters.Encode())
106+
}
107+
108+
func TestBrowseOptions_IncludeGold(t *testing.T) {
109+
parameters := Default()
110+
IncludeGold(false)(&parameters)
111+
112+
assert.Equal(t, "limit=10&nogold=true&offset=0&onlyReleased=false&sort=-date", parameters.Encode())
113+
}
114+
115+
func TestBrowseOptions_IncludeGold_Multiple(t *testing.T) {
116+
parameters := Default()
117+
IncludeGold(false)(&parameters)
118+
IncludeGold(true)(&parameters)
119+
120+
assert.Equal(t, "limit=10&nogold=false&offset=0&onlyReleased=false&sort=-date", parameters.Encode())
121+
}
122+
123+
func TestBrowseOptions_IncludeUnreleased(t *testing.T) {
124+
parameters := Default()
125+
IncludeUnreleased(false)(&parameters)
126+
127+
assert.Equal(t, "limit=10&nogold=false&offset=0&onlyReleased=true&sort=-date", parameters.Encode())
128+
}
129+
130+
func TestBrowseOptions_IncludeUnreleased_Multiple(t *testing.T) {
131+
parameters := Default()
132+
IncludeUnreleased(false)(&parameters)
133+
IncludeUnreleased(true)(&parameters)
134+
135+
assert.Equal(t, "limit=10&nogold=false&offset=0&onlyReleased=false&sort=-date", parameters.Encode())
136+
}
137+
138+
func TestBrowseOptions_WithSort(t *testing.T) {
139+
parameters := Default()
140+
WithSort("title")(&parameters)
141+
142+
assert.Equal(t, "limit=10&nogold=false&offset=0&onlyReleased=false&sort=title", parameters.Encode())
143+
}
144+
145+
func TestBrowseOptions_WithSort_Multiple(t *testing.T) {
146+
parameters := Default()
147+
WithSort("title")(&parameters)
148+
WithSort("-artist")(&parameters)
149+
150+
assert.Equal(t, "limit=10&nogold=false&offset=0&onlyReleased=false&sort=-artist", parameters.Encode())
151+
}
152+
153+
func TestBrowseOptions_WithLimit(t *testing.T) {
154+
parameters := Default()
155+
WithLimit(5)(&parameters)
156+
157+
assert.Equal(t, "limit=5&nogold=false&offset=0&onlyReleased=false&sort=-date", parameters.Encode())
158+
}
159+
160+
func TestBrowseOptions_WithLimit_Multiple(t *testing.T) {
161+
parameters := Default()
162+
WithLimit(5)(&parameters)
163+
WithLimit(50)(&parameters)
164+
165+
assert.Equal(t, "limit=50&nogold=false&offset=0&onlyReleased=false&sort=-date", parameters.Encode())
166+
}
167+
168+
func TestBrowseOptions_WithOffset(t *testing.T) {
169+
parameters := Default()
170+
WithOffset(5)(&parameters)
171+
172+
assert.Equal(t, "limit=10&nogold=false&offset=5&onlyReleased=false&sort=-date", parameters.Encode())
173+
}
174+
175+
func TestBrowseOptions_WithOffset_Multiple(t *testing.T) {
176+
parameters := Default()
177+
WithOffset(5)(&parameters)
178+
WithOffset(50)(&parameters)
179+
180+
assert.Equal(t, "limit=10&nogold=false&offset=50&onlyReleased=false&sort=-date", parameters.Encode())
181+
}

monstercat/catalog.go

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"fmt"
66
"io"
77
"net/http"
8-
"net/url"
98
)
109

1110
// Catalog represents a list of catalog items from Monstercat API
@@ -16,20 +15,15 @@ type Catalog struct {
1615
Offset int `json:"Offset"`
1716
}
1817

19-
// Catalog returns a set of catalog items containing the given search query, matching the given release type and being within the given range.
20-
// While limit and offset are required, you may leave search and releaseType empty to ignore those filters.
21-
// TODO: add brands[], tags[] and genres[]
22-
func (client Client) Catalog(search string, releaseType string, limit int, offset int) (Catalog, error) {
18+
// BrowseCatalog returns a set of catalog items defined by the given BrowseOptions.
19+
// All BrowseOptions will override their default values defined in Default().
20+
func (client Client) BrowseCatalog(options ...BrowseOption) (Catalog, error) {
2321
catalog := Catalog{}
2422

25-
urlParameters := url.Values{}
26-
urlParameters.Add("search", search)
27-
urlParameters.Add("types[]", releaseType)
28-
urlParameters.Add("sort", "-date") // TODO: make configurable + add values
29-
urlParameters.Add("nogold", "false") // TODO: make configurable
30-
urlParameters.Add("onlyReleased", "false") // TODO: make configurable
31-
urlParameters.Add("limit", fmt.Sprintf("%d", limit))
32-
urlParameters.Add("offset", fmt.Sprintf("%d", offset))
23+
urlParameters := Default()
24+
for _, option := range options {
25+
option(&urlParameters)
26+
}
3327

3428
request, err := http.NewRequest("GET", fmt.Sprintf("%s?%s", endpointCatalog, urlParameters.Encode()), http.NoBody)
3529
if err != nil {
@@ -62,6 +56,13 @@ func (client Client) Catalog(search string, releaseType string, limit int, offse
6256
return catalog, nil
6357
}
6458

59+
// Catalog returns a set of catalog items containing the given search query, matching the given release type and being within the given range.
60+
// While limit and offset are required, you may leave search and releaseType empty to ignore those filters.
61+
// Deprecated: Use the BrowseCatalog function instead.
62+
func (client Client) Catalog(search string, releaseType string, limit int, offset int) (Catalog, error) {
63+
return client.BrowseCatalog(WithSearch(search), WithReleaseType(releaseType), WithLimit(limit), WithOffset(offset))
64+
}
65+
6566
// HasNextPage returns true if the catalog list contains more pages, false otherwise.
6667
func (catalog Catalog) HasNextPage() bool {
6768
return (catalog.Offset + catalog.Limit) < catalog.Total

0 commit comments

Comments
 (0)