Browse Source

feat(influxdb): start parsing interval parameters

bergquist 9 years ago
parent
commit
4144eacc24

+ 2 - 1
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
 		}

+ 11 - 1
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
 }
 

+ 10 - 3
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")
 		})
 	})
 }

+ 2 - 2
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

+ 2 - 2
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() {

+ 15 - 10
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)
 }

+ 9 - 10
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"`)
 		})
 	})