Skip to content

Commit 863eb97

Browse files
authored
Update Completable interface with custom options (#47)
1 parent c1cab59 commit 863eb97

File tree

2 files changed

+59
-88
lines changed

2 files changed

+59
-88
lines changed

completion.go

Lines changed: 46 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,23 @@ import (
1010
"github.com/grafana/grafana-plugin-sdk-go/backend"
1111
)
1212

13+
const (
14+
schemas = "schemas"
15+
tables = "tables"
16+
columns = "columns"
17+
)
18+
1319
// ErrorNotImplemented is returned if the function is not implemented by the provided Driver (the Completable pointer is nil)
1420
var ErrorNotImplemented = errors.New("not implemented")
1521

22+
// Options are used to query schemas, tables and columns. They will be encoded in the request body (e.g. {"database": "mydb"})
23+
type Options map[string]string
24+
1625
// Completable will be used to autocomplete Tables Schemas and Columns for SQL languages
1726
type Completable interface {
18-
Schemas(ctx context.Context) ([]string, error)
19-
Tables(ctx context.Context, schema string) ([]string, error)
20-
Columns(ctx context.Context, table string) ([]string, error)
27+
Schemas(ctx context.Context, options Options) ([]string, error)
28+
Tables(ctx context.Context, options Options) ([]string, error)
29+
Columns(ctx context.Context, options Options) ([]string, error)
2130
}
2231

2332
func handleError(rw http.ResponseWriter, err error) {
@@ -36,74 +45,48 @@ func sendResourceResponse(rw http.ResponseWriter, res []string) {
3645
}
3746
}
3847

39-
type tableRequest struct {
40-
Schema string `json:"schema"`
41-
}
42-
43-
type columnRequest struct {
44-
Table string `json:"table"`
45-
}
46-
47-
func (ds *sqldatasource) getSchemas(rw http.ResponseWriter, req *http.Request) {
48-
if ds.Completable == nil {
49-
handleError(rw, ErrorNotImplemented)
50-
return
51-
}
52-
53-
res, err := ds.Completable.Schemas(req.Context())
54-
if err != nil {
55-
handleError(rw, err)
56-
return
57-
}
58-
59-
sendResourceResponse(rw, res)
60-
}
61-
62-
func (ds *sqldatasource) getTables(rw http.ResponseWriter, req *http.Request) {
63-
if ds.Completable == nil {
64-
handleError(rw, ErrorNotImplemented)
65-
return
66-
}
67-
68-
reqBody := tableRequest{}
69-
if err := json.NewDecoder(req.Body).Decode(&reqBody); err != nil {
70-
handleError(rw, err)
71-
return
72-
}
73-
res, err := ds.Completable.Tables(req.Context(), reqBody.Schema)
74-
if err != nil {
75-
handleError(rw, err)
76-
return
77-
}
48+
func (ds *sqldatasource) getResources(rtype string) func(rw http.ResponseWriter, req *http.Request) {
49+
return func(rw http.ResponseWriter, req *http.Request) {
50+
if ds.Completable == nil {
51+
handleError(rw, ErrorNotImplemented)
52+
return
53+
}
7854

79-
sendResourceResponse(rw, res)
80-
}
55+
options := Options{}
56+
if req.Body != nil {
57+
err := json.NewDecoder(req.Body).Decode(&options)
58+
if err != nil {
59+
handleError(rw, err)
60+
return
61+
}
62+
}
8163

82-
func (ds *sqldatasource) getColumns(rw http.ResponseWriter, req *http.Request) {
83-
if ds.Completable == nil {
84-
handleError(rw, ErrorNotImplemented)
85-
return
86-
}
64+
var res []string
65+
var err error
66+
switch rtype {
67+
case schemas:
68+
res, err = ds.Completable.Schemas(req.Context(), options)
69+
case tables:
70+
res, err = ds.Completable.Tables(req.Context(), options)
71+
case columns:
72+
res, err = ds.Completable.Columns(req.Context(), options)
73+
default:
74+
err = fmt.Errorf("unexpected resource type: %s", rtype)
75+
}
76+
if err != nil {
77+
handleError(rw, err)
78+
return
79+
}
8780

88-
column := columnRequest{}
89-
if err := json.NewDecoder(req.Body).Decode(&column); err != nil {
90-
handleError(rw, err)
91-
return
81+
sendResourceResponse(rw, res)
9282
}
93-
res, err := ds.Completable.Columns(req.Context(), column.Table)
94-
if err != nil {
95-
handleError(rw, err)
96-
return
97-
}
98-
99-
sendResourceResponse(rw, res)
10083
}
10184

10285
func (ds *sqldatasource) registerRoutes(mux *http.ServeMux) error {
10386
defaultRoutes := map[string]func(http.ResponseWriter, *http.Request){
104-
"/tables": ds.getTables,
105-
"/schemas": ds.getSchemas,
106-
"/columns": ds.getColumns,
87+
"/tables": ds.getResources(tables),
88+
"/schemas": ds.getResources(schemas),
89+
"/columns": ds.getResources(columns),
10790
}
10891
for route, handler := range defaultRoutes {
10992
mux.HandleFunc(route, handler)

completion_test.go

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -50,22 +50,22 @@ func Test_sendResourceResponse(t *testing.T) {
5050
}
5151

5252
type fakeCompletable struct {
53-
schemas []string
53+
schemas map[string][]string
5454
tables map[string][]string
5555
columns map[string][]string
5656
err error
5757
}
5858

59-
func (f *fakeCompletable) Schemas(ctx context.Context) ([]string, error) {
60-
return f.schemas, f.err
59+
func (f *fakeCompletable) Schemas(ctx context.Context, options Options) ([]string, error) {
60+
return f.schemas[options["database"]], f.err
6161
}
6262

63-
func (f *fakeCompletable) Tables(ctx context.Context, schema string) ([]string, error) {
64-
return f.tables[schema], f.err
63+
func (f *fakeCompletable) Tables(ctx context.Context, options Options) ([]string, error) {
64+
return f.tables[options["schema"]], f.err
6565
}
6666

67-
func (f *fakeCompletable) Columns(ctx context.Context, table string) ([]string, error) {
68-
return f.columns[table], f.err
67+
func (f *fakeCompletable) Columns(ctx context.Context, options Options) ([]string, error) {
68+
return f.columns[options["table"]], f.err
6969
}
7070

7171
func TestCompletable(t *testing.T) {
@@ -78,21 +78,21 @@ func TestCompletable(t *testing.T) {
7878
}{
7979
{
8080
"it should return schemas",
81-
"schemas",
82-
&fakeCompletable{schemas: []string{"foo", "bar"}},
83-
"",
81+
schemas,
82+
&fakeCompletable{schemas: map[string][]string{"foobar": {"foo", "bar"}}},
83+
`{"database":"foobar"}`,
8484
`["foo","bar"]` + "\n",
8585
},
8686
{
8787
"it should return tables of a schema",
88-
"tables",
88+
tables,
8989
&fakeCompletable{tables: map[string][]string{"foobar": {"foo", "bar"}}},
9090
`{"schema":"foobar"}`,
9191
`["foo","bar"]` + "\n",
9292
},
9393
{
9494
"it should return columns of a table",
95-
"columns",
95+
columns,
9696
&fakeCompletable{columns: map[string][]string{"foobar": {"foo", "bar"}}},
9797
`{"table":"foobar"}`,
9898
`["foo","bar"]` + "\n",
@@ -106,19 +106,7 @@ func TestCompletable(t *testing.T) {
106106
sqlds.Completable = test.fakeImpl
107107

108108
b := ioutil.NopCloser(bytes.NewReader([]byte(test.reqBody)))
109-
switch test.method {
110-
case "schemas":
111-
sqlds.getSchemas(w, &http.Request{})
112-
case "tables":
113-
sqlds.getTables(w, &http.Request{
114-
Body: b,
115-
})
116-
case "columns":
117-
sqlds.getColumns(w, &http.Request{
118-
Body: b,
119-
})
120-
}
121-
109+
sqlds.getResources(test.method)(w, &http.Request{Body: b})
122110
resp := w.Result()
123111
body, _ := io.ReadAll(resp.Body)
124112

0 commit comments

Comments
 (0)