Interpolate $__interval in backend for alerting with sql datasources (#13156)
add support for interpolate $__interval and $__interval_ms in sql datasources
This commit is contained in:
committed by
Marcus Efraimsson
parent
bae560717d
commit
0254a29e35
@@ -9,18 +9,21 @@ import (
|
||||
"github.com/grafana/grafana/pkg/tsdb"
|
||||
)
|
||||
|
||||
//const rsString = `(?:"([^"]*)")`;
|
||||
const rsIdentifier = `([_a-zA-Z0-9]+)`
|
||||
const sExpr = `\$` + rsIdentifier + `\(([^\)]*)\)`
|
||||
|
||||
type postgresMacroEngine struct {
|
||||
*tsdb.SqlMacroEngineBase
|
||||
timeRange *tsdb.TimeRange
|
||||
query *tsdb.Query
|
||||
timescaledb bool
|
||||
}
|
||||
|
||||
func newPostgresMacroEngine(timescaledb bool) tsdb.SqlMacroEngine {
|
||||
return &postgresMacroEngine{timescaledb: timescaledb}
|
||||
return &postgresMacroEngine{
|
||||
SqlMacroEngineBase: tsdb.NewSqlMacroEngineBase(),
|
||||
timescaledb: timescaledb,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *postgresMacroEngine) Interpolate(query *tsdb.Query, timeRange *tsdb.TimeRange, sql string) (string, error) {
|
||||
@@ -29,7 +32,7 @@ func (m *postgresMacroEngine) Interpolate(query *tsdb.Query, timeRange *tsdb.Tim
|
||||
rExp, _ := regexp.Compile(sExpr)
|
||||
var macroError error
|
||||
|
||||
sql = replaceAllStringSubmatchFunc(rExp, sql, func(groups []string) string {
|
||||
sql = m.ReplaceAllStringSubmatchFunc(rExp, sql, func(groups []string) string {
|
||||
|
||||
// detect if $__timeGroup is supposed to add AS time for pre 5.3 compatibility
|
||||
// if there is a ',' directly after the macro call $__timeGroup is probably used
|
||||
@@ -66,23 +69,6 @@ func (m *postgresMacroEngine) Interpolate(query *tsdb.Query, timeRange *tsdb.Tim
|
||||
return sql, nil
|
||||
}
|
||||
|
||||
func replaceAllStringSubmatchFunc(re *regexp.Regexp, str string, repl func([]string) string) string {
|
||||
result := ""
|
||||
lastIndex := 0
|
||||
|
||||
for _, v := range re.FindAllSubmatchIndex([]byte(str), -1) {
|
||||
groups := []string{}
|
||||
for i := 0; i < len(v); i += 2 {
|
||||
groups = append(groups, str[v[i]:v[i+1]])
|
||||
}
|
||||
|
||||
result += str[lastIndex:v[0]] + repl(groups)
|
||||
lastIndex = v[1]
|
||||
}
|
||||
|
||||
return result + str[lastIndex:]
|
||||
}
|
||||
|
||||
func (m *postgresMacroEngine) evaluateMacro(name string, args []string) (string, error) {
|
||||
switch name {
|
||||
case "__time":
|
||||
|
||||
@@ -43,6 +43,11 @@ func TestPostgres(t *testing.T) {
|
||||
return x, nil
|
||||
}
|
||||
|
||||
origInterpolate := tsdb.Interpolate
|
||||
tsdb.Interpolate = func(query *tsdb.Query, timeRange *tsdb.TimeRange, sql string) (string, error) {
|
||||
return sql, nil
|
||||
}
|
||||
|
||||
endpoint, err := newPostgresQueryEndpoint(&models.DataSource{
|
||||
JsonData: simplejson.New(),
|
||||
SecureJsonData: securejsondata.SecureJsonData{},
|
||||
@@ -55,6 +60,7 @@ func TestPostgres(t *testing.T) {
|
||||
Reset(func() {
|
||||
sess.Close()
|
||||
tsdb.NewXormEngine = origXormEngine
|
||||
tsdb.Interpolate = origInterpolate
|
||||
})
|
||||
|
||||
Convey("Given a table with different native data types", func() {
|
||||
@@ -222,6 +228,40 @@ func TestPostgres(t *testing.T) {
|
||||
}
|
||||
})
|
||||
|
||||
Convey("When doing a metric query using timeGroup and $__interval", func() {
|
||||
mockInterpolate := tsdb.Interpolate
|
||||
tsdb.Interpolate = origInterpolate
|
||||
|
||||
Reset(func() {
|
||||
tsdb.Interpolate = mockInterpolate
|
||||
})
|
||||
|
||||
Convey("Should replace $__interval", func() {
|
||||
query := &tsdb.TsdbQuery{
|
||||
Queries: []*tsdb.Query{
|
||||
{
|
||||
DataSource: &models.DataSource{},
|
||||
Model: simplejson.NewFromAny(map[string]interface{}{
|
||||
"rawSql": "SELECT $__timeGroup(time, $__interval) AS time, avg(value) as value FROM metric GROUP BY 1 ORDER BY 1",
|
||||
"format": "time_series",
|
||||
}),
|
||||
RefId: "A",
|
||||
},
|
||||
},
|
||||
TimeRange: &tsdb.TimeRange{
|
||||
From: fmt.Sprintf("%v", fromStart.Unix()*1000),
|
||||
To: fmt.Sprintf("%v", fromStart.Add(30*time.Minute).Unix()*1000),
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := endpoint.Query(nil, nil, query)
|
||||
So(err, ShouldBeNil)
|
||||
queryResult := resp.Results["A"]
|
||||
So(queryResult.Error, ShouldBeNil)
|
||||
So(queryResult.Meta.Get("sql").MustString(), ShouldEqual, "SELECT floor(extract(epoch from time)/60)*60 AS time, avg(value) as value FROM metric GROUP BY 1 ORDER BY 1")
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When doing a metric query using timeGroup with NULL fill enabled", func() {
|
||||
query := &tsdb.TsdbQuery{
|
||||
Queries: []*tsdb.Query{
|
||||
|
||||
Reference in New Issue
Block a user