diff --git a/.github/workflows/golangci.yml b/.github/workflows/golangci.yml index ff7b04c..2410078 100644 --- a/.github/workflows/golangci.yml +++ b/.github/workflows/golangci.yml @@ -8,10 +8,10 @@ jobs: build: runs-on: ubuntu-latest steps: - - name: Set up Go 1.16 + - name: Set up Go 1.19 uses: actions/setup-go@v2 with: - go-version: 1.16 + go-version: 1.19 id: go - name: Check out code into the Go module directory uses: actions/checkout@v2 diff --git a/.github/workflows/reviewdog.yml b/.github/workflows/reviewdog.yml index fb2cb65..d5e4292 100644 --- a/.github/workflows/reviewdog.yml +++ b/.github/workflows/reviewdog.yml @@ -10,6 +10,6 @@ jobs: - name: Set up Go uses: actions/setup-go@v2 with: - go-version: '1.16' + go-version: '1.19' - name: golangci-lint uses: reviewdog/action-golangci-lint@v1 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..a272c6b --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,16 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.3.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-added-large-files + - repo: https://github.com/dnephin/pre-commit-golang + rev: v0.5.0 + hooks: + - id: go-fmt + - id: go-imports + - id: no-go-testing + - id: golangci-lint + - id: go-unit-tests \ No newline at end of file diff --git a/README.md b/README.md index 6e9e751..ef2e5d3 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Full documentation can be found [here](https://pkg.go.dev/github.com/supabase/po Install ```bash -go get github.com/supabase/postgrest-go +go get github.com/supabase-community/postgrest-go ``` Usage diff --git a/client.go b/client.go index 8cc0ae4..2cc0496 100644 --- a/client.go +++ b/client.go @@ -61,17 +61,20 @@ func (c *Client) Ping() bool { req, err := http.NewRequest("GET", path.Join(c.clientTransport.baseURL.Path, ""), nil) if err != nil { c.ClientError = err + return false } resp, err := c.session.Do(req) if err != nil { c.ClientError = err + return false } if resp.Status != "200 OK" { c.ClientError = errors.New("ping failed") + return false } @@ -157,6 +160,7 @@ func (t transport) RoundTrip(req *http.Request) (*http.Response, error) { req.Header.Add(headerName, val) } } + req.URL = t.baseURL.ResolveReference(req.URL) return http.DefaultTransport.RoundTrip(req) } diff --git a/execute.go b/execute.go index a255113..56ab3e7 100644 --- a/execute.go +++ b/execute.go @@ -3,6 +3,7 @@ package postgrest import ( "bytes" "encoding/json" + "errors" "fmt" "io" "net/http" @@ -33,7 +34,7 @@ func executeHelper(client *Client, method string, body []byte, urlFragments []st baseUrl := path.Join(append([]string{client.clientTransport.baseURL.Path}, urlFragments...)...) req, err := http.NewRequest(method, baseUrl, readerBody) if err != nil { - return nil, 0, err + return nil, 0, fmt.Errorf("error creating request: %s", err.Error()) } for key, val := range headers { @@ -49,7 +50,7 @@ func executeHelper(client *Client, method string, body []byte, urlFragments []st return nil, 0, err } - respbody, err := io.ReadAll(resp.Body) + respBody, err := io.ReadAll(resp.Body) if err != nil { return nil, 0, err } @@ -57,9 +58,9 @@ func executeHelper(client *Client, method string, body []byte, urlFragments []st // https://postgrest.org/en/stable/api.html#errors-and-http-status-codes if resp.StatusCode >= 400 { var errmsg *ExecuteError - err := json.Unmarshal(respbody, &errmsg) + err := json.Unmarshal(respBody, &errmsg) if err != nil { - return nil, 0, err + return nil, 0, fmt.Errorf("error parsing error response: %s", err.Error()) } return nil, 0, fmt.Errorf("(%s) %s", errmsg.Code, errmsg.Message) } @@ -72,17 +73,17 @@ func executeHelper(client *Client, method string, body []byte, urlFragments []st if len(split) > 1 && split[1] != "*" { count, err = strconv.ParseInt(split[1], 0, 64) if err != nil { - return nil, 0, err + return nil, 0, fmt.Errorf("error parsing count from Content-Range header: %s", err.Error()) } } } err = resp.Body.Close() if err != nil { - return nil, 0, err + return nil, 0, errors.New("error closing response body") } - return respbody, count, nil + return respBody, count, nil } func executeString(client *Client, method string, body []byte, urlFragments []string, headers map[string]string, params map[string]string) (string, countType, error) { diff --git a/export_test.go b/export_test.go index d91710a..0326e28 100644 --- a/export_test.go +++ b/export_test.go @@ -12,7 +12,7 @@ const apiKeyEnv = "API_KEY" // If false, mock responses with httpmock. If true, use POSTGREST_URL (and // optionally, API_KEY for Supabase), to run tests against an actual Postgres // instance. -var mockResponses bool = false +var mockResponses = false var mockPath *regexp.Regexp diff --git a/filterbuilder.go b/filterbuilder.go index 32dc5ab..adcb826 100644 --- a/filterbuilder.go +++ b/filterbuilder.go @@ -20,12 +20,12 @@ type FilterBuilder struct { // ExecuteString runs the PostgREST query, returning the result as a JSON // string. -func (f *FilterBuilder) ExecuteString() (string, countType, error) { +func (f *FilterBuilder) ExecuteString() (string, int64, error) { return executeString(f.client, f.method, f.body, []string{f.tableName}, f.headers, f.params) } // Execute runs the PostgREST query, returning the result as a byte slice. -func (f *FilterBuilder) Execute() ([]byte, countType, error) { +func (f *FilterBuilder) Execute() ([]byte, int64, error) { return execute(f.client, f.method, f.body, []string{f.tableName}, f.headers, f.params) } @@ -237,7 +237,7 @@ var DefaultOrderOpts = OrderOpts{ ForeignTable: "", } -// Limits the result to the specified count. +// Limit the result to the specified count. func (f *FilterBuilder) Limit(count int, foreignTable string) *FilterBuilder { if foreignTable != "" { f.params[foreignTable+".limit"] = strconv.Itoa(count) @@ -248,7 +248,7 @@ func (f *FilterBuilder) Limit(count int, foreignTable string) *FilterBuilder { return f } -// Orders the result with the specified column. A pointer to an OrderOpts +// Order the result with the specified column. A pointer to an OrderOpts // object can be supplied to specify ordering options. func (f *FilterBuilder) Order(column string, opts *OrderOpts) *FilterBuilder { if opts == nil { @@ -280,7 +280,7 @@ func (f *FilterBuilder) Order(column string, opts *OrderOpts) *FilterBuilder { return f } -// Limits the result to rows within the specified range, inclusive. +// Range Limits the result to rows within the specified range, inclusive. func (f *FilterBuilder) Range(from, to int, foreignTable string) *FilterBuilder { if foreignTable != "" { f.params[foreignTable+".offset"] = strconv.Itoa(from) @@ -292,7 +292,7 @@ func (f *FilterBuilder) Range(from, to int, foreignTable string) *FilterBuilder return f } -// Retrieves only one row from the result. The total result set must be one row +// Single Retrieves only one row from the result. The total result set must be one row // (e.g., by using Limit). Otherwise, this will result in an error. func (f *FilterBuilder) Single() *FilterBuilder { f.headers["Accept"] = "application/vnd.pgrst.object+json" diff --git a/querybuilder.go b/querybuilder.go index 592581c..08ae536 100644 --- a/querybuilder.go +++ b/querybuilder.go @@ -18,19 +18,19 @@ type QueryBuilder struct { // ExecuteString runs the Postgrest query, returning the result as a JSON // string. -func (q *QueryBuilder) ExecuteString() (string, countType, error) { +func (q *QueryBuilder) ExecuteString() (string, int64, error) { return executeString(q.client, q.method, q.body, []string{q.tableName}, q.headers, q.params) } // Execute runs the Postgrest query, returning the result as a byte slice. -func (q *QueryBuilder) Execute() ([]byte, countType, error) { +func (q *QueryBuilder) Execute() ([]byte, int64, error) { return execute(q.client, q.method, q.body, []string{q.tableName}, q.headers, q.params) } // ExecuteTo runs the Postgrest query, encoding the result to the supplied // interface. Note that the argument for the to parameter should always be a // reference to a slice. -func (q *QueryBuilder) ExecuteTo(to interface{}) (countType, error) { +func (q *QueryBuilder) ExecuteTo(to interface{}) (int64, error) { return executeTo(q.client, q.method, q.body, to, []string{q.tableName}, q.headers, q.params) } @@ -46,7 +46,7 @@ func (q *QueryBuilder) Select(columns, count string, head bool) *FilterBuilder { q.params["select"] = "*" } else { quoted := false - var resultArr = []string{} + var resultArr []string for _, char := range strings.Split(columns, "") { if char == `"` { quoted = !quoted @@ -79,7 +79,7 @@ func (q *QueryBuilder) Insert(value interface{}, upsert bool, onConflict, return q.params["on_conflict"] = onConflict } - headerList := []string{} + var headerList []string if upsert { headerList = append(headerList, "resolution=merge-duplicates") } diff --git a/querybuilder_test.go b/querybuilder_test.go index fc2f51c..6b69660 100644 --- a/querybuilder_test.go +++ b/querybuilder_test.go @@ -14,11 +14,11 @@ func TestNewClient(t *testing.T) { } func TestSelect(t *testing.T) { - assert := assert.New(t) + assertions := assert.New(t) c := createClient(t) t.Run("ValidResult", func(t *testing.T) { - got := []map[string]interface{}{} + var got []map[string]interface{} if mockResponses { httpmock.Activate() @@ -29,16 +29,16 @@ func TestSelect(t *testing.T) { } bs, count, err := c.From("users").Select("id, name, email", "", false).Execute() - assert.NoError(err) + assertions.NoError(err) err = json.Unmarshal(bs, &got) - assert.NoError(err) - assert.EqualValues(users, got) - assert.Equal(countType(0), count) + assertions.NoError(err) + assertions.EqualValues(users, got) + assertions.Equal(countType(0), count) }) t.Run("WithCount", func(t *testing.T) { - got := []map[string]interface{}{} + var got []map[string]interface{} if mockResponses { httpmock.Activate() @@ -53,17 +53,17 @@ func TestSelect(t *testing.T) { } bs, count, err := c.From("users").Select("id, name, email", "exact", false).Execute() - assert.NoError(err) + assertions.NoError(err) err = json.Unmarshal(bs, &got) - assert.NoError(err) - assert.EqualValues(users, got) - assert.Equal(countType(2), count) + assertions.NoError(err) + assertions.EqualValues(users, got) + assertions.Equal(countType(2), count) }) } func TestFilter(t *testing.T) { - assert := assert.New(t) + assertions := assert.New(t) c := createClient(t) t.Run("Eq", func(t *testing.T) { @@ -77,7 +77,7 @@ func TestFilter(t *testing.T) { } got, _, err := c.From("users").Select("email", "", false).Eq("email", "patti@test.com").ExecuteString() - assert.NoError(err) - assert.Equal(want, got) + assertions.NoError(err) + assertions.Equal(want, got) }) } diff --git a/test/basic/main.go b/test/basic/main.go index 3c63920..844c35b 100644 --- a/test/basic/main.go +++ b/test/basic/main.go @@ -19,11 +19,10 @@ var ( func main() { client := postgrest.NewClient(RestUrl, schema, headers) - res, count, err := client.From("todos").Select("id,task,done", "", false).Eq("task", "that created from postgrest-go").Execute() + res, _, err := client.From("actor").Select("actor_id,first_name", "", false).ExecuteString() if err != nil { panic(err) } fmt.Println(res) - fmt.Printf("count: %v", count) }