InfluxDB: Add new truthiness operators (Is and Is Not) to InfluxQL Query Builder (#77923)

* InfluxDB: Add new truthiness operators (`Is` and `Is Not`) to InfluxQL Editor for use with boolean fields

* InfluxDB: Make the front-end aware of the new operators so that translation between raw and builder works

* Chore: Add tests

* feat: identify type of field value to allow other types to work with Is/Is Not

Tags: always quote
Integer: Don't quote
Float: Don't quote
Boolean: Don't quote
String: Quote

* Chore: Add test-cases for type inference

* Update front-end to infer type for operators Is and Is Not

* chore: Add front-end tests

* chore: add additional front-end tests

* chore: fix failing lint test

* chore: fix tests (run prettier)
This commit is contained in:
Ben Tasker
2023-11-15 20:10:37 +00:00
committed by GitHub
parent a94acf4b63
commit f38f657f87
6 changed files with 291 additions and 5 deletions

View File

@@ -67,6 +67,45 @@ func (query *Query) renderTags() []string {
}
}
isOperatorTypeHandler := func(tag *Tag) (string, string) {
// Attempt to identify the type of the supplied value
var lowerValue = strings.ToLower(tag.Value)
var r = regexp.MustCompile(`^(-?)[0-9\.]+$`)
var textValue string
var operator string
// Perform operator replacements
switch tag.Operator {
case "Is":
operator = "="
case "Is Not":
operator = "!="
default:
// This should never happen
operator = "="
}
// Always quote tag values
if strings.HasSuffix(tag.Key, "::tag") {
textValue = fmt.Sprintf("'%s'", strings.ReplaceAll(tag.Value, `\`, `\\`))
return textValue, operator
}
// Try and discern the type of fields
if lowerValue == "true" || lowerValue == "false" {
// boolean, don't quote, but make lowercase
textValue = lowerValue
} else if r.MatchString(tag.Value) {
// Integer or float, don't quote
textValue = tag.Value
} else {
// String (or unknown) - quote
textValue = fmt.Sprintf("'%s'", strings.ReplaceAll(tag.Value, `\`, `\\`))
}
return textValue, operator
}
// quote value unless regex or number
var textValue string
switch tag.Operator {
@@ -74,6 +113,8 @@ func (query *Query) renderTags() []string {
textValue = tag.Value
case "<", ">", ">=", "<=":
textValue = tag.Value
case "Is", "Is Not":
textValue, tag.Operator = isOperatorTypeHandler(tag)
default:
textValue = fmt.Sprintf("'%s'", strings.ReplaceAll(tag.Value, `\`, `\\`))
}

View File

@@ -239,6 +239,47 @@ func TestInfluxdbQueryBuilder(t *testing.T) {
require.Equal(t, strings.Join(query.renderTags(), ""), `"key" <= 10001`)
})
t.Run("can render boolean equality tags", func(t *testing.T) {
query := &Query{Tags: []*Tag{{Operator: "Is", Value: "false", Key: "key"}}}
require.Equal(t, strings.Join(query.renderTags(), ""), `"key" = false`)
})
t.Run("can render boolean inequality tags", func(t *testing.T) {
query := &Query{Tags: []*Tag{{Operator: "Is Not", Value: "true", Key: "key"}}}
require.Equal(t, strings.Join(query.renderTags(), ""), `"key" != true`)
})
t.Run("can correct case of boolean tags", func(t *testing.T) {
query := &Query{Tags: []*Tag{{Operator: "Is", Value: "False", Key: "key"}}}
require.Equal(t, strings.Join(query.renderTags(), ""), `"key" = false`)
})
t.Run("can use strings with Is", func(t *testing.T) {
query := &Query{Tags: []*Tag{{Operator: "Is", Value: "A string", Key: "key"}}}
require.Equal(t, strings.Join(query.renderTags(), ""), `"key" = 'A string'`)
})
t.Run("can use integers with Is", func(t *testing.T) {
query := &Query{Tags: []*Tag{{Operator: "Is", Value: "123", Key: "key"}}}
require.Equal(t, strings.Join(query.renderTags(), ""), `"key" = 123`)
})
t.Run("can use negative integers with Is", func(t *testing.T) {
query := &Query{Tags: []*Tag{{Operator: "Is", Value: "-123", Key: "key"}}}
require.Equal(t, strings.Join(query.renderTags(), ""), `"key" = -123`)
})
t.Run("can use floats with Is", func(t *testing.T) {
query := &Query{Tags: []*Tag{{Operator: "Is", Value: "1.23", Key: "key"}}}
require.Equal(t, strings.Join(query.renderTags(), ""), `"key" = 1.23`)
})
t.Run("can use negative floats with Is", func(t *testing.T) {
query := &Query{Tags: []*Tag{{Operator: "Is", Value: "-1.23", Key: "key"}}}
require.Equal(t, strings.Join(query.renderTags(), ""), `"key" = -1.23`)
})
t.Run("can render string tags", func(t *testing.T) {
query := &Query{Tags: []*Tag{{Operator: "=", Value: "value", Key: "key"}}}