Skip to content

Commit 57b7357

Browse files
committed
refactor: move postgrest-go inside
1 parent c44e0d6 commit 57b7357

11 files changed

+994
-1
lines changed

Diff for: postgrest/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.vscode

Diff for: postgrest/LICENSE

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
MIT License
2+
3+
Copyright (c) 2021 Do a Huddle, Inc.
4+
Copyright (c) 2021-2024 Ned Palacios
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a copy
7+
of this software and associated documentation files (the "Software"), to deal
8+
in the Software without restriction, including without limitation the rights
9+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
copies of the Software, and to permit persons to whom the Software is
11+
furnished to do so, subject to the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included in all
14+
copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
SOFTWARE.

Diff for: postgrest/pkg/client.go

+165
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
package postgrest_go
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"encoding/base64"
7+
"encoding/json"
8+
"fmt"
9+
"io"
10+
"net/http"
11+
"net/url"
12+
)
13+
14+
type Client struct {
15+
session http.Client
16+
Debug bool
17+
defaultHeaders http.Header
18+
Transport *PostgrestTransport
19+
}
20+
21+
type ClientOption func(c *Client)
22+
23+
func NewClient(baseURL url.URL, opts ...ClientOption) *Client {
24+
transport := PostgrestTransport{
25+
baseURL: baseURL,
26+
Parent: http.DefaultTransport,
27+
}
28+
29+
c := Client{
30+
Transport: &transport,
31+
defaultHeaders: http.Header{},
32+
session: http.Client{Transport: &transport},
33+
}
34+
35+
c.defaultHeaders.Set("Accept", "application/json")
36+
c.defaultHeaders.Set("Content-Type", "application/json")
37+
c.defaultHeaders.Set("Accept-Profile", "public")
38+
c.defaultHeaders.Set("Content-Profile", "public")
39+
40+
for _, opt := range opts {
41+
opt(&c)
42+
}
43+
44+
if c.Debug {
45+
fmt.Println("CAUTION! Please make sure to disable the debug option before deploying it to production.")
46+
c.Transport.debug = c.Debug
47+
}
48+
return &c
49+
}
50+
51+
func (c *Client) From(table string) *RequestBuilder {
52+
return &RequestBuilder{
53+
client: c,
54+
path: "/" + table,
55+
header: http.Header{},
56+
params: url.Values{},
57+
}
58+
}
59+
60+
type RpcRequestBuilder struct {
61+
client *Client
62+
path string
63+
header http.Header
64+
httpMethod string
65+
params map[string]interface{}
66+
}
67+
68+
func (c *Client) Rpc(f string, params map[string]interface{}) *RpcRequestBuilder {
69+
return &RpcRequestBuilder{
70+
client: c,
71+
path: c.Transport.baseURL.String() + "rpc/" + f,
72+
header: http.Header{},
73+
httpMethod: http.MethodPost,
74+
params: params,
75+
}
76+
}
77+
78+
func (r *RpcRequestBuilder) Execute(result interface{}) error {
79+
return r.ExecuteWithContext(context.Background(), result)
80+
}
81+
82+
func (r *RpcRequestBuilder) ExecuteWithContext(ctx context.Context, result interface{}) error {
83+
data, err := json.Marshal(r.params)
84+
if err != nil {
85+
return err
86+
}
87+
88+
req, err := http.NewRequestWithContext(ctx, r.httpMethod, r.path, bytes.NewBuffer(data))
89+
if err != nil {
90+
return err
91+
}
92+
93+
req.Header = r.client.Headers()
94+
95+
// inject/override custom headers
96+
for key, vals := range r.header {
97+
for _, val := range vals {
98+
req.Header.Set(key, val)
99+
}
100+
}
101+
102+
req.URL.Path = req.URL.Path[1:]
103+
req.URL = r.client.Transport.baseURL.ResolveReference(req.URL)
104+
105+
resp, err := r.client.session.Do(req)
106+
if err != nil {
107+
return err
108+
}
109+
110+
defer resp.Body.Close()
111+
body, err := io.ReadAll(resp.Body)
112+
if err != nil {
113+
return err
114+
}
115+
116+
statusOK := resp.StatusCode >= 200 && resp.StatusCode < 300
117+
if !statusOK {
118+
reqError := RequestError{HTTPStatusCode: resp.StatusCode}
119+
120+
if err = json.Unmarshal(body, &reqError); err != nil {
121+
return err
122+
}
123+
124+
return &reqError
125+
}
126+
127+
if resp.StatusCode != http.StatusNoContent && r != nil {
128+
if err = json.Unmarshal(body, result); err != nil {
129+
return err
130+
}
131+
}
132+
133+
return nil
134+
}
135+
136+
func (c *Client) CloseIdleConnections() {
137+
c.session.CloseIdleConnections()
138+
}
139+
140+
func (c *Client) Headers() http.Header {
141+
return c.defaultHeaders.Clone()
142+
}
143+
144+
func (c *Client) AddHeader(key string, value string) {
145+
c.defaultHeaders.Set(key, value)
146+
}
147+
148+
func WithTokenAuth(token string) ClientOption {
149+
return func(c *Client) {
150+
c.AddHeader("Authorization", "Bearer "+token)
151+
}
152+
}
153+
154+
func WithBasicAuth(username, password string) ClientOption {
155+
return func(c *Client) {
156+
c.AddHeader("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(username+":"+password)))
157+
}
158+
}
159+
160+
func WithSchema(schema string) ClientOption {
161+
return func(c *Client) {
162+
c.AddHeader("Accept-Profile", schema)
163+
c.AddHeader("Content-Profile", schema)
164+
}
165+
}

Diff for: postgrest/pkg/client_test.go

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package postgrest_go
2+
3+
import (
4+
"net/url"
5+
"testing"
6+
)
7+
8+
func TestPostgrestClient_Constructor(t *testing.T) {
9+
client := NewClient(url.URL{Scheme: "https", Host: "example.com"})
10+
11+
if got := client.Transport.baseURL.String(); got != "https://example.com" {
12+
t.Errorf("expected baseURL == %s, got %s", "https://example.com", got)
13+
}
14+
15+
if got := client.defaultHeaders.Get("Accept"); got != "application/json" {
16+
t.Errorf("expected header Accept == %s, got %s", "application/json", got)
17+
}
18+
if got := client.defaultHeaders.Get("Content-Type"); got != "application/json" {
19+
t.Errorf("expected header Content-Type == %s, got %s", "application/json", got)
20+
}
21+
if got := client.defaultHeaders.Get("Accept-Profile"); got != "public" {
22+
t.Errorf("expected header Accept-Profile == %s, got %s", "public", got)
23+
}
24+
if got := client.defaultHeaders.Get("Content-Profile"); got != "public" {
25+
t.Errorf("expected header Content-Profile == %s, got %s", "public", got)
26+
}
27+
}
28+
29+
func TestPostgrestClient_TokenAuth(t *testing.T) {
30+
client := NewClient(
31+
url.URL{Scheme: "https", Host: "example.com"},
32+
WithTokenAuth("s3cr3t"))
33+
34+
if got := client.defaultHeaders.Get("Authorization"); got != "Bearer s3cr3t" {
35+
t.Errorf("expected header Authorization == %s, got %s", "Bearer s3cr3t", got)
36+
}
37+
}
38+
39+
func TestPostgrestClient_BasicAuth(t *testing.T) {
40+
client := NewClient(
41+
url.URL{Scheme: "https", Host: "example.com"},
42+
WithBasicAuth("admin", "s3cr3t"))
43+
44+
if got := client.defaultHeaders.Get("Authorization"); got != "Basic YWRtaW46czNjcjN0" {
45+
t.Errorf("expected header Authorization == %s, got %s", "Basic YWRtaW46czNjcjN0", got)
46+
}
47+
}
48+
49+
func TestPostgrestClient_Schema(t *testing.T) {
50+
client := NewClient(
51+
url.URL{Scheme: "https", Host: "example.com"},
52+
WithSchema("private"))
53+
54+
headers := client.Headers()
55+
if got := headers.Get("Accept-Profile"); got != "private" {
56+
t.Errorf("expected header Accept-Profile == %s, got %s", "private", got)
57+
}
58+
if got := headers.Get("Content-Profile"); got != "private" {
59+
t.Errorf("expected header Content-Profile == %s, got %s", "private", got)
60+
}
61+
}

Diff for: postgrest/pkg/filter_request_builder_test.go

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package postgrest_go
2+
3+
import (
4+
"net/http"
5+
"net/url"
6+
"testing"
7+
)
8+
9+
func TestFilterRequestBuilder_Constructor(t *testing.T) {
10+
client := NewClient(url.URL{Scheme: "https", Host: "example.com"})
11+
12+
path := "/example_table"
13+
httpMethod := "GET"
14+
15+
builder := FilterRequestBuilder{
16+
QueryRequestBuilder: QueryRequestBuilder{
17+
client: client,
18+
path: path,
19+
httpMethod: httpMethod,
20+
json: nil,
21+
},
22+
negateNext: false,
23+
}
24+
25+
if builder.path != path {
26+
t.Errorf("expected path == %s, got %s", path, builder.path)
27+
}
28+
if builder.httpMethod != httpMethod {
29+
t.Errorf("expected httpMethod == %s, got %s", httpMethod, builder.httpMethod)
30+
}
31+
if builder.json != nil {
32+
t.Errorf("expected json == %v, got %v", nil, builder.json)
33+
}
34+
}
35+
36+
func TestFilterRequestBuilder_Not(t *testing.T) {
37+
client := NewClient(url.URL{Scheme: "https", Host: "example.com"})
38+
39+
path := "/example_table"
40+
httpMethod := http.MethodGet
41+
42+
builder := FilterRequestBuilder{
43+
QueryRequestBuilder: QueryRequestBuilder{
44+
client: client,
45+
path: path,
46+
httpMethod: httpMethod,
47+
json: nil,
48+
},
49+
negateNext: false,
50+
}
51+
52+
if got := builder.Not().negateNext; !got {
53+
t.Errorf("expected negateNext == true, got %v", got)
54+
}
55+
}
56+
57+
func TestFilterRequestBuilder_Filter(t *testing.T) {
58+
client := NewClient(url.URL{Scheme: "https", Host: "example.com"})
59+
60+
path := "/example_table"
61+
httpMethod := http.MethodGet
62+
63+
builder := &FilterRequestBuilder{
64+
QueryRequestBuilder: QueryRequestBuilder{
65+
client: client,
66+
path: path,
67+
httpMethod: httpMethod,
68+
json: nil,
69+
params: url.Values{},
70+
},
71+
negateNext: false,
72+
}
73+
74+
builder = builder.Filter(":col.name", "eq", "val")
75+
76+
want := "eq.val"
77+
got := builder.params.Get("\":col.name\"")
78+
79+
if want != got {
80+
t.Errorf("expected http param \":col.name\" == %s, got %s", want, got)
81+
}
82+
}
83+
84+
func TestFilterRequestBuilder_MultivaluedParam(t *testing.T) {
85+
client := NewClient(url.URL{Scheme: "https", Host: "example.com"})
86+
87+
path := "/example_table"
88+
httpMethod := http.MethodGet
89+
90+
builder := &FilterRequestBuilder{
91+
QueryRequestBuilder: QueryRequestBuilder{
92+
client: client,
93+
path: path,
94+
httpMethod: httpMethod,
95+
json: nil,
96+
params: url.Values{},
97+
},
98+
negateNext: false,
99+
}
100+
101+
builder = builder.Lte("x", "a").Gte("x", "b")
102+
103+
want := "x=lte.a&x=gte.b"
104+
got := builder.params.Encode()
105+
106+
if want != got {
107+
t.Errorf("expected http params.Encode() == %s, got %s", want, got)
108+
}
109+
}

Diff for: postgrest/pkg/query_request_builder_test.go

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package postgrest_go
2+
3+
import (
4+
"net/url"
5+
"testing"
6+
)
7+
8+
func TestQueryRequestBuilder_Constructor(t *testing.T) {
9+
client := NewClient(url.URL{Scheme: "https", Host: "example.com"})
10+
11+
path := "/example_table"
12+
httpMethod := "GET"
13+
14+
builder := QueryRequestBuilder{
15+
client: client,
16+
path: path,
17+
httpMethod: httpMethod,
18+
json: nil,
19+
}
20+
21+
if builder.path != path {
22+
t.Errorf("expected path == %s, got %s", path, builder.path)
23+
}
24+
if builder.httpMethod != httpMethod {
25+
t.Errorf("expected httpMethod == %s, got %s", httpMethod, builder.httpMethod)
26+
}
27+
if builder.json != nil {
28+
t.Errorf("expected json == %v, got %v", nil, builder.json)
29+
}
30+
}

0 commit comments

Comments
 (0)