178 lines
5.2 KiB
Go
178 lines
5.2 KiB
Go
package storageflux
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/influxdata/flux/ast"
|
|
"github.com/influxdata/flux/semantic"
|
|
"github.com/influxdata/influxdb/models"
|
|
"github.com/influxdata/influxdb/storage/reads/datatypes"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
func toStoragePredicate(f *semantic.FunctionExpression) (*datatypes.Predicate, error) {
|
|
if f.Block.Parameters == nil || len(f.Block.Parameters.List) != 1 {
|
|
return nil, errors.New("storage predicate functions must have exactly one parameter")
|
|
}
|
|
|
|
root, err := toStoragePredicateHelper(f.Block.Body.(semantic.Expression), f.Block.Parameters.List[0].Key.Name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &datatypes.Predicate{
|
|
Root: root,
|
|
}, nil
|
|
}
|
|
|
|
func toStoragePredicateHelper(n semantic.Expression, objectName string) (*datatypes.Node, error) {
|
|
switch n := n.(type) {
|
|
case *semantic.LogicalExpression:
|
|
left, err := toStoragePredicateHelper(n.Left, objectName)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "left hand side")
|
|
}
|
|
right, err := toStoragePredicateHelper(n.Right, objectName)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "right hand side")
|
|
}
|
|
children := []*datatypes.Node{left, right}
|
|
switch n.Operator {
|
|
case ast.AndOperator:
|
|
return &datatypes.Node{
|
|
NodeType: datatypes.NodeTypeLogicalExpression,
|
|
Value: &datatypes.Node_Logical_{Logical: datatypes.LogicalAnd},
|
|
Children: children,
|
|
}, nil
|
|
case ast.OrOperator:
|
|
return &datatypes.Node{
|
|
NodeType: datatypes.NodeTypeLogicalExpression,
|
|
Value: &datatypes.Node_Logical_{Logical: datatypes.LogicalOr},
|
|
Children: children,
|
|
}, nil
|
|
default:
|
|
return nil, fmt.Errorf("unknown logical operator %v", n.Operator)
|
|
}
|
|
case *semantic.BinaryExpression:
|
|
left, err := toStoragePredicateHelper(n.Left, objectName)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "left hand side")
|
|
}
|
|
right, err := toStoragePredicateHelper(n.Right, objectName)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "right hand side")
|
|
}
|
|
children := []*datatypes.Node{left, right}
|
|
op, err := toComparisonOperator(n.Operator)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &datatypes.Node{
|
|
NodeType: datatypes.NodeTypeComparisonExpression,
|
|
Value: &datatypes.Node_Comparison_{Comparison: op},
|
|
Children: children,
|
|
}, nil
|
|
case *semantic.StringLiteral:
|
|
return &datatypes.Node{
|
|
NodeType: datatypes.NodeTypeLiteral,
|
|
Value: &datatypes.Node_StringValue{
|
|
StringValue: n.Value,
|
|
},
|
|
}, nil
|
|
case *semantic.IntegerLiteral:
|
|
return &datatypes.Node{
|
|
NodeType: datatypes.NodeTypeLiteral,
|
|
Value: &datatypes.Node_IntegerValue{
|
|
IntegerValue: n.Value,
|
|
},
|
|
}, nil
|
|
case *semantic.BooleanLiteral:
|
|
return &datatypes.Node{
|
|
NodeType: datatypes.NodeTypeLiteral,
|
|
Value: &datatypes.Node_BooleanValue{
|
|
BooleanValue: n.Value,
|
|
},
|
|
}, nil
|
|
case *semantic.FloatLiteral:
|
|
return &datatypes.Node{
|
|
NodeType: datatypes.NodeTypeLiteral,
|
|
Value: &datatypes.Node_FloatValue{
|
|
FloatValue: n.Value,
|
|
},
|
|
}, nil
|
|
case *semantic.RegexpLiteral:
|
|
return &datatypes.Node{
|
|
NodeType: datatypes.NodeTypeLiteral,
|
|
Value: &datatypes.Node_RegexValue{
|
|
RegexValue: n.Value.String(),
|
|
},
|
|
}, nil
|
|
case *semantic.MemberExpression:
|
|
// Sanity check that the object is the objectName identifier
|
|
if ident, ok := n.Object.(*semantic.IdentifierExpression); !ok || ident.Name != objectName {
|
|
return nil, fmt.Errorf("unknown object %q", n.Object)
|
|
}
|
|
switch n.Property {
|
|
case datatypes.FieldKey:
|
|
return &datatypes.Node{
|
|
NodeType: datatypes.NodeTypeTagRef,
|
|
Value: &datatypes.Node_TagRefValue{
|
|
TagRefValue: models.FieldKeyTagKey,
|
|
},
|
|
}, nil
|
|
case datatypes.MeasurementKey:
|
|
return &datatypes.Node{
|
|
NodeType: datatypes.NodeTypeTagRef,
|
|
Value: &datatypes.Node_TagRefValue{
|
|
TagRefValue: models.MeasurementTagKey,
|
|
},
|
|
}, nil
|
|
case datatypes.ValueKey:
|
|
return &datatypes.Node{
|
|
NodeType: datatypes.NodeTypeFieldRef,
|
|
Value: &datatypes.Node_FieldRefValue{
|
|
FieldRefValue: datatypes.ValueKey,
|
|
},
|
|
}, nil
|
|
|
|
}
|
|
return &datatypes.Node{
|
|
NodeType: datatypes.NodeTypeTagRef,
|
|
Value: &datatypes.Node_TagRefValue{
|
|
TagRefValue: n.Property,
|
|
},
|
|
}, nil
|
|
case *semantic.DurationLiteral:
|
|
return nil, errors.New("duration literals not supported in storage predicates")
|
|
case *semantic.DateTimeLiteral:
|
|
return nil, errors.New("time literals not supported in storage predicates")
|
|
default:
|
|
return nil, fmt.Errorf("unsupported semantic expression type %T", n)
|
|
}
|
|
}
|
|
|
|
func toComparisonOperator(o ast.OperatorKind) (datatypes.Node_Comparison, error) {
|
|
switch o {
|
|
case ast.EqualOperator:
|
|
return datatypes.ComparisonEqual, nil
|
|
case ast.NotEqualOperator:
|
|
return datatypes.ComparisonNotEqual, nil
|
|
case ast.RegexpMatchOperator:
|
|
return datatypes.ComparisonRegex, nil
|
|
case ast.NotRegexpMatchOperator:
|
|
return datatypes.ComparisonNotRegex, nil
|
|
case ast.StartsWithOperator:
|
|
return datatypes.ComparisonStartsWith, nil
|
|
case ast.LessThanOperator:
|
|
return datatypes.ComparisonLess, nil
|
|
case ast.LessThanEqualOperator:
|
|
return datatypes.ComparisonLessEqual, nil
|
|
case ast.GreaterThanOperator:
|
|
return datatypes.ComparisonGreater, nil
|
|
case ast.GreaterThanEqualOperator:
|
|
return datatypes.ComparisonGreaterEqual, nil
|
|
default:
|
|
return 0, fmt.Errorf("unknown operator %v", o)
|
|
}
|
|
}
|