From f17cf6bb0966fd41e5077a0acb207e7a99f2e876 Mon Sep 17 00:00:00 2001 From: Chris Goller Date: Wed, 19 Apr 2017 11:03:53 -0500 Subject: [PATCH] Add InfluxQL template rendering --- influx/templates.go | 53 +++++++++++++++ influx/templates_test.go | 139 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 192 insertions(+) create mode 100644 influx/templates.go create mode 100644 influx/templates_test.go diff --git a/influx/templates.go b/influx/templates.go new file mode 100644 index 0000000000..24f5338baa --- /dev/null +++ b/influx/templates.go @@ -0,0 +1,53 @@ +package influx + +import "strings" + +// TempValue is a value use to replace a template in an InfluxQL query +type TempValue struct { + Value string `json:"value"` + Type string `json:"type"` +} + +// TempVar is a named variable within an InfluxQL query to be replaced with Values +type TempVar struct { + Var string `json:"tempVar"` + Values []TempValue `json:"values"` +} + +// String converts the template variable into a correct InfluxQL string based +// on its type +func (t TempVar) String() string { + if len(t.Values) == 0 { + return "" + } + switch t.Values[0].Type { + case "tagKey", "fieldKey": + return `"` + t.Values[0].Value + `"` + case "tagValue": + return `'` + t.Values[0].Value + `'` + case "csv": + return t.Values[0].Value + default: + return "" + } +} + +// TempVars are template variables to replace within an InfluxQL query +type TempVars struct { + Vars []TempVar `json:"tempVars"` +} + +// TemplateReplace replaces templates with values within the query string +func TemplateReplace(query string, templates TempVars) string { + replacements := []string{} + for _, v := range templates.Vars { + newVal := v.String() + if newVal != "" { + replacements = append(replacements, v.Var, newVal) + } + } + + replacer := strings.NewReplacer(replacements...) + replaced := replacer.Replace(query) + return replaced +} diff --git a/influx/templates_test.go b/influx/templates_test.go new file mode 100644 index 0000000000..ba0ba26407 --- /dev/null +++ b/influx/templates_test.go @@ -0,0 +1,139 @@ +package influx + +import ( + "testing" +) + +func TestTemplateReplace(t *testing.T) { + tests := []struct { + name string + query string + vars TempVars + want string + }{ + { + name: "select with parameters", + query: "$METHOD field1, $field FROM $measurement WHERE temperature > $temperature", + vars: TempVars{ + Vars: []TempVar{ + { + Var: "$temperature", + Values: []TempValue{ + { + Type: "csv", + Value: "10", + }, + }, + }, + { + Var: "$field", + Values: []TempValue{ + { + Type: "fieldKey", + Value: "field2", + }, + }, + }, + { + Var: "$METHOD", + Values: []TempValue{ + { + Type: "csv", + Value: "SELECT", + }, + }, + }, + { + Var: "$measurement", + Values: []TempValue{ + { + Type: "csv", + Value: `"cpu"`, + }, + }, + }, + }, + }, + want: `SELECT field1, "field2" FROM "cpu" WHERE temperature > 10`, + }, + { + name: "select with parameters and aggregates", + query: `SELECT mean($field) FROM "cpu" WHERE $tag = $value GROUP BY $tag`, + vars: TempVars{ + Vars: []TempVar{ + { + Var: "$value", + Values: []TempValue{ + { + Type: "tagValue", + Value: "howdy.com", + }, + }, + }, + { + Var: "$tag", + Values: []TempValue{ + { + Type: "tagKey", + Value: "host", + }, + }, + }, + { + Var: "$field", + Values: []TempValue{ + { + Type: "fieldKey", + Value: "field", + }, + }, + }, + }, + }, + want: `SELECT mean("field") FROM "cpu" WHERE "host" = 'howdy.com' GROUP BY "host"`, + }, + { + name: "Non-existant parameters", + query: `SELECT $field FROM "cpu"`, + want: `SELECT $field FROM "cpu"`, + }, + { + name: "var without a value", + query: `SELECT $field FROM "cpu"`, + vars: TempVars{ + Vars: []TempVar{ + { + Var: "$field", + }, + }, + }, + want: `SELECT $field FROM "cpu"`, + }, + { + name: "var with unknown type", + query: `SELECT $field FROM "cpu"`, + vars: TempVars{ + Vars: []TempVar{ + { + Var: "$field", + Values: []TempValue{ + { + Type: "who knows?", + Value: "field", + }, + }, + }, + }, + }, + want: `SELECT $field FROM "cpu"`, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := TemplateReplace(tt.query, tt.vars) + if got != tt.want { + t.Errorf("TestParse %s =\n%s\nwant\n%s", tt.name, got, tt.want) + } + }) + } +}