feat(influxdb): add query part definitions

This commit is contained in:
bergquist 2016-10-05 16:59:33 +02:00
parent 8588bb386c
commit 9968fa5bc5
4 changed files with 88 additions and 56 deletions

View File

@ -1,6 +1,10 @@
package influxdb package influxdb
import "github.com/grafana/grafana/pkg/components/simplejson" import (
"strconv"
"github.com/grafana/grafana/pkg/components/simplejson"
)
type InfluxdbQueryParser struct{} type InfluxdbQueryParser struct{}
@ -108,14 +112,29 @@ func (*InfluxdbQueryParser) parseQueryPart(model *simplejson.Json) (*QueryPart,
for _, paramObj := range model.Get("params").MustArray() { for _, paramObj := range model.Get("params").MustArray() {
param := simplejson.NewFromAny(paramObj) param := simplejson.NewFromAny(paramObj)
pv, err := param.String() stringParam, err := param.String()
if err != nil { if err == nil {
return nil, err params = append(params, stringParam)
continue
} }
params = append(params, pv)
intParam, err := param.Int()
if err == nil {
params = append(params, strconv.Itoa(intParam))
continue
}
return nil, err
} }
return &QueryPart{Type: typ, Params: params}, nil qp, err := NewQueryPart(typ, params)
if err != nil {
return nil, err
}
return qp, nil
//return &QueryPart{Type: typ, Params: params}, nil
} }
func (qp *InfluxdbQueryParser) parseGroupBy(model *simplejson.Json) ([]*QueryPart, error) { func (qp *InfluxdbQueryParser) parseGroupBy(model *simplejson.Json) ([]*QueryPart, error) {

View File

@ -14,7 +14,7 @@ func TestInfluxdbQueryParser(t *testing.T) {
Convey("converting metric name", func() { Convey("converting metric name", func() {
json := ` json := `
{ {
"dsType": "influxdb", "dsType": "influxdb",
"groupBy": [ "groupBy": [
{ {
@ -31,7 +31,7 @@ func TestInfluxdbQueryParser(t *testing.T) {
}, },
{ {
"params": [ "params": [
"null" "none"
], ],
"type": "fill" "type": "fill"
} }
@ -61,8 +61,10 @@ func TestInfluxdbQueryParser(t *testing.T) {
] ]
}, },
{ {
"type": "mean", "type": "bottom",
"params": [] "params": [
3
]
} }
], ],
[ [

View File

@ -7,8 +7,14 @@ import (
var renders map[string]QueryDefinition var renders map[string]QueryDefinition
type DefinitionParameters struct {
Name string
Type string
}
type QueryDefinition struct { type QueryDefinition struct {
Renderer func(part *QueryPart, innerExpr string) string Renderer func(part *QueryPart, innerExpr string) string
Params []DefinitionParameters
} }
func init() { func init() {
@ -26,34 +32,34 @@ func init() {
renders["derivative"] = QueryDefinition{ renders["derivative"] = QueryDefinition{
Renderer: functionRenderer, Renderer: functionRenderer,
//params: [{ name: "duration", type: "interval", options: ['1s', '10s', '1m', '5m', '10m', '15m', '1h']}], Params: []DefinitionParameters{{Name: "duration", Type: "interval"}},
} }
renders["non_negative_derivative"] = QueryDefinition{ renders["non_negative_derivative"] = QueryDefinition{
Renderer: functionRenderer, Renderer: functionRenderer,
//params: [{ name: "duration", type: "interval", options: ['1s', '10s', '1m', '5m', '10m', '15m', '1h']}], Params: []DefinitionParameters{{Name: "duration", Type: "interval"}},
} }
renders["difference"] = QueryDefinition{Renderer: functionRenderer} renders["difference"] = QueryDefinition{Renderer: functionRenderer}
renders["moving_average"] = QueryDefinition{ renders["moving_average"] = QueryDefinition{
Renderer: functionRenderer, Renderer: functionRenderer,
//params: [{ name: "window", type: "number", options: [5, 10, 20, 30, 40]}] Params: []DefinitionParameters{{Name: "window", Type: "number"}},
} }
renders["stddev"] = QueryDefinition{Renderer: functionRenderer} renders["stddev"] = QueryDefinition{Renderer: functionRenderer}
renders["time"] = QueryDefinition{ renders["time"] = QueryDefinition{
Renderer: functionRenderer, Renderer: functionRenderer,
//params: [{ name: "interval", type: "time", options: ['auto', '1s', '10s', '1m', '5m', '10m', '15m', '1h'] }], Params: []DefinitionParameters{{Name: "interval", Type: "time"}},
} }
renders["fill"] = QueryDefinition{ renders["fill"] = QueryDefinition{
Renderer: functionRenderer, Renderer: functionRenderer,
//params: [{ name: "fill", type: "string", options: ['none', 'null', '0', 'previous'] }], Params: []DefinitionParameters{{Name: "fill", Type: "string"}},
} }
renders["elapsed"] = QueryDefinition{ renders["elapsed"] = QueryDefinition{
Renderer: functionRenderer, Renderer: functionRenderer,
//params: [{ name: "duration", type: "interval", options: ['1s', '10s', '1m', '5m', '10m', '15m', '1h']}], Params: []DefinitionParameters{{Name: "duration", Type: "interval"}},
} }
renders["bottom"] = QueryDefinition{ renders["bottom"] = QueryDefinition{
Renderer: functionRenderer, Renderer: functionRenderer,
//params: [{name: 'count', type: 'int'}], Params: []DefinitionParameters{{Name: "count", Type: "int"}},
} }
renders["first"] = QueryDefinition{Renderer: functionRenderer} renders["first"] = QueryDefinition{Renderer: functionRenderer}
@ -62,15 +68,15 @@ func init() {
renders["min"] = QueryDefinition{Renderer: functionRenderer} renders["min"] = QueryDefinition{Renderer: functionRenderer}
renders["percentile"] = QueryDefinition{ renders["percentile"] = QueryDefinition{
Renderer: functionRenderer, Renderer: functionRenderer,
//params: [{name: 'nth', type: 'int'}], Params: []DefinitionParameters{{Name: "nth", Type: "int"}},
} }
renders["top"] = QueryDefinition{ renders["top"] = QueryDefinition{
Renderer: functionRenderer, Renderer: functionRenderer,
//params: [{name: 'count', type: 'int'}], Params: []DefinitionParameters{{Name: "count", Type: "int"}},
} }
renders["tag"] = QueryDefinition{ renders["tag"] = QueryDefinition{
Renderer: fieldRenderer, Renderer: fieldRenderer,
//params: [{name: 'tag', type: 'string', dynamicLookup: true}], Params: []DefinitionParameters{{Name: "tag", Type: "string"}},
} }
renders["math"] = QueryDefinition{Renderer: suffixRenderer} renders["math"] = QueryDefinition{Renderer: suffixRenderer}
@ -81,7 +87,7 @@ func fieldRenderer(part *QueryPart, innerExpr string) string {
if part.Params[0] == "*" { if part.Params[0] == "*" {
return "*" return "*"
} }
return fmt.Sprintf(`"%v"`, part.Params[0]) return fmt.Sprintf(`"%s"`, part.Params[0])
} }
func functionRenderer(part *QueryPart, innerExpr string) string { func functionRenderer(part *QueryPart, innerExpr string) string {
@ -106,19 +112,26 @@ func (r QueryDefinition) Render(part *QueryPart, innerExpr string) string {
return r.Renderer(part, innerExpr) return r.Renderer(part, innerExpr)
} }
type QueryPartDefinition struct { func NewQueryPart(typ string, params []string) (*QueryPart, error) {
def, exist := renders[typ]
if !exist {
return nil, fmt.Errorf("Missing query definition for %s", typ)
}
return &QueryPart{
Type: typ,
Params: params,
Def: def,
}, nil
} }
type QueryPart struct { type QueryPart struct {
Def QueryDefinition
Type string Type string
Params []string Params []string
} }
func (qp *QueryPart) Render(expr string) (string, error) { func (qp *QueryPart) Render(expr string) string {
renderFn, exist := renders[qp.Type] return qp.Def.Renderer(qp, expr)
if !exist {
return "", fmt.Errorf("could not find render strategy %s", qp.Type)
}
return renderFn.Renderer(qp, expr), nil
} }

View File

@ -10,52 +10,50 @@ func TestInfluxdbQueryPart(t *testing.T) {
Convey("Influxdb query part builder", t, func() { Convey("Influxdb query part builder", t, func() {
Convey("should handle field renderer parts", func() { Convey("should handle field renderer parts", func() {
part := QueryPart{ part, err := NewQueryPart("field", []string{"value"})
Type: "field", So(err, ShouldBeNil)
Params: []string{"value"},
}
res, _ := part.Render("value") res := part.Render("value")
So(res, ShouldEqual, `"value"`) So(res, ShouldEqual, `"value"`)
}) })
Convey("should handle nested function parts", func() { Convey("should handle nested function parts", func() {
part := QueryPart{ part, err := NewQueryPart("derivative", []string{"10s"})
Type: "derivative", So(err, ShouldBeNil)
Params: []string{"10s"},
}
res, _ := part.Render("mean(value)") res := part.Render("mean(value)")
So(res, ShouldEqual, "derivative(mean(value), 10s)") So(res, ShouldEqual, "derivative(mean(value), 10s)")
}) })
Convey("should nest spread function", func() { Convey("bottom", func() {
part := QueryPart{ part, err := NewQueryPart("bottom", []string{"3"})
Type: "spread",
}
res, err := part.Render("value")
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(res, ShouldEqual, "spread(value)")
res := part.Render("value")
So(res, ShouldEqual, "bottom(value, 3)")
})
Convey("should nest spread function", func() {
part, err := NewQueryPart("spread", []string{})
So(err, ShouldBeNil)
res := part.Render("value")
So(res, ShouldEqual, `spread(value)`)
}) })
Convey("should handle suffix parts", func() { Convey("should handle suffix parts", func() {
part := QueryPart{ part, err := NewQueryPart("math", []string{"/ 100"})
Type: "math", So(err, ShouldBeNil)
Params: []string{"/ 100"},
}
res, _ := part.Render("mean(value)") res := part.Render("mean(value)")
So(res, ShouldEqual, "mean(value) / 100") So(res, ShouldEqual, "mean(value) / 100")
}) })
Convey("should handle alias parts", func() { Convey("should handle alias parts", func() {
part := QueryPart{ part, err := NewQueryPart("alias", []string{"test"})
Type: "alias", So(err, ShouldBeNil)
Params: []string{"test"},
}
res, _ := part.Render("mean(value)") res := part.Render("mean(value)")
So(res, ShouldEqual, `mean(value) AS "test"`) So(res, ShouldEqual, `mean(value) AS "test"`)
}) })
}) })