fix(predicate): add special tag key, fixed children number

pull/15692/head
Kelvin Wang 2019-10-31 14:16:53 -04:00
parent 0dde41f895
commit 45cbd5fd31
5 changed files with 128 additions and 18 deletions

View File

@ -31,7 +31,7 @@ func (op LogicalOperator) Value() (datatypes.Node_Logical, error) {
// LogicalNode is a node type includes a logical expression with other nodes.
type LogicalNode struct {
Operator LogicalOperator `json:"operator"`
Children []Node `json:"children"`
Children [2]Node `json:"children"`
}
// ToDataType convert a LogicalNode to datatypes.Node.

View File

@ -73,9 +73,7 @@ func Parse(sts string) (n Node, err error) {
}
func (p *parser) parseLogicalNode() (Node, error) {
n := &LogicalNode{
Children: make([]Node, 0),
}
n := new(LogicalNode)
for {
tok, pos, _ := p.scanIgnoreWhitespace()
switch tok {
@ -91,9 +89,30 @@ func (p *parser) parseLogicalNode() (Node, error) {
if err != nil {
return *n, err
}
n.Children = append(n.Children, tr)
if n.Children[0] == nil {
n.Children[0] = tr
} else {
n.Children[1] = tr
}
case influxql.AND:
n.Operator = LogicalAnd
if n.Children[1] == nil {
continue
}
var n1 Node
var err error
if tokNext := p.peekTok(); tokNext == influxql.LPAREN {
n1, err = p.parseLogicalNode()
} else {
n1, err = p.parseTagRuleNode()
}
if err != nil {
return *n, err
}
n = &LogicalNode{
Children: [2]Node{*n, n1},
Operator: LogicalAnd,
}
case influxql.OR:
return *n, &influxdb.Error{
Code: influxdb.EInvalid,
@ -112,7 +131,11 @@ func (p *parser) parseLogicalNode() (Node, error) {
Msg: fmt.Sprintf("extra ( seen"),
}
}
n.Children = append(n.Children, n1)
if n.Children[0] == nil {
n.Children[0] = n1
} else {
n.Children[1] = n1
}
case influxql.RPAREN:
p.openParen--
fallthrough
@ -123,7 +146,7 @@ func (p *parser) parseLogicalNode() (Node, error) {
Msg: fmt.Sprintf("extra ) seen"),
}
}
if len(n.Children) == 1 {
if n.Children[1] == nil {
return n.Children[0], nil
}
return *n, nil
@ -201,3 +224,13 @@ scanRegularTagValue:
}
}
}
// peekRune returns the next rune that would be read by the scanner.
func (p *parser) peekTok() influxql.Token {
tok, _, _ := p.scanIgnoreWhitespace()
if tok != influxql.EOF {
p.unscan()
}
return tok
}

View File

@ -18,10 +18,23 @@ func TestParseNode(t *testing.T) {
err error
}{
{
str: ` abc="opq" AND gender="male" AND temp=1123`,
node: LogicalNode{Operator: LogicalAnd, Children: []Node{
str: `abc=opq`,
node: TagRuleNode{Tag: influxdb.Tag{Key: "abc", Value: "opq"}},
},
{
str: `abc=opq and gender="male"`,
node: LogicalNode{Operator: LogicalAnd, Children: [2]Node{
TagRuleNode{Tag: influxdb.Tag{Key: "abc", Value: "opq"}},
TagRuleNode{Tag: influxdb.Tag{Key: "gender", Value: "male"}},
}},
},
{
str: ` abc="opq" AND gender="male" AND temp=1123`,
node: LogicalNode{Operator: LogicalAnd, Children: [2]Node{
LogicalNode{Operator: LogicalAnd, Children: [2]Node{
TagRuleNode{Tag: influxdb.Tag{Key: "abc", Value: "opq"}},
TagRuleNode{Tag: influxdb.Tag{Key: "gender", Value: "male"}},
}},
TagRuleNode{Tag: influxdb.Tag{Key: "temp", Value: "1123"}},
}},
},
@ -34,16 +47,18 @@ func TestParseNode(t *testing.T) {
},
{
str: ` (t1="v1" and t2="v2") and (t3=v3 and (t4=v4 and t5=v5 and t6=v6))`,
node: LogicalNode{Operator: LogicalAnd, Children: []Node{
LogicalNode{Operator: LogicalAnd, Children: []Node{
node: LogicalNode{Operator: LogicalAnd, Children: [2]Node{
LogicalNode{Operator: LogicalAnd, Children: [2]Node{
TagRuleNode{Tag: influxdb.Tag{Key: "t1", Value: "v1"}},
TagRuleNode{Tag: influxdb.Tag{Key: "t2", Value: "v2"}},
}},
LogicalNode{Operator: LogicalAnd, Children: []Node{
LogicalNode{Operator: LogicalAnd, Children: [2]Node{
TagRuleNode{Tag: influxdb.Tag{Key: "t3", Value: "v3"}},
LogicalNode{Operator: LogicalAnd, Children: []Node{
TagRuleNode{Tag: influxdb.Tag{Key: "t4", Value: "v4"}},
TagRuleNode{Tag: influxdb.Tag{Key: "t5", Value: "v5"}},
LogicalNode{Operator: LogicalAnd, Children: [2]Node{
LogicalNode{Operator: LogicalAnd, Children: [2]Node{
TagRuleNode{Tag: influxdb.Tag{Key: "t4", Value: "v4"}},
TagRuleNode{Tag: influxdb.Tag{Key: "t5", Value: "v5"}},
}},
TagRuleNode{Tag: influxdb.Tag{Key: "t6", Value: "v6"}},
}},
}},

View File

@ -5,6 +5,7 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/influxdata/influxdb"
"github.com/influxdata/influxdb/models"
"github.com/influxdata/influxdb/storage/reads/datatypes"
influxtesting "github.com/influxdata/influxdb/testing"
)
@ -45,11 +46,63 @@ func TestDataTypeConversion(t *testing.T) {
},
},
},
{
name: "measurement tag rule",
node: &TagRuleNode{
Operator: influxdb.Equal,
Tag: influxdb.Tag{
Key: "_measurement",
Value: "cpu",
},
},
dataType: &datatypes.Node{
NodeType: datatypes.NodeTypeComparisonExpression,
Value: &datatypes.Node_Comparison_{Comparison: datatypes.ComparisonEqual},
Children: []*datatypes.Node{
{
NodeType: datatypes.NodeTypeTagRef,
Value: &datatypes.Node_TagRefValue{TagRefValue: models.MeasurementTagKey},
},
{
NodeType: datatypes.NodeTypeLiteral,
Value: &datatypes.Node_StringValue{
StringValue: "cpu",
},
},
},
},
},
{
name: "field tag rule",
node: &TagRuleNode{
Operator: influxdb.Equal,
Tag: influxdb.Tag{
Key: "_field",
Value: "cpu",
},
},
dataType: &datatypes.Node{
NodeType: datatypes.NodeTypeComparisonExpression,
Value: &datatypes.Node_Comparison_{Comparison: datatypes.ComparisonEqual},
Children: []*datatypes.Node{
{
NodeType: datatypes.NodeTypeTagRef,
Value: &datatypes.Node_TagRefValue{TagRefValue: models.FieldKeyTagKey},
},
{
NodeType: datatypes.NodeTypeLiteral,
Value: &datatypes.Node_StringValue{
StringValue: "cpu",
},
},
},
},
},
{
name: "logical",
node: &LogicalNode{
Operator: LogicalAnd,
Children: []Node{
Children: [2]Node{
&TagRuleNode{
Operator: influxdb.Equal,
Tag: influxdb.Tag{
@ -111,10 +164,10 @@ func TestDataTypeConversion(t *testing.T) {
name: "conplex logical",
node: &LogicalNode{
Operator: LogicalAnd,
Children: []Node{
Children: [2]Node{
&LogicalNode{
Operator: LogicalAnd,
Children: []Node{
Children: [2]Node{
&TagRuleNode{
Operator: influxdb.Equal,
Tag: influxdb.Tag{

View File

@ -4,12 +4,18 @@ import (
"fmt"
"github.com/influxdata/influxdb"
"github.com/influxdata/influxdb/models"
"github.com/influxdata/influxdb/storage/reads/datatypes"
)
// TagRuleNode is a node type of a single tag rule.
type TagRuleNode influxdb.TagRule
var specialKey = map[string]string{
"_measurement": models.MeasurementTagKey,
"_field": models.FieldKeyTagKey,
}
// NodeTypeLiteral convert a TagRuleNode to a nodeTypeLiteral.
func NodeTypeLiteral(tr TagRuleNode) *datatypes.Node {
switch tr.Operator {
@ -61,6 +67,9 @@ func (n TagRuleNode) ToDataType() (*datatypes.Node, error) {
if err != nil {
return nil, err
}
if special, ok := specialKey[n.Key]; ok {
n.Key = special
}
return &datatypes.Node{
NodeType: datatypes.NodeTypeComparisonExpression,
Value: &datatypes.Node_Comparison_{Comparison: compare},