Skip to content

Commit

Permalink
feat: add initial support for reference tables (#196)
Browse files Browse the repository at this point in the history
  • Loading branch information
obs-gh-abhinavpappu authored Feb 10, 2025
1 parent 5cce6a9 commit 2613a7a
Show file tree
Hide file tree
Showing 20 changed files with 1,053 additions and 76 deletions.
56 changes: 56 additions & 0 deletions client/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"time"

"github.com/observeinc/terraform-provider-observe/client/meta"
"github.com/observeinc/terraform-provider-observe/client/rest"
)

var (
Expand Down Expand Up @@ -1471,3 +1472,58 @@ func (c *Client) GetIngestInfo(ctx context.Context) (*meta.IngestInfo, error) {
func (c *Client) GetCloudInfo(ctx context.Context) (*meta.CloudInfo, error) {
return c.Meta.GetCloudInfo(ctx)
}

func (c *Client) CreateReferenceTable(ctx context.Context, input *rest.ReferenceTableInput) (*rest.ReferenceTable, error) {
if !c.Flags[flagObs2110] {
c.obs2110.Lock()
defer c.obs2110.Unlock()
}
result, err := c.Rest.CreateReferenceTable(ctx, input)
if err != nil {
return nil, err
}

return result, nil
}

func (c *Client) UpdateReferenceTable(ctx context.Context, id string, input *rest.ReferenceTableInput) (*rest.ReferenceTable, error) {
if !c.Flags[flagObs2110] {
c.obs2110.Lock()
defer c.obs2110.Unlock()
}
result, err := c.Rest.UpdateReferenceTable(ctx, id, input)
if err != nil {
return nil, err
}

return result, nil
}

func (c *Client) UpdateReferenceTableMetadata(ctx context.Context, id string, input *rest.ReferenceTableMetadataInput) (*rest.ReferenceTable, error) {
if !c.Flags[flagObs2110] {
c.obs2110.Lock()
defer c.obs2110.Unlock()
}
result, err := c.Rest.UpdateReferenceTableMetadata(ctx, id, input)
if err != nil {
return nil, err
}

return result, nil
}

func (c *Client) DeleteReferenceTable(ctx context.Context, id string) error {
if !c.Flags[flagObs2110] {
c.obs2110.Lock()
defer c.obs2110.Unlock()
}
return c.Rest.DeleteReferenceTable(ctx, id)
}

func (c *Client) GetReferenceTable(ctx context.Context, id string) (*rest.ReferenceTable, error) {
return c.Rest.GetReferenceTable(ctx, id)
}

func (c *Client) LookupReferenceTable(ctx context.Context, label string) (*rest.ReferenceTable, error) {
return c.Rest.LookupReferenceTable(ctx, label)
}
18 changes: 9 additions & 9 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import (
"time"

"github.com/observeinc/terraform-provider-observe/client/internal/collect"
"github.com/observeinc/terraform-provider-observe/client/internal/customer"
"github.com/observeinc/terraform-provider-observe/client/meta"
"github.com/observeinc/terraform-provider-observe/client/rest"
)

// RoundTripperFunc implements http.RoundTripper
Expand All @@ -32,9 +32,9 @@ type Client struct {
// our API does not allow concurrent FK creation, so we use a lock as a workaround
obs2110 sync.Mutex

Meta *meta.Client
Customer *customer.Client
Collect *collect.Client
Meta *meta.Client
Rest *rest.Client
Collect *collect.Client
}

// login to retrieve a valid token, only need to do this once
Expand All @@ -44,7 +44,7 @@ func (c *Client) loginOnFirstRun(ctx context.Context) (loginErr error) {
ctx = setSensitive(ctx, true)
ctx = requireAuth(ctx, false)

token, err := c.Customer.Login(ctx, *c.UserEmail, *c.UserPassword)
token, err := c.Rest.Login(ctx, *c.UserEmail, *c.UserPassword)
if err != nil {
loginErr = fmt.Errorf("failed to retrieve token: %w", err)
} else {
Expand Down Expand Up @@ -174,10 +174,10 @@ func New(c *Config) (*Client, error) {
}

client := &Client{
Config: c,
Meta: metaAPI,
Customer: customer.New(customerURL, httpClient),
Collect: collectAPI,
Config: c,
Meta: metaAPI,
Rest: rest.New(customerURL, httpClient),
Collect: collectAPI,
}

httpClient.Transport = client.withMiddleware(transport)
Expand Down
66 changes: 0 additions & 66 deletions client/internal/customer/client.go

This file was deleted.

1 change: 1 addition & 0 deletions client/oid/oid.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ const (
TypeRbacStatement Type = "rbacstatement"
TypeSnowflakeOutboundShare Type = "snowflakeoutboundshare"
TypeDatasetOutboundShare Type = "datasetoutboundshare"
TypeReferenceTable Type = "referencetable"
)

func (t Type) IsValid() bool {
Expand Down
120 changes: 120 additions & 0 deletions client/rest/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package rest

import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"strings"

"net/http"
)

// Client implements our RESTful customer API
type Client struct {
endpoint string
httpClient *http.Client
}

// do is a helper to run HTTP request for a JSON API
func (c *Client) do(ctx context.Context, method string, path string, body map[string]interface{}, result interface{}) error {
var (
endpoint = fmt.Sprintf("%s%s", c.endpoint, path)
reqBody io.Reader
)

if body != nil {
data, err := json.Marshal(body)
if err != nil {
return fmt.Errorf("failed to marshal request body: %w", err)
}
reqBody = bytes.NewBuffer(data)
}

req, err := http.NewRequestWithContext(ctx, method, endpoint, reqBody)
if err != nil {
return fmt.Errorf("failed to create request: %w", err)
}

req.Header.Set("Content-Type", "application/json")

resp, err := c.httpClient.Do(req)
if err != nil {
return fmt.Errorf("request failed: %w", err)
}

defer resp.Body.Close()
switch resp.StatusCode {
case http.StatusOK:
default:
return fmt.Errorf(strings.ToLower(http.StatusText(resp.StatusCode)))
}
decoder := json.NewDecoder(resp.Body)
if err := decoder.Decode(&result); err != nil {
return fmt.Errorf("error decoding response: %w", err)
}
return nil
}

type errorResponse struct {
Message string `json:"message"`
}

func responseWrapper(resp *http.Response, err error) (*http.Response, error) {
if err != nil {
return nil, err
}
if !(resp.StatusCode >= 200 && resp.StatusCode < 300) {
defer resp.Body.Close()
var errResponse errorResponse
if err := json.NewDecoder(resp.Body).Decode(&errResponse); err != nil {
return nil, fmt.Errorf("got status code %d, but failed to decode error message: %w", resp.StatusCode, err)
}
return nil, ErrorWithStatusCode{StatusCode: resp.StatusCode, Err: errors.New(errResponse.Message)}
}
return resp, nil
}

func (c *Client) Post(path string, contentType string, body io.Reader) (*http.Response, error) {
return responseWrapper(c.httpClient.Post(c.endpoint+path, contentType, body))
}

func (c *Client) Get(path string) (*http.Response, error) {
return responseWrapper(c.httpClient.Get(c.endpoint + path))
}

func (c *Client) Put(path string, contentType string, body io.Reader) (*http.Response, error) {
req, err := http.NewRequest("PUT", c.endpoint+path, body)
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", contentType)
return responseWrapper(c.httpClient.Do(req))
}

func (c *Client) Patch(path string, contentType string, body io.Reader) (*http.Response, error) {
req, err := http.NewRequest("PATCH", c.endpoint+path, body)
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", contentType)
return responseWrapper(c.httpClient.Do(req))
}

func (c *Client) Delete(path string) (*http.Response, error) {
req, err := http.NewRequest("DELETE", c.endpoint+path, nil)
if err != nil {
return nil, err
}
return responseWrapper(c.httpClient.Do(req))
}

// New returns client to customer API
func New(endpoint string, client *http.Client) *Client {
return &Client{
endpoint: endpoint,
httpClient: client,
}
}
25 changes: 25 additions & 0 deletions client/rest/helpers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package rest

import (
"fmt"
"net/http"
)

type ErrorWithStatusCode struct {
StatusCode int
Err error
}

func (e ErrorWithStatusCode) Error() string {
return fmt.Sprintf("%s (%d): %s", http.StatusText(e.StatusCode), e.StatusCode, e.Err.Error())
}

func HasStatusCode(err error, code int) bool {
if err == nil {
return false
}
if errWithStatusCode, ok := err.(ErrorWithStatusCode); ok {
return errWithStatusCode.StatusCode == code
}
return false
}
2 changes: 1 addition & 1 deletion client/internal/customer/login.go → client/rest/login.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package customer
package rest

import (
"context"
Expand Down
Loading

0 comments on commit 2613a7a

Please sign in to comment.