grafana/pkg/tsdb/elasticsearch/parse_query.go
Ivana Huckova 2a1a5145d0
Elasticsearch: Fix using of individual query time ranges when querying (#84201)
* WIP - proof of concept

* Update pkg/tsdb/elasticsearch/client/client.go

Co-authored-by: Sven Grossmann <sven.grossmann@grafana.com>

* update and add test

* lint

* Fix lint

* Bring back logging when creating client

---------

Co-authored-by: Sven Grossmann <sven.grossmann@grafana.com>
2024-03-13 12:49:35 +02:00

119 lines
3.5 KiB
Go

package elasticsearch
import (
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
)
func parseQuery(tsdbQuery []backend.DataQuery, logger log.Logger) ([]*Query, error) {
queries := make([]*Query, 0)
for _, q := range tsdbQuery {
model, err := simplejson.NewJson(q.JSON)
if err != nil {
return nil, err
}
// we had a string-field named `timeField` in the past. we do not use it anymore.
// please do not create a new field with that name, to avoid potential problems with old, persisted queries.
rawQuery := model.Get("query").MustString()
bucketAggs, err := parseBucketAggs(model)
if err != nil {
logger.Error("Failed to parse bucket aggs in query", "error", err, "model", string(q.JSON))
return nil, err
}
metrics, err := parseMetrics(model)
if err != nil {
logger.Error("Failed to parse metrics in query", "error", err, "model", string(q.JSON))
return nil, err
}
alias := model.Get("alias").MustString("")
intervalMs := model.Get("intervalMs").MustInt64(0)
interval := q.Interval
queries = append(queries, &Query{
RawQuery: rawQuery,
BucketAggs: bucketAggs,
Metrics: metrics,
Alias: alias,
Interval: interval,
IntervalMs: intervalMs,
RefID: q.RefID,
MaxDataPoints: q.MaxDataPoints,
TimeRange: q.TimeRange,
})
}
return queries, nil
}
func parseBucketAggs(model *simplejson.Json) ([]*BucketAgg, error) {
var err error
bucketAggs := model.Get("bucketAggs").MustArray()
result := make([]*BucketAgg, 0, len(bucketAggs))
for _, t := range bucketAggs {
aggJSON := simplejson.NewFromAny(t)
agg := &BucketAgg{}
agg.Type, err = aggJSON.Get("type").String()
if err != nil {
return nil, err
}
agg.ID, err = aggJSON.Get("id").String()
if err != nil {
return nil, err
}
agg.Field = aggJSON.Get("field").MustString()
agg.Settings = simplejson.NewFromAny(aggJSON.Get("settings").MustMap())
result = append(result, agg)
}
return result, nil
}
func parseMetrics(model *simplejson.Json) ([]*MetricAgg, error) {
var err error
metrics := model.Get("metrics").MustArray()
result := make([]*MetricAgg, 0, len(metrics))
for _, t := range metrics {
metricJSON := simplejson.NewFromAny(t)
metric := &MetricAgg{}
metric.Field = metricJSON.Get("field").MustString()
metric.Hide = metricJSON.Get("hide").MustBool(false)
metric.ID = metricJSON.Get("id").MustString()
metric.PipelineAggregate = metricJSON.Get("pipelineAgg").MustString()
// In legacy editors, we were storing empty settings values as "null"
// The new editor doesn't store empty strings at all
// We need to ensures backward compatibility with old queries and remove empty fields
settings := metricJSON.Get("settings").MustMap()
for k, v := range settings {
if v == "null" {
delete(settings, k)
}
}
metric.Settings = simplejson.NewFromAny(settings)
metric.Meta = simplejson.NewFromAny(metricJSON.Get("meta").MustMap())
metric.Type, err = metricJSON.Get("type").String()
if err != nil {
return nil, err
}
if isPipelineAggWithMultipleBucketPaths(metric.Type) {
metric.PipelineVariables = map[string]string{}
pvArr := metricJSON.Get("pipelineVariables").MustArray()
for _, v := range pvArr {
kv := v.(map[string]any)
metric.PipelineVariables[kv["name"].(string)] = kv["pipelineAgg"].(string)
}
}
result = append(result, metric)
}
return result, nil
}