Skip to content

Commit

Permalink
Add basic auto-completion support (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
flobernd authored May 15, 2023
1 parent f7a3907 commit 60677d1
Show file tree
Hide file tree
Showing 8 changed files with 816 additions and 46 deletions.
7 changes: 3 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,23 @@ module github.com/sneller-inc/sneller
go 1.19

require (
github.com/SnellerInc/sneller v0.0.0-20230505151417-5806cd3a42c7
github.com/grafana/grafana-plugin-sdk-go v0.159.0
github.com/patrickmn/go-cache v2.1.0+incompatible
go.opentelemetry.io/otel v1.14.0
go.opentelemetry.io/otel/trace v1.14.0
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53
)

require (
github.com/BurntSushi/toml v1.2.1 // indirect
github.com/SnellerInc/sneller v0.0.0-20230505151417-5806cd3a42c7 // indirect
github.com/apache/arrow/go/arrow v0.0.0-20211112161151-bc219186db40 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cenkalti/backoff/v4 v4.2.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cheekybits/genny v1.0.0 // indirect
github.com/chromedp/cdproto v0.0.0-20220208224320-6efb837e6bc2 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/dchest/siphash v1.2.3 // indirect
github.com/elazarl/goproxy v0.0.0-20220115173737-adb46da277ac // indirect
github.com/fatih/color v1.7.0 // indirect
github.com/getkin/kin-openapi v0.112.0 // indirect
Expand Down Expand Up @@ -73,8 +74,6 @@ require (
go.opentelemetry.io/otel/metric v0.37.0 // indirect
go.opentelemetry.io/otel/sdk v1.14.0 // indirect
go.opentelemetry.io/proto/otlp v0.19.0 // indirect
golang.org/x/crypto v0.8.0 // indirect
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 // indirect
golang.org/x/net v0.9.0 // indirect
golang.org/x/sys v0.7.0 // indirect
golang.org/x/text v0.9.0 // indirect
Expand Down
6 changes: 2 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE
github.com/SnellerInc/sneller v0.0.0-20230505151417-5806cd3a42c7 h1:3GAYAlEQoiW3q8x88cbi140EM1p3g8vBHxqWS75Oro8=
github.com/SnellerInc/sneller v0.0.0-20230505151417-5806cd3a42c7/go.mod h1:BaisUxgu4MI9tL6dwYPccGKsXkBP7+BnMz8fL/F/TNk=
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
github.com/amazon-ion/ion-go v1.2.0 h1:EgFy23/7gRxRYdUkJARh/7eZc8BYkFFDZZSqB3PwVqQ=
github.com/amazon-ion/ion-go v1.2.0/go.mod h1:3ZEje8i20TiIPVZlN+KE3B2ppZ1B8d9F/KaT7Dtec+k=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/apache/arrow/go/arrow v0.0.0-20211112161151-bc219186db40 h1:q4dksr6ICHXqG5hm0ZW5IHyeEJXoIJSOZeBLmWPNeIQ=
github.com/apache/arrow/go/arrow v0.0.0-20211112161151-bc219186db40/go.mod h1:Q7yQnSMnLvcXlZ8RV+jwz/6y1rQTqbX6C82SndT52Zs=
Expand Down Expand Up @@ -83,7 +81,6 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dchest/siphash v1.2.3 h1:QXwFc8cFOR2dSa/gE6o/HokBMWtLUaNDVd+22aKHeEA=
github.com/dchest/siphash v1.2.3/go.mod h1:0NvQU092bT0ipiFN++/rXm69QG9tVxLAlQHIXMPAkHc=
github.com/elazarl/goproxy v0.0.0-20220115173737-adb46da277ac h1:XDAn206aIqKPdF5YczuuJXSQPx+WOen0Pxbxp5Fq8Pg=
github.com/elazarl/goproxy v0.0.0-20220115173737-adb46da277ac/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
Expand Down Expand Up @@ -274,6 +271,8 @@ github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQ
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY=
github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
github.com/pierrec/lz4/v4 v4.1.8 h1:ieHkV+i2BRzngO4Wd/3HGowuZStgq6QkPsD1eolNAO4=
Expand Down Expand Up @@ -372,7 +371,6 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ=
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@
"sass-loader": "13.2.0",
"style-loader": "3.3.1",
"swc-loader": "^0.2.3",
"tsconfig-paths": "^4.1.0",
"ts-node": "^10.5.0",
"tsconfig-paths": "^4.1.0",
"typescript": "^4.4.0",
"webpack": "^5.69.1",
"webpack-cli": "^4.9.2",
Expand All @@ -59,6 +59,7 @@
"dependencies": {
"@emotion/css": "^11.1.3",
"@grafana/data": "9.3.8",
"@grafana/experimental": "^1.1.0",
"@grafana/runtime": "9.3.8",
"@grafana/ui": "9.3.8",
"react": "17.0.2",
Expand Down
65 changes: 65 additions & 0 deletions pkg/plugin/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@ import (
"io"
"net/http"
"strings"
"time"

"github.com/SnellerInc/sneller/ion"
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
"golang.org/x/exp/maps"
)

// executeQuery executes a Sneller query and returns the HTTP response.
Expand All @@ -21,6 +24,12 @@ func (d *Datasource) executeQuery(ctx context.Context, database, sql string) (*h

// getDatabases returns a list of database names.
func (d *Datasource) getDatabases(ctx context.Context) ([]string, int, error) {
key := "databases"
cached, found := d.cache.Get(key)
if found {
return cached.([]string), 0, nil
}

resp, err := d.executeRequest(ctx, http.MethodGet, "/databases", nil,
map[string]string{"Accept": "application/json"},
nil)
Expand Down Expand Up @@ -48,11 +57,19 @@ func (d *Datasource) getDatabases(ctx context.Context) ([]string, int, error) {
return t.Name
})

d.cache.Set(key, names, time.Minute*1)

return names, 0, nil
}

// getTables returns a list of table names for the given database.
func (d *Datasource) getTables(ctx context.Context, database string) ([]string, int, error) {
key := fmt.Sprintf("tables_%s", database)
cached, found := d.cache.Get(key)
if found {
return cached.([]string), 0, nil
}

resp, err := d.executeRequest(ctx, http.MethodGet, "/tables", nil,
map[string]string{"Accept": "application/json"},
map[string]string{"database": database})
Expand All @@ -76,9 +93,57 @@ func (d *Datasource) getTables(ctx context.Context, database string) ([]string,
return nil, 500, err
}

d.cache.Set(key, result, time.Minute*1)

return result, 0, nil
}

// getColumns returns a list of column names for the given database and table.
func (d *Datasource) getColumns(ctx context.Context, database, table string) ([]string, int, error) {
key := fmt.Sprintf("columns_%s_%s", database, table)
cached, found := d.cache.Get(key)
if found {
return cached.([]string), 0, nil
}

resp, err := d.executeQuery(ctx, database, fmt.Sprintf(`SELECT SNELLER_DATASHAPE(*) FROM (SELECT * FROM %q LIMIT 1000)`, table))
if err != nil {
if resp != nil {
return nil, resp.StatusCode, err
}
return nil, 500, err
}

defer func() {
if err := resp.Body.Close(); err != nil {
log.DefaultLogger.Error("failed to close response body", "err", err)
}
}()

payload := map[string]any{}

err = ion.NewDecoder(resp.Body, 1024*1024*10).Decode(&payload)
if err != nil {
return nil, 500, err
}

fields, ok := payload["fields"]
if !ok {
return []string{}, 0, nil
}

vals, ok := fields.(map[string]any)
if !ok {
return []string{}, 0, nil
}

cols := maps.Keys(vals)

d.cache.Set(key, cols, time.Minute*1)

return cols, 0, nil
}

// newRequest creates a new HTTP request and initializes the 'Authentication' header from the
// configured Sneller authentication token in the 'Authentication' header.
func (d *Datasource) newRequest(ctx context.Context, method, path string, body io.Reader) (*http.Request, error) {
Expand Down
33 changes: 33 additions & 0 deletions pkg/plugin/datasource.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
"github.com/grafana/grafana-plugin-sdk-go/backend/tracing"
"github.com/grafana/grafana-plugin-sdk-go/data"
cache "github.com/patrickmn/go-cache"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
)
Expand Down Expand Up @@ -58,6 +59,7 @@ func NewDatasource(settings backend.DataSourceInstanceSettings) (instancemgmt.In
settings: settings,
endpoint: jsonData.Endpoint,
client: client,
cache: cache.New(5*time.Minute, 5*time.Minute),
}

mux := datasource.NewQueryTypeMux()
Expand All @@ -76,6 +78,7 @@ type Datasource struct {
handler backend.QueryDataHandler
endpoint string
client *http.Client
cache *cache.Cache
}

// Dispose here tells plugin SDK that plugin wants to clean up resources when a new instance
Expand Down Expand Up @@ -154,6 +157,13 @@ func (d *Datasource) CallResource(ctx context.Context, req *backend.CallResource
})
}
return sender.Send(d.handleCallResourceTables(ctx, segments[1]))
case "columns":
if len(segments) != 3 {
return sender.Send(&backend.CallResourceResponse{
Status: http.StatusBadRequest,
})
}
return sender.Send(d.handleCallResourceColumns(ctx, segments[1], segments[2]))
default:
return sender.Send(&backend.CallResourceResponse{
Status: http.StatusNotFound,
Expand Down Expand Up @@ -203,6 +213,27 @@ func (d *Datasource) handleCallResourceTables(ctx context.Context, database stri
}
}

func (d *Datasource) handleCallResourceColumns(ctx context.Context, database, table string) *backend.CallResourceResponse {
databases, status, err := d.getColumns(ctx, database, table)
if err != nil {
return &backend.CallResourceResponse{
Status: status,
Body: []byte(err.Error()),
}
}
result, err := json.Marshal(databases)
if err != nil {
return &backend.CallResourceResponse{
Status: status,
Body: []byte(err.Error()),
}
}
return &backend.CallResourceResponse{
Status: http.StatusOK,
Body: result,
}
}

func (d *Datasource) handleQuery(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
response := backend.NewQueryDataResponse()

Expand Down Expand Up @@ -274,6 +305,8 @@ func (d *Datasource) query(ctx context.Context, _ backend.PluginContext, query b
switch resp.StatusCode {
case http.StatusUnauthorized:
return backend.ErrDataResponse(backend.StatusUnauthorized, fmt.Sprintf("unauthorized: %s", err))
case http.StatusForbidden:
return backend.ErrDataResponse(backend.StatusForbidden, fmt.Sprintf("forbidden: %s", err))
case http.StatusBadRequest:
return backend.ErrDataResponse(backend.StatusValidationFailed, fmt.Sprintf("bad request: %s", err))
}
Expand Down
Loading

0 comments on commit 60677d1

Please sign in to comment.