refactor(http/query): update http query logic for new parser API
parent
3660cfc34a
commit
4918b15f35
2
go.mod
2
go.mod
|
@ -79,7 +79,7 @@ require (
|
|||
github.com/hashicorp/vault-plugin-secrets-kv v0.0.0-20181106190520-2236f141171e // indirect
|
||||
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d // indirect
|
||||
github.com/imdario/mergo v0.3.6 // indirect
|
||||
github.com/influxdata/flux v0.12.0
|
||||
github.com/influxdata/flux v0.12.1-0.20190104180637-9c4371ac8c93
|
||||
github.com/influxdata/influxql v0.0.0-20180925231337-1cbfca8e56b6
|
||||
github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368
|
||||
github.com/jefferai/jsonx v0.0.0-20160721235117-9cc31c3135ee // indirect
|
||||
|
|
4
go.sum
4
go.sum
|
@ -240,8 +240,8 @@ github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28=
|
|||
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/influxdata/flux v0.12.0 h1:mI91GHgqb5sbsz9fesvKwbZrh3wpxLKIEeCYswRBh2A=
|
||||
github.com/influxdata/flux v0.12.0/go.mod h1:81jeDcHVn1rN5uj9aQ81S72Q8ol8If7N0zM0G8TnxTE=
|
||||
github.com/influxdata/flux v0.12.1-0.20190104180637-9c4371ac8c93 h1:HYb4I2jH8OrHAZj4bjPLNz9rSSHnWUdphCUNlD75wqo=
|
||||
github.com/influxdata/flux v0.12.1-0.20190104180637-9c4371ac8c93/go.mod h1:81jeDcHVn1rN5uj9aQ81S72Q8ol8If7N0zM0G8TnxTE=
|
||||
github.com/influxdata/goreleaser v0.86.2-0.20181010170531-0fd209ba67f5/go.mod h1:aVuBpDAT5VtjtUxzvBt8HOd0buzvvk7OX3H2iaviixg=
|
||||
github.com/influxdata/influxql v0.0.0-20180925231337-1cbfca8e56b6 h1:CFx+pP90q/qg3spoiZjf8donE4WpAdjeJfPOcoNqkWo=
|
||||
github.com/influxdata/influxql v0.0.0-20180925231337-1cbfca8e56b6/go.mod h1:KpVI7okXjK6PRi3Z5B+mtKZli+R1DnZgb3N+tzevNgo=
|
||||
|
|
|
@ -26,7 +26,7 @@ import (
|
|||
// QueryRequest is a flux query request.
|
||||
type QueryRequest struct {
|
||||
Spec *flux.Spec `json:"spec,omitempty"`
|
||||
AST *ast.Program `json:"ast,omitempty"`
|
||||
AST *ast.Package `json:"ast,omitempty"`
|
||||
Query string `json:"query"`
|
||||
Type string `json:"type"`
|
||||
Dialect QueryDialect `json:"dialect"`
|
||||
|
@ -128,49 +128,26 @@ func (r QueryRequest) Analyze() (*QueryAnalysis, error) {
|
|||
|
||||
func (r QueryRequest) analyzeFluxQuery() (*QueryAnalysis, error) {
|
||||
a := &QueryAnalysis{}
|
||||
_, err := parser.NewAST(r.Query)
|
||||
if err == nil {
|
||||
pkg := parser.ParseSource(r.Query)
|
||||
errCount := ast.Check(pkg)
|
||||
if errCount == 0 {
|
||||
a.Errors = []queryParseError{}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
ms := fluxParseErrorRE.FindAllStringSubmatch(err.Error(), -1)
|
||||
a.Errors = make([]queryParseError, 0, len(ms))
|
||||
for _, m := range ms {
|
||||
if len(m) != 5 {
|
||||
return nil, fmt.Errorf("flux query error is not formatted as expected: got %d matches expected 5", len(m))
|
||||
a.Errors = make([]queryParseError, 0, errCount)
|
||||
ast.Walk(ast.CreateVisitor(func(node ast.Node) {
|
||||
loc := node.Location()
|
||||
for _, err := range node.Errs() {
|
||||
a.Errors = append(a.Errors, queryParseError{
|
||||
Line: loc.Start.Line,
|
||||
Column: loc.Start.Column,
|
||||
Message: err.Msg,
|
||||
})
|
||||
}
|
||||
lineStr := m[1]
|
||||
line, err := strconv.Atoi(lineStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse line number from error mesage: %s -> %v", lineStr, err)
|
||||
}
|
||||
colStr := m[2]
|
||||
col, err := strconv.Atoi(colStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse column number from error mesage: %s -> %v", colStr, err)
|
||||
}
|
||||
charStr := m[3]
|
||||
char, err := strconv.Atoi(charStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse character number from error mesage: %s -> %v", charStr, err)
|
||||
}
|
||||
msg := m[4]
|
||||
|
||||
a.Errors = append(a.Errors, queryParseError{
|
||||
Line: line,
|
||||
Column: col,
|
||||
Character: char,
|
||||
Message: msg,
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
}), pkg)
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var fluxParseErrorRE = regexp.MustCompile(`(\d+):(\d+) \((\d+)\): ([[:graph:] ]+)`)
|
||||
|
||||
func (r QueryRequest) analyzeInfluxQLQuery() (*QueryAnalysis, error) {
|
||||
a := &QueryAnalysis{}
|
||||
_, err := influxql.ParseQuery(r.Query)
|
||||
|
@ -238,7 +215,7 @@ func nowFunc(now time.Time) values.Function {
|
|||
return values.NewFunction("now", ftype, call, sideEffect)
|
||||
}
|
||||
|
||||
func toSpec(p *ast.Program, now func() time.Time) (*flux.Spec, error) {
|
||||
func toSpec(p *ast.Package, now func() time.Time) (*flux.Spec, error) {
|
||||
itrp := flux.NewInterpreter()
|
||||
itrp.SetOption("now", nowFunc(now()))
|
||||
semProg, err := semantic.New(p)
|
||||
|
|
|
@ -98,7 +98,7 @@ type langRequest struct {
|
|||
}
|
||||
|
||||
type postFluxASTResponse struct {
|
||||
AST *ast.Program `json:"ast"`
|
||||
AST *ast.Package `json:"ast"`
|
||||
}
|
||||
|
||||
// postFluxAST returns a flux AST for provided flux string
|
||||
|
@ -112,14 +112,15 @@ func (h *FluxHandler) postFluxAST(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
ast, err := parser.NewAST(request.Query)
|
||||
if err != nil {
|
||||
pkg := parser.ParseSource(request.Query)
|
||||
if ast.Check(pkg) > 0 {
|
||||
err := ast.GetError(pkg)
|
||||
EncodeError(ctx, errors.InvalidDataf("invalid AST: %v", err), w)
|
||||
return
|
||||
}
|
||||
|
||||
res := postFluxASTResponse{
|
||||
AST: ast,
|
||||
AST: pkg,
|
||||
}
|
||||
|
||||
if err := encodeResponse(ctx, w, http.StatusOK, res); err != nil {
|
||||
|
|
|
@ -202,7 +202,7 @@ func TestFluxHandler_postFluxAST(t *testing.T) {
|
|||
name: "get ast from()",
|
||||
w: httptest.NewRecorder(),
|
||||
r: httptest.NewRequest("POST", "/api/v2/query/ast", bytes.NewBufferString(`{"query": "from()"}`)),
|
||||
want: `{"ast":{"type":"Program","location":{"start":{"line":1,"column":1},"end":{"line":1,"column":7},"source":"from()"},"package":null,"imports":null,"body":[{"type":"ExpressionStatement","location":{"start":{"line":1,"column":1},"end":{"line":1,"column":7},"source":"from()"},"expression":{"type":"CallExpression","location":{"start":{"line":1,"column":1},"end":{"line":1,"column":7},"source":"from()"},"callee":{"type":"Identifier","location":{"start":{"line":1,"column":1},"end":{"line":1,"column":5},"source":"from"},"name":"from"}}}]}}
|
||||
want: `{"ast":{"type":"Package","package":"main","files":[{"type":"File","location":{"start":{"line":1,"column":1},"end":{"line":1,"column":7},"source":"from()"},"package":null,"imports":null,"body":[{"type":"ExpressionStatement","location":{"start":{"line":1,"column":1},"end":{"line":1,"column":7},"source":"from()"},"expression":{"type":"CallExpression","location":{"start":{"line":1,"column":1},"end":{"line":1,"column":7},"source":"from()"},"callee":{"type":"Identifier","location":{"start":{"line":1,"column":1},"end":{"line":1,"column":5},"source":"from"},"name":"from"}}}]}]}}
|
||||
`,
|
||||
status: http.StatusOK,
|
||||
},
|
||||
|
|
|
@ -24,7 +24,7 @@ import (
|
|||
func TestQueryRequest_WithDefaults(t *testing.T) {
|
||||
type fields struct {
|
||||
Spec *flux.Spec
|
||||
AST *ast.Program
|
||||
AST *ast.Package
|
||||
Query string
|
||||
Type string
|
||||
Dialect QueryDialect
|
||||
|
@ -67,7 +67,7 @@ func TestQueryRequest_WithDefaults(t *testing.T) {
|
|||
func TestQueryRequest_Validate(t *testing.T) {
|
||||
type fields struct {
|
||||
Spec *flux.Spec
|
||||
AST *ast.Program
|
||||
AST *ast.Package
|
||||
Query string
|
||||
Type string
|
||||
Dialect QueryDialect
|
||||
|
@ -181,7 +181,7 @@ func TestQueryRequest_Validate(t *testing.T) {
|
|||
|
||||
func Test_toSpec(t *testing.T) {
|
||||
type args struct {
|
||||
p *ast.Program
|
||||
p *ast.Package
|
||||
now func() time.Time
|
||||
}
|
||||
tests := []struct {
|
||||
|
@ -193,7 +193,7 @@ func Test_toSpec(t *testing.T) {
|
|||
{
|
||||
name: "ast converts to spec",
|
||||
args: args{
|
||||
p: &ast.Program{},
|
||||
p: &ast.Package{},
|
||||
now: func() time.Time { return time.Unix(0, 0) },
|
||||
},
|
||||
want: &flux.Spec{
|
||||
|
@ -203,10 +203,12 @@ func Test_toSpec(t *testing.T) {
|
|||
{
|
||||
name: "bad semantics error",
|
||||
args: args{
|
||||
p: &ast.Program{
|
||||
Body: []ast.Statement{
|
||||
&ast.ReturnStatement{},
|
||||
},
|
||||
p: &ast.Package{
|
||||
Files: []*ast.File{{
|
||||
Body: []ast.Statement{
|
||||
&ast.ReturnStatement{},
|
||||
},
|
||||
}},
|
||||
},
|
||||
now: func() time.Time { return time.Unix(0, 0) },
|
||||
},
|
||||
|
@ -231,7 +233,7 @@ func Test_toSpec(t *testing.T) {
|
|||
func TestQueryRequest_proxyRequest(t *testing.T) {
|
||||
type fields struct {
|
||||
Spec *flux.Spec
|
||||
AST *ast.Program
|
||||
AST *ast.Package
|
||||
Query string
|
||||
Type string
|
||||
Dialect QueryDialect
|
||||
|
@ -279,7 +281,7 @@ func TestQueryRequest_proxyRequest(t *testing.T) {
|
|||
{
|
||||
name: "valid AST",
|
||||
fields: fields{
|
||||
AST: &ast.Program{},
|
||||
AST: &ast.Package{},
|
||||
Type: "flux",
|
||||
Dialect: QueryDialect{
|
||||
Delimiter: ",",
|
||||
|
|
Loading…
Reference in New Issue