Skip to content

Commit 45f5992

Browse files
authored
Implement PostgresBranchesService for Postgres branches (#257)
* Get started on PostgresBranchesService * Use standard cluster SKU * Scaffold out rest of the PostgresBranchesService * Implement Create function for PostgresBranches * Add PostgresBranches service to Client * Update CreatePostgresBranchRequest * Update comments * Fill out LIst struct * Implement remaining interface methods * Start on tests * Implement namespace filtering on schema * Add kind and update comments * Fix Schema return type
1 parent 5a1728e commit 45f5992

File tree

3 files changed

+434
-0
lines changed

3 files changed

+434
-0
lines changed

planetscale/client.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ type Client struct {
5555
DataImports DataImportsService
5656
Organizations OrganizationsService
5757
Passwords PasswordsService
58+
PostgresBranches PostgresBranchesService
5859
Regions RegionsService
5960
DeployRequests DeployRequestsService
6061
ServiceTokens ServiceTokenService
@@ -277,6 +278,7 @@ func NewClient(opts ...ClientOption) (*Client, error) {
277278
c.ServiceTokens = &serviceTokenService{client: c}
278279
c.Keyspaces = &keyspacesService{client: c}
279280
c.Workflows = &workflowsService{client: c}
281+
c.PostgresBranches = &postgresBranchesService{client: c}
280282

281283
return c, nil
282284
}

planetscale/postgres_branches.go

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
package planetscale
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"net/http"
7+
"net/url"
8+
"time"
9+
)
10+
11+
// PostgresBranch represents a Postgres branch in the PlanetScale API.
12+
type PostgresBranch struct {
13+
ID string `json:"id"`
14+
Name string `json:"name"`
15+
ClusterName string `json:"cluster_name"`
16+
ClusterDisplayName string `json:"cluster_display_name"`
17+
ClusterArchitecture string `json:"cluster_architecture"`
18+
ClusterIOPS int `json:"cluster_iops"`
19+
State string `json:"state"`
20+
CreatedAt time.Time `json:"created_at"`
21+
UpdatedAt time.Time `json:"updated_at"`
22+
Actor Actor `json:"actor"`
23+
Production bool `json:"production"`
24+
Ready bool `json:"ready"`
25+
ParentBranch string `json:"parent_branch"`
26+
Region Region `json:"region"`
27+
Kind string `json:"kind"`
28+
}
29+
30+
type postgresBranchesResponse struct {
31+
Branches []*PostgresBranch `json:"data"`
32+
}
33+
34+
// CreatePostgresBranchRequest encapsulates the request to create a Postgres branch.
35+
type CreatePostgresBranchRequest struct {
36+
Organization string `json:"-"`
37+
Database string `json:"-"`
38+
Region string `json:"region,omitempty"`
39+
Name string `json:"name"`
40+
ParentBranch string `json:"parent_branch"`
41+
BackupID string `json:"backup_id,omitempty"`
42+
ClusterName string `json:"cluster_name,omitempty"`
43+
}
44+
45+
// ListPostgresBranchesRequest encapsulates the request to list Postgres branches for a database.
46+
type ListPostgresBranchesRequest struct {
47+
Organization string
48+
Database string
49+
}
50+
51+
// GetPostgresBranchRequest encapsulates the request to get a specific Postgres branch.
52+
type GetPostgresBranchRequest struct {
53+
Organization string
54+
Database string
55+
Branch string
56+
}
57+
58+
// DeletePostgresBranchRequest encapsulates the request to delete a Postgres branch.
59+
type DeletePostgresBranchRequest struct {
60+
Organization string
61+
Database string
62+
Branch string
63+
}
64+
65+
// PostgresBranchSchemaRequest encapsulates the request to get the schema of a Postgres branch.
66+
type PostgresBranchSchemaRequest struct {
67+
Organization string
68+
Database string
69+
Branch string
70+
Namespace string `json:"-"`
71+
}
72+
73+
// PostgresBranchSchema encapsulates the schema of a Postgres branch.
74+
type PostgresBranchSchema struct {
75+
Name string `json:"name"`
76+
Raw string `json:"raw"`
77+
HTML string `json:"html"`
78+
}
79+
80+
// postgresBranchSchemaResponse returns the schemas
81+
type postgresBranchSchemaResponse struct {
82+
Schemas []*PostgresBranchSchema `json:"data"`
83+
}
84+
85+
type PostgresBranchesService interface {
86+
Create(context.Context, *CreatePostgresBranchRequest) (*PostgresBranch, error)
87+
List(context.Context, *ListPostgresBranchesRequest) ([]*PostgresBranch, error)
88+
Get(context.Context, *GetPostgresBranchRequest) (*PostgresBranch, error)
89+
Delete(context.Context, *DeletePostgresBranchRequest) error
90+
Schema(context.Context, *PostgresBranchSchemaRequest) ([]*PostgresBranchSchema, error)
91+
ListClusterSKUs(context.Context, *ListBranchClusterSKUsRequest, ...ListOption) ([]*ClusterSKU, error)
92+
}
93+
94+
type postgresBranchesService struct {
95+
client *Client
96+
}
97+
98+
var _ PostgresBranchesService = &postgresBranchesService{}
99+
100+
func NewPostgresBranchesService(client *Client) *postgresBranchesService {
101+
return &postgresBranchesService{
102+
client: client,
103+
}
104+
}
105+
106+
// Create creates a new Postgres branch in the specified organization and database.
107+
func (p *postgresBranchesService) Create(ctx context.Context, createReq *CreatePostgresBranchRequest) (*PostgresBranch, error) {
108+
path := postgresBranchesAPIPath(createReq.Organization, createReq.Database)
109+
req, err := p.client.newRequest(http.MethodPost, path, createReq)
110+
if err != nil {
111+
return nil, fmt.Errorf("error creating http request: %w", err)
112+
}
113+
114+
b := &PostgresBranch{}
115+
if err := p.client.do(ctx, req, b); err != nil {
116+
return nil, err
117+
}
118+
119+
return b, nil
120+
}
121+
122+
// List returns a list of Postgres branches for the specified organization and database.
123+
func (p *postgresBranchesService) List(ctx context.Context, listReq *ListPostgresBranchesRequest) ([]*PostgresBranch, error) {
124+
req, err := p.client.newRequest(http.MethodGet, postgresBranchesAPIPath(listReq.Organization, listReq.Database), nil)
125+
if err != nil {
126+
return nil, fmt.Errorf("error creating http request: %w", err)
127+
}
128+
129+
pgBranches := &postgresBranchesResponse{}
130+
if err := p.client.do(ctx, req, &pgBranches); err != nil {
131+
return nil, err
132+
}
133+
134+
return pgBranches.Branches, nil
135+
}
136+
137+
// Get returns a single Postgres branch for the specified organization, database, and branch.
138+
func (p *postgresBranchesService) Get(ctx context.Context, getReq *GetPostgresBranchRequest) (*PostgresBranch, error) {
139+
path := fmt.Sprintf("%s/%s", postgresBranchesAPIPath(getReq.Organization, getReq.Database), getReq.Branch)
140+
req, err := p.client.newRequest(http.MethodGet, path, nil)
141+
if err != nil {
142+
return nil, fmt.Errorf("error creating http request: %w", err)
143+
}
144+
145+
pgBranch := &PostgresBranch{}
146+
if err := p.client.do(ctx, req, &pgBranch); err != nil {
147+
return nil, err
148+
}
149+
150+
return pgBranch, nil
151+
}
152+
153+
// Delete deletes a Postgres branch from the specified organization and database.
154+
func (p *postgresBranchesService) Delete(ctx context.Context, deleteReq *DeletePostgresBranchRequest) error {
155+
path := fmt.Sprintf("%s/%s", postgresBranchesAPIPath(deleteReq.Organization, deleteReq.Database), deleteReq.Branch)
156+
req, err := p.client.newRequest(http.MethodDelete, path, nil)
157+
if err != nil {
158+
return fmt.Errorf("error creating http request: %w", err)
159+
}
160+
161+
err = p.client.do(ctx, req, nil)
162+
return err
163+
}
164+
165+
// ListClusterSKUs returns a list of cluster SKUs for the specified Postgres branch.
166+
func (p *postgresBranchesService) ListClusterSKUs(ctx context.Context, listReq *ListBranchClusterSKUsRequest, opts ...ListOption) ([]*ClusterSKU, error) {
167+
path := fmt.Sprintf("%s/cluster-size-skus", postgresBranchAPIPath(listReq.Organization, listReq.Database, listReq.Branch))
168+
169+
defaultOpts := defaultListOptions()
170+
for _, opt := range opts {
171+
err := opt(defaultOpts)
172+
if err != nil {
173+
return nil, err
174+
}
175+
}
176+
177+
if vals := defaultOpts.URLValues.Encode(); vals != "" {
178+
path += "?" + vals
179+
}
180+
181+
req, err := p.client.newRequest(http.MethodGet, path, nil)
182+
if err != nil {
183+
return nil, fmt.Errorf("error creating http request: %w", err)
184+
}
185+
186+
clusterSKUs := []*ClusterSKU{}
187+
if err := p.client.do(ctx, req, &clusterSKUs); err != nil {
188+
return nil, err
189+
}
190+
191+
return clusterSKUs, nil
192+
}
193+
194+
// Schema returns the schema for the specified Postgres branch.
195+
func (p *postgresBranchesService) Schema(ctx context.Context, schemaReq *PostgresBranchSchemaRequest) ([]*PostgresBranchSchema, error) {
196+
path := fmt.Sprintf("%s/schema", postgresBranchAPIPath(schemaReq.Organization, schemaReq.Database, schemaReq.Branch))
197+
v := url.Values{}
198+
if schemaReq.Namespace != "" {
199+
v.Set("namespace", schemaReq.Namespace)
200+
}
201+
202+
if vals := v.Encode(); vals != "" {
203+
path += "?" + vals
204+
}
205+
206+
req, err := p.client.newRequest(http.MethodGet, path, nil)
207+
if err != nil {
208+
return nil, fmt.Errorf("error creating http request: %w", err)
209+
}
210+
211+
schemas := &postgresBranchSchemaResponse{}
212+
if err := p.client.do(ctx, req, &schemas); err != nil {
213+
return nil, err
214+
}
215+
216+
return schemas.Schemas, nil
217+
}
218+
219+
func postgresBranchesAPIPath(org, db string) string {
220+
return fmt.Sprintf("%s/%s/branches", databasesAPIPath(org), db)
221+
}
222+
223+
func postgresBranchAPIPath(org, db, branch string) string {
224+
return fmt.Sprintf("%s/%s", postgresBranchesAPIPath(org, db), branch)
225+
}

0 commit comments

Comments
 (0)