mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
feat(influxdb): render select and groupby
This commit is contained in:
parent
9968fa5bc5
commit
4387d20222
@ -12,13 +12,15 @@ import (
|
||||
|
||||
type InfluxDBExecutor struct {
|
||||
*tsdb.DataSourceInfo
|
||||
QueryParser *InfluxdbQueryParser
|
||||
QueryParser *InfluxdbQueryParser
|
||||
QueryBuilder *QueryBuild
|
||||
}
|
||||
|
||||
func NewInfluxDBExecutor(dsInfo *tsdb.DataSourceInfo) tsdb.Executor {
|
||||
return &InfluxDBExecutor{
|
||||
DataSourceInfo: dsInfo,
|
||||
QueryParser: &InfluxdbQueryParser{},
|
||||
QueryBuilder: &QueryBuild{},
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,12 +48,16 @@ func (e *InfluxDBExecutor) Execute(ctx context.Context, queries tsdb.QuerySlice,
|
||||
for _, v := range queries {
|
||||
|
||||
query, err := e.QueryParser.Parse(v.Model)
|
||||
|
||||
if err != nil {
|
||||
result.Error = err
|
||||
return result
|
||||
}
|
||||
|
||||
glog.Info("Influxdb executor", "query", query)
|
||||
|
||||
rawQuery, err := e.QueryBuilder.Build(query)
|
||||
|
||||
glog.Info("Influxdb", "error", err, "rawQuery", rawQuery)
|
||||
}
|
||||
|
||||
return result
|
||||
|
@ -1,10 +1,65 @@
|
||||
package influxdb
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type QueryBuild struct{}
|
||||
|
||||
func (*QueryBuild) Build(query *Query) (string, error) {
|
||||
func renderTags(query *Query) []string {
|
||||
var res []string
|
||||
for i, tag := range query.Tags {
|
||||
str := ""
|
||||
|
||||
return "", fmt.Errorf("query is not valid")
|
||||
if i > 0 {
|
||||
if tag.Condition == "" {
|
||||
str += "AND"
|
||||
} else {
|
||||
str += tag.Condition
|
||||
}
|
||||
str += " "
|
||||
}
|
||||
|
||||
res = append(res, fmt.Sprintf(`%s"%s" %s '%s'`, str, tag.Key, tag.Operator, tag.Value))
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func (*QueryBuild) Build(query *Query) (string, error) {
|
||||
res := "SELECT "
|
||||
|
||||
var selectors []string
|
||||
for _, sel := range query.Selects {
|
||||
|
||||
stk := ""
|
||||
for _, s := range *sel {
|
||||
stk = s.Render(stk)
|
||||
}
|
||||
selectors = append(selectors, stk)
|
||||
}
|
||||
res += strings.Join(selectors, ", ")
|
||||
|
||||
res += fmt.Sprintf(` FROM "%s"`, query.Measurement)
|
||||
|
||||
res += " WHERE "
|
||||
conditions := renderTags(query)
|
||||
res += strings.Join(conditions, " ")
|
||||
if len(conditions) > 0 {
|
||||
res += " AND "
|
||||
}
|
||||
|
||||
res += "$timeFilter"
|
||||
|
||||
var groupBy []string
|
||||
for _, group := range query.GroupBy {
|
||||
groupBy = append(groupBy, group.Render(""))
|
||||
}
|
||||
|
||||
if len(groupBy) > 0 {
|
||||
res += " GROUP BY " + strings.Join(groupBy, " ")
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
@ -8,50 +8,40 @@ import (
|
||||
|
||||
func TestInfluxdbQueryBuilder(t *testing.T) {
|
||||
Convey("Influxdb query builder", t, func() {
|
||||
builder := QueryBuild{}
|
||||
|
||||
builder := &QueryBuild{}
|
||||
qp1, _ := NewQueryPart("field", []string{"value"})
|
||||
qp2, _ := NewQueryPart("mean", []string{})
|
||||
|
||||
groupBy1, _ := NewQueryPart("time", []string{"$interval"})
|
||||
groupBy2, _ := NewQueryPart("fill", []string{"null"})
|
||||
|
||||
tag1 := &Tag{Key: "hostname", Value: "server1", Operator: "="}
|
||||
tag2 := &Tag{Key: "hostname", Value: "server2", Operator: "=", Condition: "OR"}
|
||||
|
||||
Convey("can build query", func() {
|
||||
//query := &Query{}
|
||||
//res, err := builder.Build(query)
|
||||
//So(err, ShouldBeNil)
|
||||
query := &Query{
|
||||
Selects: []*Select{{*qp1, *qp2}},
|
||||
Measurement: "cpu",
|
||||
GroupBy: []*QueryPart{groupBy1, groupBy2},
|
||||
}
|
||||
|
||||
rawQuery, err := builder.Build(query)
|
||||
So(err, ShouldBeNil)
|
||||
So(rawQuery, ShouldEqual, `SELECT mean("value") FROM "cpu" WHERE $timeFilter GROUP BY time($interval) fill(null)`)
|
||||
})
|
||||
|
||||
Convey("empty queries should return error", func() {
|
||||
query := &Query{}
|
||||
Convey("can asd query", func() {
|
||||
query := &Query{
|
||||
Selects: []*Select{{*qp1, *qp2}},
|
||||
Measurement: "cpu",
|
||||
GroupBy: []*QueryPart{groupBy1},
|
||||
Tags: []*Tag{tag1, tag2},
|
||||
}
|
||||
|
||||
res, err := builder.Build(query)
|
||||
So(err, ShouldNotBeNil)
|
||||
So(res, ShouldEqual, "")
|
||||
rawQuery, err := builder.Build(query)
|
||||
So(err, ShouldBeNil)
|
||||
So(rawQuery, ShouldEqual, `SELECT mean("value") FROM "cpu" WHERE "hostname" = 'server1' OR "hostname" = 'server2' AND $timeFilter GROUP BY time($interval)`)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
describe('render series with mesurement only', function() {
|
||||
it('should generate correct query', function() {
|
||||
var query = new InfluxQuery({
|
||||
measurement: 'cpu',
|
||||
}, templateSrv, {});
|
||||
|
||||
var queryText = query.render();
|
||||
expect(queryText).to.be('SELECT mean("value") FROM "cpu" WHERE $timeFilter GROUP BY time($interval) fill(null)');
|
||||
});
|
||||
});
|
||||
*/
|
||||
|
||||
/*
|
||||
describe('series with tags OR condition', function() {
|
||||
it('should generate correct query', function() {
|
||||
var query = new InfluxQuery({
|
||||
measurement: 'cpu',
|
||||
groupBy: [{type: 'time', params: ['auto']}],
|
||||
tags: [{key: 'hostname', value: 'server1'}, {key: 'hostname', value: 'server2', condition: "OR"}]
|
||||
}, templateSrv, {});
|
||||
|
||||
var queryText = query.render();
|
||||
expect(queryText).to.be('SELECT mean("value") FROM "cpu" WHERE "hostname" = \'server1\' OR "hostname" = \'server2\' AND ' +
|
||||
'$timeFilter GROUP BY time($interval)');
|
||||
});
|
||||
});
|
||||
*/
|
||||
|
@ -91,13 +91,13 @@ func fieldRenderer(part *QueryPart, innerExpr string) string {
|
||||
}
|
||||
|
||||
func functionRenderer(part *QueryPart, innerExpr string) string {
|
||||
params := strings.Join(part.Params, ", ")
|
||||
|
||||
if len(part.Params) > 0 {
|
||||
return fmt.Sprintf("%s(%s, %s)", part.Type, innerExpr, params)
|
||||
if innerExpr != "" {
|
||||
part.Params = append([]string{innerExpr}, part.Params...)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s(%s)", part.Type, innerExpr)
|
||||
params := strings.Join(part.Params, ", ")
|
||||
|
||||
return fmt.Sprintf("%s(%s)", part.Type, params)
|
||||
}
|
||||
|
||||
func suffixRenderer(part *QueryPart, innerExpr string) string {
|
||||
|
Loading…
Reference in New Issue
Block a user