mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
feat(influxdb): add query part definitions
This commit is contained in:
parent
8588bb386c
commit
9968fa5bc5
@ -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) {
|
||||||
|
@ -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
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
@ -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
|
|
||||||
}
|
}
|
||||||
|
@ -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"`)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user