285 lines
5.4 KiB
Go
285 lines
5.4 KiB
Go
package reads
|
|
|
|
import (
|
|
"math"
|
|
"regexp"
|
|
|
|
"github.com/influxdata/influxql"
|
|
)
|
|
|
|
// evalExpr evaluates expr against a map.
|
|
func evalExpr(expr influxql.Expr, m Valuer) interface{} {
|
|
if expr == nil {
|
|
return nil
|
|
}
|
|
|
|
switch expr := expr.(type) {
|
|
case *influxql.BinaryExpr:
|
|
return evalBinaryExpr(expr, m)
|
|
case *influxql.BooleanLiteral:
|
|
return expr.Val
|
|
case *influxql.IntegerLiteral:
|
|
return expr.Val
|
|
case *influxql.UnsignedLiteral:
|
|
return expr.Val
|
|
case *influxql.NumberLiteral:
|
|
return expr.Val
|
|
case *influxql.ParenExpr:
|
|
return evalExpr(expr.Expr, m)
|
|
case *influxql.RegexLiteral:
|
|
return expr.Val
|
|
case *influxql.StringLiteral:
|
|
return expr.Val
|
|
case *influxql.VarRef:
|
|
v, _ := m.Value(expr.Val)
|
|
return v
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func evalBinaryExpr(expr *influxql.BinaryExpr, m Valuer) interface{} {
|
|
lhs := evalExpr(expr.LHS, m)
|
|
rhs := evalExpr(expr.RHS, m)
|
|
if lhs == nil && rhs != nil {
|
|
// When the LHS is nil and the RHS is a boolean, implicitly cast the
|
|
// nil to false.
|
|
if _, ok := rhs.(bool); ok {
|
|
lhs = false
|
|
}
|
|
} else if lhs != nil && rhs == nil {
|
|
// Implicit cast of the RHS nil to false when the LHS is a boolean.
|
|
if _, ok := lhs.(bool); ok {
|
|
rhs = false
|
|
}
|
|
}
|
|
|
|
// Evaluate if both sides are simple types.
|
|
switch lhs := lhs.(type) {
|
|
case bool:
|
|
rhs, ok := rhs.(bool)
|
|
switch expr.Op {
|
|
case influxql.AND:
|
|
return ok && (lhs && rhs)
|
|
case influxql.OR:
|
|
return ok && (lhs || rhs)
|
|
case influxql.BITWISE_AND:
|
|
return ok && (lhs && rhs)
|
|
case influxql.BITWISE_OR:
|
|
return ok && (lhs || rhs)
|
|
case influxql.BITWISE_XOR:
|
|
return ok && (lhs != rhs)
|
|
case influxql.EQ:
|
|
return ok && (lhs == rhs)
|
|
case influxql.NEQ:
|
|
return ok && (lhs != rhs)
|
|
}
|
|
case float64:
|
|
// Try the rhs as a float64 or int64
|
|
rhsf, ok := rhs.(float64)
|
|
if !ok {
|
|
var rhsi int64
|
|
if rhsi, ok = rhs.(int64); ok {
|
|
rhsf = float64(rhsi)
|
|
}
|
|
}
|
|
|
|
rhs := rhsf
|
|
switch expr.Op {
|
|
case influxql.EQ:
|
|
return ok && (lhs == rhs)
|
|
case influxql.NEQ:
|
|
return ok && (lhs != rhs)
|
|
case influxql.LT:
|
|
return ok && (lhs < rhs)
|
|
case influxql.LTE:
|
|
return ok && (lhs <= rhs)
|
|
case influxql.GT:
|
|
return ok && (lhs > rhs)
|
|
case influxql.GTE:
|
|
return ok && (lhs >= rhs)
|
|
case influxql.ADD:
|
|
if !ok {
|
|
return nil
|
|
}
|
|
return lhs + rhs
|
|
case influxql.SUB:
|
|
if !ok {
|
|
return nil
|
|
}
|
|
return lhs - rhs
|
|
case influxql.MUL:
|
|
if !ok {
|
|
return nil
|
|
}
|
|
return lhs * rhs
|
|
case influxql.DIV:
|
|
if !ok {
|
|
return nil
|
|
} else if rhs == 0 {
|
|
return float64(0)
|
|
}
|
|
return lhs / rhs
|
|
case influxql.MOD:
|
|
if !ok {
|
|
return nil
|
|
}
|
|
return math.Mod(lhs, rhs)
|
|
}
|
|
case int64:
|
|
// Try as a float64 to see if a float cast is required.
|
|
rhsf, ok := rhs.(float64)
|
|
if ok {
|
|
lhs := float64(lhs)
|
|
rhs := rhsf
|
|
switch expr.Op {
|
|
case influxql.EQ:
|
|
return lhs == rhs
|
|
case influxql.NEQ:
|
|
return lhs != rhs
|
|
case influxql.LT:
|
|
return lhs < rhs
|
|
case influxql.LTE:
|
|
return lhs <= rhs
|
|
case influxql.GT:
|
|
return lhs > rhs
|
|
case influxql.GTE:
|
|
return lhs >= rhs
|
|
case influxql.ADD:
|
|
return lhs + rhs
|
|
case influxql.SUB:
|
|
return lhs - rhs
|
|
case influxql.MUL:
|
|
return lhs * rhs
|
|
case influxql.DIV:
|
|
if rhs == 0 {
|
|
return float64(0)
|
|
}
|
|
return lhs / rhs
|
|
case influxql.MOD:
|
|
return math.Mod(lhs, rhs)
|
|
}
|
|
} else {
|
|
rhs, ok := rhs.(int64)
|
|
switch expr.Op {
|
|
case influxql.EQ:
|
|
return ok && (lhs == rhs)
|
|
case influxql.NEQ:
|
|
return ok && (lhs != rhs)
|
|
case influxql.LT:
|
|
return ok && (lhs < rhs)
|
|
case influxql.LTE:
|
|
return ok && (lhs <= rhs)
|
|
case influxql.GT:
|
|
return ok && (lhs > rhs)
|
|
case influxql.GTE:
|
|
return ok && (lhs >= rhs)
|
|
case influxql.ADD:
|
|
if !ok {
|
|
return nil
|
|
}
|
|
return lhs + rhs
|
|
case influxql.SUB:
|
|
if !ok {
|
|
return nil
|
|
}
|
|
return lhs - rhs
|
|
case influxql.MUL:
|
|
if !ok {
|
|
return nil
|
|
}
|
|
return lhs * rhs
|
|
case influxql.DIV:
|
|
if !ok {
|
|
return nil
|
|
} else if rhs == 0 {
|
|
return float64(0)
|
|
}
|
|
return lhs / rhs
|
|
case influxql.MOD:
|
|
if !ok {
|
|
return nil
|
|
} else if rhs == 0 {
|
|
return int64(0)
|
|
}
|
|
return lhs % rhs
|
|
case influxql.BITWISE_AND:
|
|
if !ok {
|
|
return nil
|
|
}
|
|
return lhs & rhs
|
|
case influxql.BITWISE_OR:
|
|
if !ok {
|
|
return nil
|
|
}
|
|
return lhs | rhs
|
|
case influxql.BITWISE_XOR:
|
|
if !ok {
|
|
return nil
|
|
}
|
|
return lhs ^ rhs
|
|
}
|
|
}
|
|
case string:
|
|
switch expr.Op {
|
|
case influxql.EQ:
|
|
rhs, ok := rhs.(string)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
return lhs == rhs
|
|
case influxql.NEQ:
|
|
rhs, ok := rhs.(string)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
return lhs != rhs
|
|
case influxql.EQREGEX:
|
|
rhs, ok := rhs.(*regexp.Regexp)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
return rhs.MatchString(lhs)
|
|
case influxql.NEQREGEX:
|
|
rhs, ok := rhs.(*regexp.Regexp)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
return !rhs.MatchString(lhs)
|
|
}
|
|
case []byte:
|
|
switch expr.Op {
|
|
case influxql.EQ:
|
|
rhs, ok := rhs.(string)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
return string(lhs) == rhs
|
|
case influxql.NEQ:
|
|
rhs, ok := rhs.(string)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
return string(lhs) != rhs
|
|
case influxql.EQREGEX:
|
|
rhs, ok := rhs.(*regexp.Regexp)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
return rhs.Match(lhs)
|
|
case influxql.NEQREGEX:
|
|
rhs, ok := rhs.(*regexp.Regexp)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
return !rhs.Match(lhs)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func EvalExprBool(expr influxql.Expr, m Valuer) bool {
|
|
v, _ := evalExpr(expr, m).(bool)
|
|
return v
|
|
}
|