1package influxdb 2 3import ( 4 "fmt" 5 "strings" 6 7 "github.com/grafana/grafana-plugin-sdk-go/backend" 8) 9 10var renders map[string]QueryDefinition 11 12type DefinitionParameters struct { 13 Name string 14 Type string 15} 16 17type QueryDefinition struct { 18 Renderer func(query *Query, queryContext *backend.QueryDataRequest, part *QueryPart, innerExpr string) string 19 Params []DefinitionParameters 20} 21 22func init() { 23 renders = make(map[string]QueryDefinition) 24 25 renders["field"] = QueryDefinition{Renderer: fieldRenderer} 26 27 renders["spread"] = QueryDefinition{Renderer: functionRenderer} 28 renders["count"] = QueryDefinition{Renderer: functionRenderer} 29 renders["distinct"] = QueryDefinition{Renderer: functionRenderer} 30 renders["integral"] = QueryDefinition{Renderer: functionRenderer} 31 renders["mean"] = QueryDefinition{Renderer: functionRenderer} 32 renders["median"] = QueryDefinition{Renderer: functionRenderer} 33 renders["sum"] = QueryDefinition{Renderer: functionRenderer} 34 renders["mode"] = QueryDefinition{Renderer: functionRenderer} 35 renders["cumulative_sum"] = QueryDefinition{Renderer: functionRenderer} 36 renders["non_negative_difference"] = QueryDefinition{Renderer: functionRenderer} 37 38 renders["holt_winters"] = QueryDefinition{ 39 Renderer: functionRenderer, 40 Params: []DefinitionParameters{{Name: "number", Type: "number"}, {Name: "season", Type: "number"}}, 41 } 42 renders["holt_winters_with_fit"] = QueryDefinition{ 43 Renderer: functionRenderer, 44 Params: []DefinitionParameters{{Name: "number", Type: "number"}, {Name: "season", Type: "number"}}, 45 } 46 47 renders["derivative"] = QueryDefinition{ 48 Renderer: functionRenderer, 49 Params: []DefinitionParameters{{Name: "duration", Type: "interval"}}, 50 } 51 52 renders["non_negative_derivative"] = QueryDefinition{ 53 Renderer: functionRenderer, 54 Params: []DefinitionParameters{{Name: "duration", Type: "interval"}}, 55 } 56 renders["difference"] = QueryDefinition{Renderer: functionRenderer} 57 renders["moving_average"] = QueryDefinition{ 58 Renderer: functionRenderer, 59 Params: []DefinitionParameters{{Name: "window", Type: "number"}}, 60 } 61 renders["stddev"] = QueryDefinition{Renderer: functionRenderer} 62 renders["time"] = QueryDefinition{ 63 Renderer: functionRenderer, 64 Params: []DefinitionParameters{{Name: "interval", Type: "time"}, {Name: "offset", Type: "time"}}, 65 } 66 renders["fill"] = QueryDefinition{ 67 Renderer: functionRenderer, 68 Params: []DefinitionParameters{{Name: "fill", Type: "string"}}, 69 } 70 renders["elapsed"] = QueryDefinition{ 71 Renderer: functionRenderer, 72 Params: []DefinitionParameters{{Name: "duration", Type: "interval"}}, 73 } 74 renders["bottom"] = QueryDefinition{ 75 Renderer: functionRenderer, 76 Params: []DefinitionParameters{{Name: "count", Type: "int"}}, 77 } 78 79 renders["first"] = QueryDefinition{Renderer: functionRenderer} 80 renders["last"] = QueryDefinition{Renderer: functionRenderer} 81 renders["max"] = QueryDefinition{Renderer: functionRenderer} 82 renders["min"] = QueryDefinition{Renderer: functionRenderer} 83 renders["percentile"] = QueryDefinition{ 84 Renderer: functionRenderer, 85 Params: []DefinitionParameters{{Name: "nth", Type: "int"}}, 86 } 87 renders["top"] = QueryDefinition{ 88 Renderer: functionRenderer, 89 Params: []DefinitionParameters{{Name: "count", Type: "int"}}, 90 } 91 renders["tag"] = QueryDefinition{ 92 Renderer: fieldRenderer, 93 Params: []DefinitionParameters{{Name: "tag", Type: "string"}}, 94 } 95 96 renders["math"] = QueryDefinition{Renderer: suffixRenderer} 97 renders["alias"] = QueryDefinition{Renderer: aliasRenderer} 98} 99 100func fieldRenderer(query *Query, queryContext *backend.QueryDataRequest, part *QueryPart, innerExpr string) string { 101 if part.Params[0] == "*" { 102 return "*" 103 } 104 return fmt.Sprintf(`"%s"`, part.Params[0]) 105} 106 107func functionRenderer(query *Query, queryContext *backend.QueryDataRequest, part *QueryPart, innerExpr string) string { 108 for i, param := range part.Params { 109 if part.Type == "time" && param == "auto" { 110 part.Params[i] = "$__interval" 111 } 112 } 113 114 if innerExpr != "" { 115 part.Params = append([]string{innerExpr}, part.Params...) 116 } 117 118 params := strings.Join(part.Params, ", ") 119 120 return fmt.Sprintf("%s(%s)", part.Type, params) 121} 122 123func suffixRenderer(query *Query, queryContext *backend.QueryDataRequest, part *QueryPart, innerExpr string) string { 124 return fmt.Sprintf("%s %s", innerExpr, part.Params[0]) 125} 126 127func aliasRenderer(query *Query, queryContext *backend.QueryDataRequest, part *QueryPart, innerExpr string) string { 128 return fmt.Sprintf(`%s AS "%s"`, innerExpr, part.Params[0]) 129} 130 131func NewQueryPart(typ string, params []string) (*QueryPart, error) { 132 def, exist := renders[typ] 133 if !exist { 134 return nil, fmt.Errorf("missing query definition for %q", typ) 135 } 136 137 return &QueryPart{ 138 Type: typ, 139 Params: params, 140 Def: def, 141 }, nil 142} 143 144type QueryPart struct { 145 Def QueryDefinition 146 Type string 147 Params []string 148} 149 150func (qp *QueryPart) Render(query *Query, queryContext *backend.QueryDataRequest, expr string) string { 151 return qp.Def.Renderer(query, queryContext, qp, expr) 152} 153