package models import ( "errors" "fmt" "strconv" "time" "github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/influxdata/influxql" "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/infra/log" ) var ( ErrInvalidQuery = errors.New("invalid InfluxDB query") ) type InfluxdbQueryParser struct{} func QueryParse(query backend.DataQuery, logger log.Logger) (*Query, error) { model, err := simplejson.NewJson(query.JSON) if err != nil { return nil, fmt.Errorf("couldn't unmarshal query") } policy := model.Get("policy").MustString("default") rawQuery := model.Get("query").MustString("") useRawQuery := model.Get("rawQuery").MustBool(false) alias := model.Get("alias").MustString("") tz := model.Get("tz").MustString("") limit := model.Get("limit").MustString("") slimit := model.Get("slimit").MustString("") orderByTime := model.Get("orderByTime").MustString("") measurement := model.Get("measurement").MustString("") resultFormat := model.Get("resultFormat").MustString("") adhocFilters, err := parseAdhocFilters(model.Get("adhocFilters").MustArray()) if err != nil { return nil, errors.Join(ErrInvalidQuery, err) } tags, err := parseTags(model) if err != nil { return nil, errors.Join(ErrInvalidQuery, err) } groupBys, err := parseGroupBy(model) if err != nil { return nil, errors.Join(ErrInvalidQuery, err) } selects, err := parseSelects(model) if err != nil { return nil, errors.Join(ErrInvalidQuery, err) } interval := query.Interval // we make sure it is at least 1 millisecond minInterval := time.Millisecond if interval < minInterval { interval = minInterval } var statement influxql.Statement if useRawQuery { statement, err = influxql.ParseStatement(rawQuery) if err != nil { logger.Debug(fmt.Sprintf("Couldn't parse raw query: %v", err), "rawQuery", rawQuery) } } return &Query{ Measurement: measurement, Policy: policy, GroupBy: groupBys, Tags: tags, Selects: selects, RawQuery: rawQuery, Interval: interval, Alias: alias, UseRawQuery: useRawQuery, Tz: tz, Limit: limit, Slimit: slimit, OrderByTime: orderByTime, ResultFormat: resultFormat, Statement: statement, AdhocFilters: adhocFilters, }, nil } func parseSelects(model *simplejson.Json) ([]*Select, error) { selectObjs := model.Get("select").MustArray() result := make([]*Select, 0, len(selectObjs)) for _, selectObj := range selectObjs { selectJson := simplejson.NewFromAny(selectObj) var parts Select for _, partObj := range selectJson.MustArray() { part := simplejson.NewFromAny(partObj) queryPart, err := parseQueryPart(part) if err != nil { return nil, err } parts = append(parts, *queryPart) } result = append(result, &parts) } return result, nil } func parseAdhocFilters(adhocFilters []any) ([]*Tag, error) { result := make([]*Tag, 0, len(adhocFilters)) for _, t := range adhocFilters { tagJson := simplejson.NewFromAny(t) tag := &Tag{} var err error tag.Key, err = tagJson.Get("key").String() if err != nil { return nil, err } tag.Value, err = tagJson.Get("value").String() if err != nil { return nil, err } operator, err := tagJson.Get("operator").String() if err == nil { tag.Operator = operator } condition, err := tagJson.Get("condition").String() if err == nil { tag.Condition = condition } result = append(result, tag) } return result, nil } func parseTags(model *simplejson.Json) ([]*Tag, error) { tags := model.Get("tags").MustArray() result := make([]*Tag, 0, len(tags)) for _, t := range tags { tagJson := simplejson.NewFromAny(t) tag := &Tag{} var err error tag.Key, err = tagJson.Get("key").String() if err != nil { return nil, err } tag.Value, err = tagJson.Get("value").String() if err != nil { return nil, err } operator, err := tagJson.Get("operator").String() if err == nil { tag.Operator = operator } condition, err := tagJson.Get("condition").String() if err == nil { tag.Condition = condition } result = append(result, tag) } return result, nil } func parseQueryPart(model *simplejson.Json) (*QueryPart, error) { typ, err := model.Get("type").String() if err != nil { return nil, err } var params []string for _, paramObj := range model.Get("params").MustArray() { param := simplejson.NewFromAny(paramObj) stringParam, err := param.String() if err == nil { params = append(params, stringParam) continue } intParam, err := param.Int() if err == nil { params = append(params, strconv.Itoa(intParam)) continue } return nil, err } qp, err := NewQueryPart(typ, params) if err != nil { return nil, err } return qp, nil } func parseGroupBy(model *simplejson.Json) ([]*QueryPart, error) { groupBy := model.Get("groupBy").MustArray() result := make([]*QueryPart, 0, len(groupBy)) for _, groupObj := range groupBy { groupJson := simplejson.NewFromAny(groupObj) queryPart, err := parseQueryPart(groupJson) if err != nil { return nil, err } result = append(result, queryPart) } return result, nil }