From 4144eacc24978325a37cc4c819fd8ad29ff5c4ad Mon Sep 17 00:00:00 2001 From: bergquist Date: Thu, 13 Oct 2016 11:42:51 +0200 Subject: [PATCH] feat(influxdb): start parsing interval parameters --- pkg/tsdb/influxdb/influxdb.go | 3 ++- pkg/tsdb/influxdb/model_parser.go | 12 +++++++++++- pkg/tsdb/influxdb/model_parser_test.go | 13 ++++++++++--- pkg/tsdb/influxdb/query_builder.go | 4 ++-- pkg/tsdb/influxdb/query_builder_test.go | 4 ++-- pkg/tsdb/influxdb/query_part.go | 25 +++++++++++++++---------- pkg/tsdb/influxdb/query_part_test.go | 19 +++++++++---------- 7 files changed, 51 insertions(+), 29 deletions(-) diff --git a/pkg/tsdb/influxdb/influxdb.go b/pkg/tsdb/influxdb/influxdb.go index 2666cb0bd71..22f6230ed6d 100644 --- a/pkg/tsdb/influxdb/influxdb.go +++ b/pkg/tsdb/influxdb/influxdb.go @@ -91,7 +91,8 @@ func (e *InfluxDBExecutor) Execute(ctx context.Context, queries tsdb.QuerySlice, func (e *InfluxDBExecutor) getQuery(queries tsdb.QuerySlice, context *tsdb.QueryContext) (string, error) { for _, v := range queries { - query, err := e.QueryParser.Parse(v.Model) + + query, err := e.QueryParser.Parse(v.Model, e.DataSourceInfo) if err != nil { return "", err } diff --git a/pkg/tsdb/influxdb/model_parser.go b/pkg/tsdb/influxdb/model_parser.go index b2b7fc5489b..ff8977f925b 100644 --- a/pkg/tsdb/influxdb/model_parser.go +++ b/pkg/tsdb/influxdb/model_parser.go @@ -4,13 +4,15 @@ import ( "strconv" "github.com/grafana/grafana/pkg/components/simplejson" + "github.com/grafana/grafana/pkg/tsdb" ) type InfluxdbQueryParser struct{} -func (qp *InfluxdbQueryParser) Parse(model *simplejson.Json) (*Query, error) { +func (qp *InfluxdbQueryParser) Parse(model *simplejson.Json, dsInfo *tsdb.DataSourceInfo) (*Query, error) { policy := model.Get("policy").MustString("default") rawQuery := model.Get("query").MustString("") + interval := model.Get("interval").MustString("") measurement := model.Get("measurement").MustString("") @@ -34,6 +36,13 @@ func (qp *InfluxdbQueryParser) Parse(model *simplejson.Json) (*Query, error) { return nil, err } + if interval == "" { + dsInterval := dsInfo.JsonData.Get("timeInterval").MustString("") + if dsInterval != "" { + interval = dsInterval + } + } + return &Query{ Measurement: measurement, Policy: policy, @@ -42,6 +51,7 @@ func (qp *InfluxdbQueryParser) Parse(model *simplejson.Json) (*Query, error) { Tags: tags, Selects: selects, RawQuery: rawQuery, + Interval: interval, }, nil } diff --git a/pkg/tsdb/influxdb/model_parser_test.go b/pkg/tsdb/influxdb/model_parser_test.go index bcaaf706bd8..8f43cc7d70f 100644 --- a/pkg/tsdb/influxdb/model_parser_test.go +++ b/pkg/tsdb/influxdb/model_parser_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/grafana/grafana/pkg/components/simplejson" + "github.com/grafana/grafana/pkg/tsdb" . "github.com/smartystreets/goconvey/convey" ) @@ -11,6 +12,9 @@ func TestInfluxdbQueryParser(t *testing.T) { Convey("Influxdb query parser", t, func() { parser := &InfluxdbQueryParser{} + dsInfo := &tsdb.DataSourceInfo{ + JsonData: simplejson.New(), + } Convey("can parse influxdb json model", func() { json := ` @@ -101,15 +105,16 @@ func TestInfluxdbQueryParser(t *testing.T) { ] } ` - + dsInfo.JsonData.Set("timeInterval", ">20s") modelJson, err := simplejson.NewJson([]byte(json)) So(err, ShouldBeNil) - res, err := parser.Parse(modelJson) + res, err := parser.Parse(modelJson, dsInfo) So(err, ShouldBeNil) So(len(res.GroupBy), ShouldEqual, 3) So(len(res.Selects), ShouldEqual, 3) So(len(res.Tags), ShouldEqual, 2) + So(res.Interval, ShouldEqual, ">20s") }) Convey("can part raw query json model", func() { @@ -130,6 +135,7 @@ func TestInfluxdbQueryParser(t *testing.T) { "type": "fill" } ], + "interval": ">10s", "policy": "default", "query": "RawDummieQuery", "rawQuery": true, @@ -160,12 +166,13 @@ func TestInfluxdbQueryParser(t *testing.T) { modelJson, err := simplejson.NewJson([]byte(json)) So(err, ShouldBeNil) - res, err := parser.Parse(modelJson) + res, err := parser.Parse(modelJson, dsInfo) So(err, ShouldBeNil) So(res.RawQuery, ShouldEqual, "RawDummieQuery") So(len(res.GroupBy), ShouldEqual, 2) So(len(res.Selects), ShouldEqual, 1) So(len(res.Tags), ShouldEqual, 0) + So(res.Interval, ShouldEqual, ">10s") }) }) } diff --git a/pkg/tsdb/influxdb/query_builder.go b/pkg/tsdb/influxdb/query_builder.go index 2bd31149fd1..bf0dc084c49 100644 --- a/pkg/tsdb/influxdb/query_builder.go +++ b/pkg/tsdb/influxdb/query_builder.go @@ -67,7 +67,7 @@ func (qb *QueryBuilder) renderSelectors(query *Query, queryContext *tsdb.QueryCo stk := "" for _, s := range *sel { - stk = s.Render(queryContext, stk) + stk = s.Render(query, queryContext, stk) } selectors = append(selectors, stk) } @@ -109,7 +109,7 @@ func (qb *QueryBuilder) renderGroupBy(query *Query, queryContext *tsdb.QueryCont groupBy += " " } - groupBy += group.Render(queryContext, "") + groupBy += group.Render(query, queryContext, "") } return groupBy diff --git a/pkg/tsdb/influxdb/query_builder_test.go b/pkg/tsdb/influxdb/query_builder_test.go index 52273f67f80..4552f85b28a 100644 --- a/pkg/tsdb/influxdb/query_builder_test.go +++ b/pkg/tsdb/influxdb/query_builder_test.go @@ -37,7 +37,7 @@ func TestInfluxdbQueryBuilder(t *testing.T) { rawQuery, err := builder.Build(query, queryContext) So(err, ShouldBeNil) - So(rawQuery, ShouldEqual, `SELECT mean("value") FROM "policy"."cpu" WHERE time > now() - 5m GROUP BY time(200ms) fill(null)`) + So(rawQuery, ShouldEqual, `SELECT mean("value") FROM "policy"."cpu" WHERE time > now() - 5m GROUP BY time(10s) fill(null)`) }) Convey("can build query with group bys", func() { @@ -51,7 +51,7 @@ func TestInfluxdbQueryBuilder(t *testing.T) { rawQuery, err := builder.Build(query, queryContext) So(err, ShouldBeNil) - So(rawQuery, ShouldEqual, `SELECT mean("value") FROM "cpu" WHERE "hostname" = 'server1' OR "hostname" = 'server2' AND time > now() - 5m GROUP BY time(200ms), "datacenter" fill(null)`) + So(rawQuery, ShouldEqual, `SELECT mean("value") FROM "cpu" WHERE "hostname" = 'server1' OR "hostname" = 'server2' AND time > now() - 5m GROUP BY time(5s), "datacenter" fill(null)`) }) Convey("can render time range", func() { diff --git a/pkg/tsdb/influxdb/query_part.go b/pkg/tsdb/influxdb/query_part.go index bace83246c2..ec24efa0057 100644 --- a/pkg/tsdb/influxdb/query_part.go +++ b/pkg/tsdb/influxdb/query_part.go @@ -15,7 +15,7 @@ type DefinitionParameters struct { } type QueryDefinition struct { - Renderer func(queryContext *tsdb.QueryContext, part *QueryPart, innerExpr string) string + Renderer func(query *Query, queryContext *tsdb.QueryContext, part *QueryPart, innerExpr string) string Params []DefinitionParameters } @@ -85,17 +85,22 @@ func init() { renders["alias"] = QueryDefinition{Renderer: aliasRenderer} } -func fieldRenderer(queryContext *tsdb.QueryContext, part *QueryPart, innerExpr string) string { +func fieldRenderer(query *Query, queryContext *tsdb.QueryContext, part *QueryPart, innerExpr string) string { if part.Params[0] == "*" { return "*" } return fmt.Sprintf(`"%s"`, part.Params[0]) } -func functionRenderer(queryContext *tsdb.QueryContext, part *QueryPart, innerExpr string) string { +func functionRenderer(query *Query, queryContext *tsdb.QueryContext, part *QueryPart, innerExpr string) string { for i, v := range part.Params { if v == "$interval" { - part.Params[i] = tsdb.CalculateInterval(queryContext.TimeRange) + if query.Interval != "" { + interval := strings.Replace(strings.Replace(query.Interval, "<", "", 1), ">", "", 1) + part.Params[i] = interval + } else { + part.Params[i] = tsdb.CalculateInterval(queryContext.TimeRange) + } } } @@ -108,16 +113,16 @@ func functionRenderer(queryContext *tsdb.QueryContext, part *QueryPart, innerExp return fmt.Sprintf("%s(%s)", part.Type, params) } -func suffixRenderer(queryContext *tsdb.QueryContext, part *QueryPart, innerExpr string) string { +func suffixRenderer(query *Query, queryContext *tsdb.QueryContext, part *QueryPart, innerExpr string) string { return fmt.Sprintf("%s %s", innerExpr, part.Params[0]) } -func aliasRenderer(queryContext *tsdb.QueryContext, part *QueryPart, innerExpr string) string { +func aliasRenderer(query *Query, queryContext *tsdb.QueryContext, part *QueryPart, innerExpr string) string { return fmt.Sprintf(`%s AS "%s"`, innerExpr, part.Params[0]) } -func (r QueryDefinition) Render(queryContext *tsdb.QueryContext, part *QueryPart, innerExpr string) string { - return r.Renderer(queryContext, part, innerExpr) +func (r QueryDefinition) Render(query *Query, queryContext *tsdb.QueryContext, part *QueryPart, innerExpr string) string { + return r.Renderer(query, queryContext, part, innerExpr) } func NewQueryPart(typ string, params []string) (*QueryPart, error) { @@ -140,6 +145,6 @@ type QueryPart struct { Params []string } -func (qp *QueryPart) Render(queryContext *tsdb.QueryContext, expr string) string { - return qp.Def.Renderer(queryContext, qp, expr) +func (qp *QueryPart) Render(query *Query, queryContext *tsdb.QueryContext, expr string) string { + return qp.Def.Renderer(query, queryContext, qp, expr) } diff --git a/pkg/tsdb/influxdb/query_part_test.go b/pkg/tsdb/influxdb/query_part_test.go index bd2d544d3e1..51107a774e0 100644 --- a/pkg/tsdb/influxdb/query_part_test.go +++ b/pkg/tsdb/influxdb/query_part_test.go @@ -10,15 +10,14 @@ import ( func TestInfluxdbQueryPart(t *testing.T) { Convey("Influxdb query parts", t, func() { - queryContext := &tsdb.QueryContext{ - TimeRange: tsdb.NewTimeRange("5m", "now"), - } + queryContext := &tsdb.QueryContext{TimeRange: tsdb.NewTimeRange("5m", "now")} + query := &Query{} Convey("render field ", func() { part, err := NewQueryPart("field", []string{"value"}) So(err, ShouldBeNil) - res := part.Render(queryContext, "value") + res := part.Render(query, queryContext, "value") So(res, ShouldEqual, `"value"`) }) @@ -26,7 +25,7 @@ func TestInfluxdbQueryPart(t *testing.T) { part, err := NewQueryPart("derivative", []string{"10s"}) So(err, ShouldBeNil) - res := part.Render(queryContext, "mean(value)") + res := part.Render(query, queryContext, "mean(value)") So(res, ShouldEqual, "derivative(mean(value), 10s)") }) @@ -34,7 +33,7 @@ func TestInfluxdbQueryPart(t *testing.T) { part, err := NewQueryPart("bottom", []string{"3"}) So(err, ShouldBeNil) - res := part.Render(queryContext, "value") + res := part.Render(query, queryContext, "value") So(res, ShouldEqual, "bottom(value, 3)") }) @@ -42,7 +41,7 @@ func TestInfluxdbQueryPart(t *testing.T) { part, err := NewQueryPart("time", []string{"$interval"}) So(err, ShouldBeNil) - res := part.Render(queryContext, "") + res := part.Render(query, queryContext, "") So(res, ShouldEqual, "time(200ms)") }) @@ -50,7 +49,7 @@ func TestInfluxdbQueryPart(t *testing.T) { part, err := NewQueryPart("spread", []string{}) So(err, ShouldBeNil) - res := part.Render(queryContext, "value") + res := part.Render(query, queryContext, "value") So(res, ShouldEqual, `spread(value)`) }) @@ -58,7 +57,7 @@ func TestInfluxdbQueryPart(t *testing.T) { part, err := NewQueryPart("math", []string{"/ 100"}) So(err, ShouldBeNil) - res := part.Render(queryContext, "mean(value)") + res := part.Render(query, queryContext, "mean(value)") So(res, ShouldEqual, "mean(value) / 100") }) @@ -66,7 +65,7 @@ func TestInfluxdbQueryPart(t *testing.T) { part, err := NewQueryPart("alias", []string{"test"}) So(err, ShouldBeNil) - res := part.Render(queryContext, "mean(value)") + res := part.Render(query, queryContext, "mean(value)") So(res, ShouldEqual, `mean(value) AS "test"`) }) })