Просмотр исходного кода

feat(influxdb): add querypart renderers

bergquist 9 лет назад
Родитель
Сommit
c7abd3ba4e
4 измененных файлов с 242 добавлено и 115 удалено
  1. 0 5
      pkg/tsdb/influxdb/models.go
  2. 76 62
      pkg/tsdb/influxdb/parser_test.go
  3. 121 2
      pkg/tsdb/influxdb/query_part.go
  4. 45 46
      pkg/tsdb/influxdb/query_part_test.go

+ 0 - 5
pkg/tsdb/influxdb/models.go

@@ -15,11 +15,6 @@ type Tag struct {
 	Value    string
 	Value    string
 }
 }
 
 
-type QueryPart struct {
-	Type   string
-	Params []string
-}
-
 type Select []QueryPart
 type Select []QueryPart
 
 
 type InfluxDbSelect struct {
 type InfluxDbSelect struct {

+ 76 - 62
pkg/tsdb/influxdb/parser_test.go

@@ -14,70 +14,84 @@ func TestInfluxdbQueryParser(t *testing.T) {
 
 
 		Convey("converting metric name", func() {
 		Convey("converting metric name", func() {
 			json := `
 			json := `
-      {
-        "dsType": "influxdb",
-        "groupBy": [
-          {
-            "params": [
-              "$interval"
-            ],
-            "type": "time"
-          },
-          {
-            "type": "tag",
-            "params": [
-              "datacenter"
-            ]
-          },
-          {
-            "params": [
-              "null"
-            ],
-            "type": "fill"
-          }
-        ],
-        "measurement": "logins.count",
-        "policy": "default",
-        "refId": "B",
-        "resultFormat": "time_series",
-        "select": [
-          [
-            {
-              "params": [
-                "value"
+                  {
+              "dsType": "influxdb",
+              "groupBy": [
+                {
+                  "params": [
+                    "$interval"
+                  ],
+                  "type": "time"
+                },
+                {
+                  "params": [
+                    "datacenter"
+                  ],
+                  "type": "tag"
+                },
+                {
+                  "params": [
+                    "null"
+                  ],
+                  "type": "fill"
+                }
               ],
               ],
-              "type": "field"
-            },
-            {
-              "params": [
-
-              ],
-              "type": "count"
-            }
-          ],
-          [
-            {
-              "params": [
-                "value"
-              ],
-              "type": "field"
-            },
-            {
-              "params": [
-
+              "measurement": "logins.count",
+              "policy": "default",
+              "refId": "B",
+              "resultFormat": "time_series",
+              "select": [
+                [
+                  {
+                    "type": "field",
+                    "params": [
+                      "value"
+                    ]
+                  },
+                  {
+                    "type": "count",
+                    "params": []
+                  }
+                ],
+                [
+                  {
+                    "type": "field",
+                    "params": [
+                      "value"
+                    ]
+                  },
+                  {
+                    "type": "mean",
+                    "params": []
+                  }
+                ],
+                [
+                  {
+                    "type": "field",
+                    "params": [
+                      "value"
+                    ]
+                  },
+                  {
+                    "type": "mean",
+                    "params": []
+                  },
+                  {
+                    "type": "math",
+                    "params": [
+                      " / 100"
+                    ]
+                  }
+                ]
               ],
               ],
-              "type": "mean"
+              "tags": [
+                {
+                  "key": "datacenter",
+                  "operator": "=",
+                  "value": "America"
+                }
+              ]
             }
             }
-          ]
-        ],
-        "tags": [
-          {
-            "key": "datacenter",
-            "operator": "=",
-            "value": "America"
-          }
-        ]
-      }
       `
       `
 
 
 			modelJson, err := simplejson.NewJson([]byte(json))
 			modelJson, err := simplejson.NewJson([]byte(json))
@@ -86,7 +100,7 @@ func TestInfluxdbQueryParser(t *testing.T) {
 			res, err := parser.Parse(modelJson)
 			res, err := parser.Parse(modelJson)
 			So(err, ShouldBeNil)
 			So(err, ShouldBeNil)
 			So(len(res.GroupBy), ShouldEqual, 3)
 			So(len(res.GroupBy), ShouldEqual, 3)
-			So(len(res.Selects), ShouldEqual, 2)
+			So(len(res.Selects), ShouldEqual, 3)
 			So(len(res.Tags), ShouldEqual, 1)
 			So(len(res.Tags), ShouldEqual, 1)
 		})
 		})
 	})
 	})

+ 121 - 2
pkg/tsdb/influxdb/query_part.go

@@ -1,5 +1,124 @@
 package influxdb
 package influxdb
 
 
-type Selector interface {
-	Render(input string) string
+import (
+	"fmt"
+	"strings"
+)
+
+var renders map[string]QueryDefinition
+
+type QueryDefinition struct {
+	Renderer func(part *QueryPart, innerExpr string) string
+}
+
+func init() {
+	renders = make(map[string]QueryDefinition)
+
+	renders["field"] = QueryDefinition{Renderer: fieldRenderer}
+
+	renders["spread"] = QueryDefinition{Renderer: functionRenderer}
+	renders["count"] = QueryDefinition{Renderer: functionRenderer}
+	renders["distinct"] = QueryDefinition{Renderer: functionRenderer}
+	renders["integral"] = QueryDefinition{Renderer: functionRenderer}
+	renders["mean"] = QueryDefinition{Renderer: functionRenderer}
+	renders["median"] = QueryDefinition{Renderer: functionRenderer}
+	renders["sum"] = QueryDefinition{Renderer: functionRenderer}
+
+	renders["derivative"] = QueryDefinition{
+		Renderer: functionRenderer,
+		//params: [{ name: "duration", type: "interval", options: ['1s', '10s', '1m', '5m', '10m', '15m', '1h']}],
+	}
+
+	renders["non_negative_derivative"] = QueryDefinition{
+		Renderer: functionRenderer,
+		//params: [{ name: "duration", type: "interval", options: ['1s', '10s', '1m', '5m', '10m', '15m', '1h']}],
+	}
+	renders["difference"] = QueryDefinition{Renderer: functionRenderer}
+	renders["moving_average"] = QueryDefinition{
+		Renderer: functionRenderer,
+		//params: [{ name: "window", type: "number", options: [5, 10, 20, 30, 40]}]
+	}
+	renders["stddev"] = QueryDefinition{Renderer: functionRenderer}
+	renders["time"] = QueryDefinition{
+		Renderer: functionRenderer,
+		//params: [{ name: "interval", type: "time", options: ['auto', '1s', '10s', '1m', '5m', '10m', '15m', '1h'] }],
+	}
+	renders["fill"] = QueryDefinition{
+		Renderer: functionRenderer,
+		//params: [{ name: "fill", type: "string", options: ['none', 'null', '0', 'previous'] }],
+	}
+	renders["elapsed"] = QueryDefinition{
+		Renderer: functionRenderer,
+		//params: [{ name: "duration", type: "interval", options: ['1s', '10s', '1m', '5m', '10m', '15m', '1h']}],
+	}
+	renders["bottom"] = QueryDefinition{
+		Renderer: functionRenderer,
+		//params: [{name: 'count', type: 'int'}],
+	}
+
+	renders["first"] = QueryDefinition{Renderer: functionRenderer}
+	renders["last"] = QueryDefinition{Renderer: functionRenderer}
+	renders["max"] = QueryDefinition{Renderer: functionRenderer}
+	renders["min"] = QueryDefinition{Renderer: functionRenderer}
+	renders["percentile"] = QueryDefinition{
+		Renderer: functionRenderer,
+		//params: [{name: 'nth', type: 'int'}],
+	}
+	renders["top"] = QueryDefinition{
+		Renderer: functionRenderer,
+		//params: [{name: 'count', type: 'int'}],
+	}
+	renders["tag"] = QueryDefinition{
+		Renderer: fieldRenderer,
+		//params: [{name: 'tag', type: 'string', dynamicLookup: true}],
+	}
+
+	renders["math"] = QueryDefinition{Renderer: suffixRenderer}
+	renders["alias"] = QueryDefinition{Renderer: aliasRenderer}
+}
+
+func fieldRenderer(part *QueryPart, innerExpr string) string {
+	if part.Params[0] == "*" {
+		return "*"
+	}
+	return fmt.Sprintf(`"%v"`, part.Params[0])
+}
+
+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)
+	}
+
+	return fmt.Sprintf("%s(%s)", part.Type, innerExpr)
+}
+
+func suffixRenderer(part *QueryPart, innerExpr string) string {
+	return fmt.Sprintf("%s %s", innerExpr, part.Params[0])
+}
+
+func aliasRenderer(part *QueryPart, innerExpr string) string {
+	return fmt.Sprintf(`%s AS "%s"`, innerExpr, part.Params[0])
+}
+
+func (r QueryDefinition) Render(part *QueryPart, innerExpr string) string {
+	return r.Renderer(part, innerExpr)
+}
+
+type QueryPartDefinition struct {
+}
+
+type QueryPart struct {
+	Type   string
+	Params []string
+}
+
+func (qp *QueryPart) Render(expr string) (string, error) {
+	renderFn, exist := renders[qp.Type]
+	if !exist {
+		return "", fmt.Errorf("could not find render strategy %s", qp.Type)
+	}
+
+	return renderFn.Renderer(qp, expr), nil
 }
 }

+ 45 - 46
pkg/tsdb/influxdb/query_part_test.go

@@ -9,55 +9,54 @@ import (
 func TestInfluxdbQueryPart(t *testing.T) {
 func TestInfluxdbQueryPart(t *testing.T) {
 	Convey("Influxdb query part builder", t, func() {
 	Convey("Influxdb query part builder", t, func() {
 
 
-		Convey("can build query", func() {
+		Convey("should handle field renderer parts", func() {
+			part := QueryPart{
+				Type:   "field",
+				Params: []string{"value"},
+			}
+
+			res, _ := part.Render("value")
+			So(res, ShouldEqual, `"value"`)
 		})
 		})
 
 
-		Convey("empty queries should return error", func() {
+		Convey("should handle nested function parts", func() {
+			part := QueryPart{
+				Type:   "derivative",
+				Params: []string{"10s"},
+			}
 
 
+			res, _ := part.Render("mean(value)")
+			So(res, ShouldEqual, "derivative(mean(value), 10s)")
+		})
+
+		Convey("should nest spread function", func() {
+			part := QueryPart{
+				Type: "spread",
+			}
+
+			res, err := part.Render("value")
+			So(err, ShouldBeNil)
+			So(res, ShouldEqual, "spread(value)")
+		})
+
+		Convey("should handle suffix parts", func() {
+			part := QueryPart{
+				Type:   "math",
+				Params: []string{"/ 100"},
+			}
+
+			res, _ := part.Render("mean(value)")
+			So(res, ShouldEqual, "mean(value) / 100")
+		})
+
+		Convey("should handle alias parts", func() {
+			part := QueryPart{
+				Type:   "alias",
+				Params: []string{"test"},
+			}
+
+			res, _ := part.Render("mean(value)")
+			So(res, ShouldEqual, `mean(value) AS "test"`)
 		})
 		})
 	})
 	})
 }
 }
-
-/*
-  describe('series with mesurement only', () => {
-    it('should handle nested function parts', () => {
-      var part = queryPart.create({
-        type: 'derivative',
-        params: ['10s'],
-      });
-
-      expect(part.text).to.be('derivative(10s)');
-      expect(part.render('mean(value)')).to.be('derivative(mean(value), 10s)');
-    });
-
-    it('should nest spread function', () => {
-      var part = queryPart.create({
-        type: 'spread'
-      });
-
-      expect(part.text).to.be('spread()');
-      expect(part.render('value')).to.be('spread(value)');
-    });
-
-    it('should handle suffirx parts', () => {
-      var part = queryPart.create({
-        type: 'math',
-        params: ['/ 100'],
-      });
-
-      expect(part.text).to.be('math(/ 100)');
-      expect(part.render('mean(value)')).to.be('mean(value) / 100');
-    });
-
-    it('should handle alias parts', () => {
-      var part = queryPart.create({
-        type: 'alias',
-        params: ['test'],
-      });
-
-      expect(part.text).to.be('alias(test)');
-      expect(part.render('mean(value)')).to.be('mean(value) AS "test"');
-    });
-
-  });
-*/