Skip to content

Commit 115268f

Browse files
authored
Add ListClusterSizeSKUs to organizations service (#230)
* Add ListClusterSKUs to the organization service * Add default_vtgate_rate * Add WithRegion ListOption
1 parent 7493444 commit 115268f

File tree

4 files changed

+191
-0
lines changed

4 files changed

+191
-0
lines changed

planetscale/client.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,24 @@ func WithLimit(limit int) ListOption {
105105
}
106106
}
107107

108+
// WithRates returns a ListOption that sets the "rates" URL parameter.
109+
func WithRates() ListOption {
110+
return func(opt *ListOptions) error {
111+
opt.URLValues.Set("rates", "true")
112+
return nil
113+
}
114+
}
115+
116+
// WithRegion returns a ListOption sets the "region" URL parameter.
117+
func WithRegion(region string) ListOption {
118+
return func(opt *ListOptions) error {
119+
if len(region) > 0 {
120+
opt.URLValues.Set("region", region)
121+
}
122+
return nil
123+
}
124+
}
125+
108126
// WithPage returns a ListOption that sets the "page" URL parameter.
109127
func WithPage(page int) ListOption {
110128
return func(opt *ListOptions) error {

planetscale/client_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,3 +162,7 @@ func TestDo(t *testing.T) {
162162
})
163163
}
164164
}
165+
166+
func Pointer[K any](val K) *K {
167+
return &val
168+
}

planetscale/organizations.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ type OrganizationsService interface {
2323
Get(context.Context, *GetOrganizationRequest) (*Organization, error)
2424
List(context.Context) ([]*Organization, error)
2525
ListRegions(context.Context, *ListOrganizationRegionsRequest) ([]*Region, error)
26+
ListClusterSKUs(context.Context, *ListOrganizationClusterSKUsRequest, ...ListOption) ([]*ClusterSKU, error)
2627
}
2728

2829
// ListRegionsRequest encapsulates the request for getting a list of regions for
@@ -31,6 +32,30 @@ type ListOrganizationRegionsRequest struct {
3132
Organization string
3233
}
3334

35+
// ListOrganizationClusterSKUsRequest encapsulates the request for getting a list of Cluster SKUs for an organization.
36+
type ListOrganizationClusterSKUsRequest struct {
37+
Organization string
38+
IncludeRates bool
39+
}
40+
41+
// ClusterSKU represents a SKU for a PlanetScale cluster
42+
type ClusterSKU struct {
43+
Name string `json:"name"`
44+
DisplayName string `json:"display_name"`
45+
CPU string `json:"cpu"`
46+
Memory string `json:"ram"`
47+
48+
Storage *int64 `json:"storage,string"`
49+
50+
Rate *int64 `json:"rate"`
51+
ReplicaRate *int64 `json:"replica_rate"`
52+
ProviderInstanceType *string `json:"provider_instance_type"`
53+
Provider *string `json:"provider"`
54+
Enabled bool `json:"enabled"`
55+
DefaultVTGate string `json:"default_vtgate"`
56+
DefaultVTGateRate *int64 `json:"default_vtgate_rate"`
57+
}
58+
3459
// Organization represents a PlanetScale organization.
3560
type Organization struct {
3661
Name string `json:"name"`
@@ -102,3 +127,32 @@ func (o *organizationsService) ListRegions(ctx context.Context, listReq *ListOrg
102127

103128
return listResponse.Regions, nil
104129
}
130+
131+
type listClusterSKUsResponse struct {
132+
ClusterSKUs []*ClusterSKU `json:"data"`
133+
}
134+
135+
func (o *organizationsService) ListClusterSKUs(ctx context.Context, listReq *ListOrganizationClusterSKUsRequest, opts ...ListOption) ([]*ClusterSKU, error) {
136+
path := fmt.Sprintf("%s/%s/cluster-size-skus", organizationsAPIPath, listReq.Organization)
137+
138+
defaultOpts := defaultListOptions()
139+
for _, opt := range opts {
140+
opt(defaultOpts)
141+
}
142+
143+
if vals := defaultOpts.URLValues.Encode(); vals != "" {
144+
path += "?" + vals
145+
}
146+
147+
req, err := o.client.newRequest(http.MethodGet, path, nil)
148+
if err != nil {
149+
return nil, errors.Wrap(err, "error creating http request")
150+
}
151+
152+
listResponse := &listClusterSKUsResponse{}
153+
if err := o.client.do(ctx, req, &listResponse); err != nil {
154+
return nil, err
155+
}
156+
157+
return listResponse.ClusterSKUs, nil
158+
}

planetscale/organizations_test.go

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,118 @@ func TestOrganizations_ListRegions(t *testing.T) {
127127

128128
c.Assert(orgs, qt.DeepEquals, want)
129129
}
130+
131+
func TestOrganizations_ListClusterSKUs(t *testing.T) {
132+
c := qt.New(t)
133+
134+
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
135+
w.WriteHeader(200)
136+
137+
c.Assert(r.URL.String(), qt.Equals, "/v1/organizations/my-cool-org/cluster-size-skus")
138+
out := `{
139+
"data": [
140+
{
141+
"name": "PS_10",
142+
"type": "ClusterSizeSku",
143+
"display_name": "PS-10",
144+
"cpu": "1/8",
145+
"provider_instance_type": null,
146+
"storage": null,
147+
"ram": "1",
148+
"sort_order": 1,
149+
"enabled": true,
150+
"provider": null,
151+
"rate": null,
152+
"replica_rate": null,
153+
"default_vtgate": "VTG_5",
154+
"default_vtgate_rate": null
155+
}
156+
]
157+
}`
158+
159+
_, err := w.Write([]byte(out))
160+
c.Assert(err, qt.IsNil)
161+
}))
162+
163+
client, err := NewClient(WithBaseURL(ts.URL))
164+
c.Assert(err, qt.IsNil)
165+
166+
ctx := context.Background()
167+
168+
orgs, err := client.Organizations.ListClusterSKUs(ctx, &ListOrganizationClusterSKUsRequest{
169+
Organization: "my-cool-org",
170+
})
171+
172+
c.Assert(err, qt.IsNil)
173+
want := []*ClusterSKU{
174+
{
175+
Name: "PS_10",
176+
DisplayName: "PS-10",
177+
CPU: "1/8",
178+
Memory: "1",
179+
Enabled: true,
180+
DefaultVTGate: "VTG_5",
181+
},
182+
}
183+
184+
c.Assert(orgs, qt.DeepEquals, want)
185+
}
186+
187+
func TestOrganizations_ListClusterSKUsWithRates(t *testing.T) {
188+
c := qt.New(t)
189+
190+
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
191+
w.WriteHeader(200)
192+
193+
c.Assert(r.URL.String(), qt.Equals, "/v1/organizations/my-cool-org/cluster-size-skus?rates=true")
194+
out := `{
195+
"data": [
196+
{
197+
"name": "PS_10",
198+
"type": "ClusterSizeSku",
199+
"display_name": "PS-10",
200+
"cpu": "1/8",
201+
"provider_instance_type": null,
202+
"storage": "100",
203+
"ram": "1",
204+
"sort_order": 1,
205+
"enabled": true,
206+
"provider": null,
207+
"rate": 39,
208+
"replica_rate": 13,
209+
"default_vtgate": "VTG_5",
210+
"default_vtgate_rate": null
211+
}
212+
]
213+
}`
214+
215+
_, err := w.Write([]byte(out))
216+
c.Assert(err, qt.IsNil)
217+
}))
218+
219+
client, err := NewClient(WithBaseURL(ts.URL))
220+
c.Assert(err, qt.IsNil)
221+
222+
ctx := context.Background()
223+
224+
orgs, err := client.Organizations.ListClusterSKUs(ctx, &ListOrganizationClusterSKUsRequest{
225+
Organization: "my-cool-org",
226+
}, WithRates())
227+
228+
c.Assert(err, qt.IsNil)
229+
want := []*ClusterSKU{
230+
{
231+
Name: "PS_10",
232+
DisplayName: "PS-10",
233+
CPU: "1/8",
234+
Memory: "1",
235+
Enabled: true,
236+
Storage: Pointer[int64](100),
237+
Rate: Pointer[int64](39),
238+
ReplicaRate: Pointer[int64](13),
239+
DefaultVTGate: "VTG_5",
240+
},
241+
}
242+
243+
c.Assert(orgs, qt.DeepEquals, want)
244+
}

0 commit comments

Comments
 (0)