Commit 4144eacc by bergquist

feat(influxdb): start parsing interval parameters

parent 1506df8c
...@@ -91,7 +91,8 @@ func (e *InfluxDBExecutor) Execute(ctx context.Context, queries tsdb.QuerySlice, ...@@ -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) { func (e *InfluxDBExecutor) getQuery(queries tsdb.QuerySlice, context *tsdb.QueryContext) (string, error) {
for _, v := range queries { for _, v := range queries {
query, err := e.QueryParser.Parse(v.Model)
query, err := e.QueryParser.Parse(v.Model, e.DataSourceInfo)
if err != nil { if err != nil {
return "", err return "", err
} }
......
...@@ -4,13 +4,15 @@ import ( ...@@ -4,13 +4,15 @@ import (
"strconv" "strconv"
"github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/tsdb"
) )
type InfluxdbQueryParser struct{} 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") policy := model.Get("policy").MustString("default")
rawQuery := model.Get("query").MustString("") rawQuery := model.Get("query").MustString("")
interval := model.Get("interval").MustString("")
measurement := model.Get("measurement").MustString("") measurement := model.Get("measurement").MustString("")
...@@ -34,6 +36,13 @@ func (qp *InfluxdbQueryParser) Parse(model *simplejson.Json) (*Query, error) { ...@@ -34,6 +36,13 @@ func (qp *InfluxdbQueryParser) Parse(model *simplejson.Json) (*Query, error) {
return nil, err return nil, err
} }
if interval == "" {
dsInterval := dsInfo.JsonData.Get("timeInterval").MustString("")
if dsInterval != "" {
interval = dsInterval
}
}
return &Query{ return &Query{
Measurement: measurement, Measurement: measurement,
Policy: policy, Policy: policy,
...@@ -42,6 +51,7 @@ func (qp *InfluxdbQueryParser) Parse(model *simplejson.Json) (*Query, error) { ...@@ -42,6 +51,7 @@ func (qp *InfluxdbQueryParser) Parse(model *simplejson.Json) (*Query, error) {
Tags: tags, Tags: tags,
Selects: selects, Selects: selects,
RawQuery: rawQuery, RawQuery: rawQuery,
Interval: interval,
}, nil }, nil
} }
......
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
"testing" "testing"
"github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/tsdb"
. "github.com/smartystreets/goconvey/convey" . "github.com/smartystreets/goconvey/convey"
) )
...@@ -11,6 +12,9 @@ func TestInfluxdbQueryParser(t *testing.T) { ...@@ -11,6 +12,9 @@ func TestInfluxdbQueryParser(t *testing.T) {
Convey("Influxdb query parser", t, func() { Convey("Influxdb query parser", t, func() {
parser := &InfluxdbQueryParser{} parser := &InfluxdbQueryParser{}
dsInfo := &tsdb.DataSourceInfo{
JsonData: simplejson.New(),
}
Convey("can parse influxdb json model", func() { Convey("can parse influxdb json model", func() {
json := ` json := `
...@@ -101,15 +105,16 @@ func TestInfluxdbQueryParser(t *testing.T) { ...@@ -101,15 +105,16 @@ func TestInfluxdbQueryParser(t *testing.T) {
] ]
} }
` `
dsInfo.JsonData.Set("timeInterval", ">20s")
modelJson, err := simplejson.NewJson([]byte(json)) modelJson, err := simplejson.NewJson([]byte(json))
So(err, ShouldBeNil) So(err, ShouldBeNil)
res, err := parser.Parse(modelJson) res, err := parser.Parse(modelJson, dsInfo)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(len(res.GroupBy), ShouldEqual, 3) So(len(res.GroupBy), ShouldEqual, 3)
So(len(res.Selects), ShouldEqual, 3) So(len(res.Selects), ShouldEqual, 3)
So(len(res.Tags), ShouldEqual, 2) So(len(res.Tags), ShouldEqual, 2)
So(res.Interval, ShouldEqual, ">20s")
}) })
Convey("can part raw query json model", func() { Convey("can part raw query json model", func() {
...@@ -130,6 +135,7 @@ func TestInfluxdbQueryParser(t *testing.T) { ...@@ -130,6 +135,7 @@ func TestInfluxdbQueryParser(t *testing.T) {
"type": "fill" "type": "fill"
} }
], ],
"interval": ">10s",
"policy": "default", "policy": "default",
"query": "RawDummieQuery", "query": "RawDummieQuery",
"rawQuery": true, "rawQuery": true,
...@@ -160,12 +166,13 @@ func TestInfluxdbQueryParser(t *testing.T) { ...@@ -160,12 +166,13 @@ func TestInfluxdbQueryParser(t *testing.T) {
modelJson, err := simplejson.NewJson([]byte(json)) modelJson, err := simplejson.NewJson([]byte(json))
So(err, ShouldBeNil) So(err, ShouldBeNil)
res, err := parser.Parse(modelJson) res, err := parser.Parse(modelJson, dsInfo)
So(err, ShouldBeNil) So(err, ShouldBeNil)
So(res.RawQuery, ShouldEqual, "RawDummieQuery") So(res.RawQuery, ShouldEqual, "RawDummieQuery")
So(len(res.GroupBy), ShouldEqual, 2) So(len(res.GroupBy), ShouldEqual, 2)
So(len(res.Selects), ShouldEqual, 1) So(len(res.Selects), ShouldEqual, 1)
So(len(res.Tags), ShouldEqual, 0) So(len(res.Tags), ShouldEqual, 0)
So(res.Interval, ShouldEqual, ">10s")
}) })
}) })
} }
...@@ -67,7 +67,7 @@ func (qb *QueryBuilder) renderSelectors(query *Query, queryContext *tsdb.QueryCo ...@@ -67,7 +67,7 @@ func (qb *QueryBuilder) renderSelectors(query *Query, queryContext *tsdb.QueryCo
stk := "" stk := ""
for _, s := range *sel { for _, s := range *sel {
stk = s.Render(queryContext, stk) stk = s.Render(query, queryContext, stk)
} }
selectors = append(selectors, stk) selectors = append(selectors, stk)
} }
...@@ -109,7 +109,7 @@ func (qb *QueryBuilder) renderGroupBy(query *Query, queryContext *tsdb.QueryCont ...@@ -109,7 +109,7 @@ func (qb *QueryBuilder) renderGroupBy(query *Query, queryContext *tsdb.QueryCont
groupBy += " " groupBy += " "
} }
groupBy += group.Render(queryContext, "") groupBy += group.Render(query, queryContext, "")
} }
return groupBy return groupBy
......
...@@ -37,7 +37,7 @@ func TestInfluxdbQueryBuilder(t *testing.T) { ...@@ -37,7 +37,7 @@ func TestInfluxdbQueryBuilder(t *testing.T) {
rawQuery, err := builder.Build(query, queryContext) rawQuery, err := builder.Build(query, queryContext)
So(err, ShouldBeNil) 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() { Convey("can build query with group bys", func() {
...@@ -51,7 +51,7 @@ func TestInfluxdbQueryBuilder(t *testing.T) { ...@@ -51,7 +51,7 @@ func TestInfluxdbQueryBuilder(t *testing.T) {
rawQuery, err := builder.Build(query, queryContext) rawQuery, err := builder.Build(query, queryContext)
So(err, ShouldBeNil) 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() { Convey("can render time range", func() {
......
...@@ -15,7 +15,7 @@ type DefinitionParameters struct { ...@@ -15,7 +15,7 @@ type DefinitionParameters struct {
} }
type QueryDefinition 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 Params []DefinitionParameters
} }
...@@ -85,19 +85,24 @@ func init() { ...@@ -85,19 +85,24 @@ func init() {
renders["alias"] = QueryDefinition{Renderer: aliasRenderer} 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] == "*" { if part.Params[0] == "*" {
return "*" return "*"
} }
return fmt.Sprintf(`"%s"`, part.Params[0]) 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 { for i, v := range part.Params {
if v == "$interval" { if v == "$interval" {
if query.Interval != "" {
interval := strings.Replace(strings.Replace(query.Interval, "<", "", 1), ">", "", 1)
part.Params[i] = interval
} else {
part.Params[i] = tsdb.CalculateInterval(queryContext.TimeRange) part.Params[i] = tsdb.CalculateInterval(queryContext.TimeRange)
} }
} }
}
if innerExpr != "" { if innerExpr != "" {
part.Params = append([]string{innerExpr}, part.Params...) part.Params = append([]string{innerExpr}, part.Params...)
...@@ -108,16 +113,16 @@ func functionRenderer(queryContext *tsdb.QueryContext, part *QueryPart, innerExp ...@@ -108,16 +113,16 @@ func functionRenderer(queryContext *tsdb.QueryContext, part *QueryPart, innerExp
return fmt.Sprintf("%s(%s)", part.Type, params) 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]) 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]) return fmt.Sprintf(`%s AS "%s"`, innerExpr, part.Params[0])
} }
func (r QueryDefinition) Render(queryContext *tsdb.QueryContext, part *QueryPart, innerExpr string) string { func (r QueryDefinition) Render(query *Query, queryContext *tsdb.QueryContext, part *QueryPart, innerExpr string) string {
return r.Renderer(queryContext, part, innerExpr) return r.Renderer(query, queryContext, part, innerExpr)
} }
func NewQueryPart(typ string, params []string) (*QueryPart, error) { func NewQueryPart(typ string, params []string) (*QueryPart, error) {
...@@ -140,6 +145,6 @@ type QueryPart struct { ...@@ -140,6 +145,6 @@ type QueryPart struct {
Params []string Params []string
} }
func (qp *QueryPart) Render(queryContext *tsdb.QueryContext, expr string) string { func (qp *QueryPart) Render(query *Query, queryContext *tsdb.QueryContext, expr string) string {
return qp.Def.Renderer(queryContext, qp, expr) return qp.Def.Renderer(query, queryContext, qp, expr)
} }
...@@ -10,15 +10,14 @@ import ( ...@@ -10,15 +10,14 @@ import (
func TestInfluxdbQueryPart(t *testing.T) { func TestInfluxdbQueryPart(t *testing.T) {
Convey("Influxdb query parts", t, func() { Convey("Influxdb query parts", t, func() {
queryContext := &tsdb.QueryContext{ queryContext := &tsdb.QueryContext{TimeRange: tsdb.NewTimeRange("5m", "now")}
TimeRange: tsdb.NewTimeRange("5m", "now"), query := &Query{}
}
Convey("render field ", func() { Convey("render field ", func() {
part, err := NewQueryPart("field", []string{"value"}) part, err := NewQueryPart("field", []string{"value"})
So(err, ShouldBeNil) So(err, ShouldBeNil)
res := part.Render(queryContext, "value") res := part.Render(query, queryContext, "value")
So(res, ShouldEqual, `"value"`) So(res, ShouldEqual, `"value"`)
}) })
...@@ -26,7 +25,7 @@ func TestInfluxdbQueryPart(t *testing.T) { ...@@ -26,7 +25,7 @@ func TestInfluxdbQueryPart(t *testing.T) {
part, err := NewQueryPart("derivative", []string{"10s"}) part, err := NewQueryPart("derivative", []string{"10s"})
So(err, ShouldBeNil) So(err, ShouldBeNil)
res := part.Render(queryContext, "mean(value)") res := part.Render(query, queryContext, "mean(value)")
So(res, ShouldEqual, "derivative(mean(value), 10s)") So(res, ShouldEqual, "derivative(mean(value), 10s)")
}) })
...@@ -34,7 +33,7 @@ func TestInfluxdbQueryPart(t *testing.T) { ...@@ -34,7 +33,7 @@ func TestInfluxdbQueryPart(t *testing.T) {
part, err := NewQueryPart("bottom", []string{"3"}) part, err := NewQueryPart("bottom", []string{"3"})
So(err, ShouldBeNil) So(err, ShouldBeNil)
res := part.Render(queryContext, "value") res := part.Render(query, queryContext, "value")
So(res, ShouldEqual, "bottom(value, 3)") So(res, ShouldEqual, "bottom(value, 3)")
}) })
...@@ -42,7 +41,7 @@ func TestInfluxdbQueryPart(t *testing.T) { ...@@ -42,7 +41,7 @@ func TestInfluxdbQueryPart(t *testing.T) {
part, err := NewQueryPart("time", []string{"$interval"}) part, err := NewQueryPart("time", []string{"$interval"})
So(err, ShouldBeNil) So(err, ShouldBeNil)
res := part.Render(queryContext, "") res := part.Render(query, queryContext, "")
So(res, ShouldEqual, "time(200ms)") So(res, ShouldEqual, "time(200ms)")
}) })
...@@ -50,7 +49,7 @@ func TestInfluxdbQueryPart(t *testing.T) { ...@@ -50,7 +49,7 @@ func TestInfluxdbQueryPart(t *testing.T) {
part, err := NewQueryPart("spread", []string{}) part, err := NewQueryPart("spread", []string{})
So(err, ShouldBeNil) So(err, ShouldBeNil)
res := part.Render(queryContext, "value") res := part.Render(query, queryContext, "value")
So(res, ShouldEqual, `spread(value)`) So(res, ShouldEqual, `spread(value)`)
}) })
...@@ -58,7 +57,7 @@ func TestInfluxdbQueryPart(t *testing.T) { ...@@ -58,7 +57,7 @@ func TestInfluxdbQueryPart(t *testing.T) {
part, err := NewQueryPart("math", []string{"/ 100"}) part, err := NewQueryPart("math", []string{"/ 100"})
So(err, ShouldBeNil) So(err, ShouldBeNil)
res := part.Render(queryContext, "mean(value)") res := part.Render(query, queryContext, "mean(value)")
So(res, ShouldEqual, "mean(value) / 100") So(res, ShouldEqual, "mean(value) / 100")
}) })
...@@ -66,7 +65,7 @@ func TestInfluxdbQueryPart(t *testing.T) { ...@@ -66,7 +65,7 @@ func TestInfluxdbQueryPart(t *testing.T) {
part, err := NewQueryPart("alias", []string{"test"}) part, err := NewQueryPart("alias", []string{"test"})
So(err, ShouldBeNil) So(err, ShouldBeNil)
res := part.Render(queryContext, "mean(value)") res := part.Render(query, queryContext, "mean(value)")
So(res, ShouldEqual, `mean(value) AS "test"`) So(res, ShouldEqual, `mean(value) AS "test"`)
}) })
}) })
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment