From 9968fa5bc5c42b40423488782209476f1d59f289 Mon Sep 17 00:00:00 2001 From: bergquist Date: Wed, 5 Oct 2016 16:59:33 +0200 Subject: [PATCH] feat(influxdb): add query part definitions --- pkg/tsdb/influxdb/parser.go | 31 +++++++++++++---- pkg/tsdb/influxdb/parser_test.go | 10 +++--- pkg/tsdb/influxdb/query_part.go | 51 +++++++++++++++++---------- pkg/tsdb/influxdb/query_part_test.go | 52 +++++++++++++--------------- 4 files changed, 88 insertions(+), 56 deletions(-) diff --git a/pkg/tsdb/influxdb/parser.go b/pkg/tsdb/influxdb/parser.go index c158d5879a1..7d51d087b5d 100644 --- a/pkg/tsdb/influxdb/parser.go +++ b/pkg/tsdb/influxdb/parser.go @@ -1,6 +1,10 @@ package influxdb -import "github.com/grafana/grafana/pkg/components/simplejson" +import ( + "strconv" + + "github.com/grafana/grafana/pkg/components/simplejson" +) type InfluxdbQueryParser struct{} @@ -108,14 +112,29 @@ func (*InfluxdbQueryParser) parseQueryPart(model *simplejson.Json) (*QueryPart, for _, paramObj := range model.Get("params").MustArray() { param := simplejson.NewFromAny(paramObj) - pv, err := param.String() - if err != nil { - return nil, err + stringParam, err := param.String() + if err == nil { + 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) { diff --git a/pkg/tsdb/influxdb/parser_test.go b/pkg/tsdb/influxdb/parser_test.go index 3dc76124365..b8bba08616a 100644 --- a/pkg/tsdb/influxdb/parser_test.go +++ b/pkg/tsdb/influxdb/parser_test.go @@ -14,7 +14,7 @@ func TestInfluxdbQueryParser(t *testing.T) { Convey("converting metric name", func() { json := ` - { + { "dsType": "influxdb", "groupBy": [ { @@ -31,7 +31,7 @@ func TestInfluxdbQueryParser(t *testing.T) { }, { "params": [ - "null" + "none" ], "type": "fill" } @@ -61,8 +61,10 @@ func TestInfluxdbQueryParser(t *testing.T) { ] }, { - "type": "mean", - "params": [] + "type": "bottom", + "params": [ + 3 + ] } ], [ diff --git a/pkg/tsdb/influxdb/query_part.go b/pkg/tsdb/influxdb/query_part.go index cba0c57b6b1..ff352f5e048 100644 --- a/pkg/tsdb/influxdb/query_part.go +++ b/pkg/tsdb/influxdb/query_part.go @@ -7,8 +7,14 @@ import ( var renders map[string]QueryDefinition +type DefinitionParameters struct { + Name string + Type string +} + type QueryDefinition struct { Renderer func(part *QueryPart, innerExpr string) string + Params []DefinitionParameters } func init() { @@ -26,34 +32,34 @@ func init() { renders["derivative"] = QueryDefinition{ 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{ 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["moving_average"] = QueryDefinition{ 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["time"] = QueryDefinition{ 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{ Renderer: functionRenderer, - //params: [{ name: "fill", type: "string", options: ['none', 'null', '0', 'previous'] }], + Params: []DefinitionParameters{{Name: "fill", Type: "string"}}, } renders["elapsed"] = QueryDefinition{ Renderer: functionRenderer, - //params: [{ name: "duration", type: "interval", options: ['1s', '10s', '1m', '5m', '10m', '15m', '1h']}], + Params: []DefinitionParameters{{Name: "duration", Type: "interval"}}, } renders["bottom"] = QueryDefinition{ Renderer: functionRenderer, - //params: [{name: 'count', type: 'int'}], + Params: []DefinitionParameters{{Name: "count", Type: "int"}}, } renders["first"] = QueryDefinition{Renderer: functionRenderer} @@ -62,15 +68,15 @@ func init() { renders["min"] = QueryDefinition{Renderer: functionRenderer} renders["percentile"] = QueryDefinition{ Renderer: functionRenderer, - //params: [{name: 'nth', type: 'int'}], + Params: []DefinitionParameters{{Name: "nth", Type: "int"}}, } renders["top"] = QueryDefinition{ Renderer: functionRenderer, - //params: [{name: 'count', type: 'int'}], + Params: []DefinitionParameters{{Name: "count", Type: "int"}}, } renders["tag"] = QueryDefinition{ Renderer: fieldRenderer, - //params: [{name: 'tag', type: 'string', dynamicLookup: true}], + Params: []DefinitionParameters{{Name: "tag", Type: "string"}}, } renders["math"] = QueryDefinition{Renderer: suffixRenderer} @@ -81,7 +87,7 @@ func fieldRenderer(part *QueryPart, innerExpr string) string { if part.Params[0] == "*" { return "*" } - return fmt.Sprintf(`"%v"`, part.Params[0]) + return fmt.Sprintf(`"%s"`, part.Params[0]) } 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) } -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 { + Def QueryDefinition Type string Params []string } -func (qp *QueryPart) Render(expr string) (string, error) { - renderFn, exist := renders[qp.Type] - if !exist { - return "", fmt.Errorf("could not find render strategy %s", qp.Type) - } - - return renderFn.Renderer(qp, expr), nil +func (qp *QueryPart) Render(expr string) string { + return qp.Def.Renderer(qp, expr) } diff --git a/pkg/tsdb/influxdb/query_part_test.go b/pkg/tsdb/influxdb/query_part_test.go index eb2583e7711..b1c24b7070f 100644 --- a/pkg/tsdb/influxdb/query_part_test.go +++ b/pkg/tsdb/influxdb/query_part_test.go @@ -10,52 +10,50 @@ func TestInfluxdbQueryPart(t *testing.T) { Convey("Influxdb query part builder", t, func() { Convey("should handle field renderer parts", func() { - part := QueryPart{ - Type: "field", - Params: []string{"value"}, - } + part, err := NewQueryPart("field", []string{"value"}) + So(err, ShouldBeNil) - res, _ := part.Render("value") + res := part.Render("value") So(res, ShouldEqual, `"value"`) }) Convey("should handle nested function parts", func() { - part := QueryPart{ - Type: "derivative", - Params: []string{"10s"}, - } + part, err := NewQueryPart("derivative", []string{"10s"}) + So(err, ShouldBeNil) - res, _ := part.Render("mean(value)") + res := part.Render("mean(value)") So(res, ShouldEqual, "derivative(mean(value), 10s)") }) - Convey("should nest spread function", func() { - part := QueryPart{ - Type: "spread", - } - - res, err := part.Render("value") + Convey("bottom", func() { + part, err := NewQueryPart("bottom", []string{"3"}) 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() { - part := QueryPart{ - Type: "math", - Params: []string{"/ 100"}, - } + part, err := NewQueryPart("math", []string{"/ 100"}) + So(err, ShouldBeNil) - res, _ := part.Render("mean(value)") + res := part.Render("mean(value)") So(res, ShouldEqual, "mean(value) / 100") }) Convey("should handle alias parts", func() { - part := QueryPart{ - Type: "alias", - Params: []string{"test"}, - } + part, err := NewQueryPart("alias", []string{"test"}) + So(err, ShouldBeNil) - res, _ := part.Render("mean(value)") + res := part.Render("mean(value)") So(res, ShouldEqual, `mean(value) AS "test"`) }) })