internal/pkg/eql/compare.go (401 lines of code) (raw):
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
// or more contributor license agreements. Licensed under the Elastic License 2.0;
// you may not use this file except in compliance with the Elastic License 2.0.
package eql
import (
"fmt"
"sort"
)
type operand interface{}
func compareEQ(left, right operand) (bool, error) {
switch v := left.(type) {
case *null:
_, ok := right.(*null)
if ok {
return true, nil
}
return false, nil
case bool:
rV, ok := right.(bool)
if !ok {
return false, nil
}
if rV == v {
return true, nil
}
return false, nil
case int:
switch rv := right.(type) {
case *null:
return false, nil
case int:
return v == rv, nil
case float64:
// TODO: check overflow, weird things will happen with precision here.
// use modf
return float64(v) == rv, nil
default:
return false, fmt.Errorf(
"compare: ==, incompatible type to compare both operands must be numbers, left=%T, right=%T",
left,
right,
)
}
case float64:
switch rv := right.(type) {
case *null:
return false, nil
case int:
return v == float64(rv), nil
case float64:
return v == rv, nil
default:
return false, fmt.Errorf(
"compare: ==, incompatible type to compare both operand must be numbers, left=%T, right=%T",
left,
right,
)
}
case string:
rV, ok := right.(string)
if !ok {
return false, nil
}
if rV == v {
return true, nil
}
return false, nil
case []interface{}:
rV, ok := right.([]interface{})
if !ok {
return false, nil
}
if len(v) != len(rV) {
return false, nil
}
for i := range v {
b, err := compareEQ(v[i], rV[i])
if err != nil {
return false, err
}
if !b {
return false, nil
}
}
return true, nil
case map[string]interface{}:
rV, ok := right.(map[string]interface{})
if !ok {
return false, nil
}
if !keysEqual(v, rV) {
return false, nil
}
for i := range v {
b, err := compareEQ(v[i], rV[i])
if err != nil {
return false, err
}
if !b {
return false, nil
}
}
return true, nil
default:
return false, fmt.Errorf(
"compare: ==, incompatible type to compare, left=%T, right=%T",
left,
right,
)
}
}
func compareNEQ(left, right operand) (bool, error) {
switch v := left.(type) {
case *null:
_, ok := right.(*null)
if ok {
return false, nil
}
return true, nil
case bool:
rV, ok := right.(bool)
if !ok {
return true, nil
}
if rV == v {
return false, nil
}
return true, nil
case int:
switch rv := right.(type) {
case *null:
return true, nil
case int:
return v != rv, nil
case float64:
// TODO: check overflow, weird things will happen with precision here.
// use modf
return float64(v) != rv, nil
default:
return false, fmt.Errorf(
"compare: ==, incompatible type to compare both operands must be numbers, left=%T, right=%T",
left,
right,
)
}
case float64:
switch rv := right.(type) {
case *null:
return true, nil
case int:
return v != float64(rv), nil
case float64:
return v != rv, nil
default:
return false, fmt.Errorf(
"compare: ==, incompatible type to compare both operands must be numbers, left=%T, right=%T",
left,
right,
)
}
case string:
rV, ok := right.(string)
if !ok {
return true, nil
}
if rV == v {
return false, nil
}
return true, nil
case []interface{}:
rV, ok := right.([]interface{})
if !ok {
return true, nil
}
if len(v) != len(rV) {
return true, nil
}
for i := range v {
b, err := compareNEQ(v[i], rV[i])
if err != nil {
return false, err
}
if b {
return true, nil
}
}
return false, nil
case map[string]interface{}:
rV, ok := right.(map[string]interface{})
if !ok {
return true, nil
}
if !keysEqual(v, rV) {
return true, nil
}
for i := range v {
b, err := compareNEQ(v[i], rV[i])
if err != nil {
return false, err
}
if b {
return true, nil
}
}
return false, nil
default:
return false, fmt.Errorf(
"compare: !=, incompatible type to compare, left=%T, right=%T",
left,
right,
)
}
}
func compareLT(left, right operand) (bool, error) {
switch v := left.(type) {
case int:
switch rv := right.(type) {
case int:
return v < rv, nil
case float64:
return float64(v) < rv, nil
default:
return false, fmt.Errorf(
"compare: <, incompatible type to compare both operands must be numbers, left=%T, right=%T",
left,
right,
)
}
case float64:
switch rv := right.(type) {
case int:
return v < float64(rv), nil
case float64:
return v < rv, nil
default:
return false, fmt.Errorf(
"compare: <, incompatible type to compare both operands must be numbers, left=%T, right=%T",
left,
right,
)
}
default:
return false, fmt.Errorf(
"compare: <, incompatible type to compare both operands must be numbers, left=%T, right=%T",
left,
right,
)
}
}
func compareLTE(left, right operand) (bool, error) {
switch v := left.(type) {
case int:
switch rv := right.(type) {
case int:
return v <= rv, nil
case float64:
return float64(v) <= rv, nil
default:
return false, fmt.Errorf(
"compare: <=, incompatible type to compare both operands must be numbers, left=%T, right=%T",
left,
right,
)
}
case float64:
switch rv := right.(type) {
case int:
return v <= float64(rv), nil
case float64:
return v <= rv, nil
default:
return false, fmt.Errorf(
"compare: <=, incompatible type to compare both operands must be numbers, left=%T, right=%T",
left,
right,
)
}
default:
return false, fmt.Errorf(
"compare: <=, incompatible type to compare both operands must be numbers, left=%T, right=%T",
left,
right,
)
}
}
func compareGT(left, right operand) (bool, error) {
switch v := left.(type) {
case int:
switch rv := right.(type) {
case int:
return v > rv, nil
case float64:
return float64(v) > rv, nil
default:
return false, fmt.Errorf(
"compare: >, incompatible type to compare both operands must be numbers, left=%T, right=%T",
left,
right,
)
}
case float64:
switch rv := right.(type) {
case int:
return v > float64(rv), nil
case float64:
return v > rv, nil
default:
return false, fmt.Errorf(
"compare: >, incompatible type to compare both operands must be numbers, left=%T, right=%T",
left,
right,
)
}
default:
return false, fmt.Errorf(
"compare: >, incompatible type to compare both operands must be numbers, left=%T, right=%T",
left,
right,
)
}
}
func compareGTE(left, right operand) (bool, error) {
switch v := left.(type) {
case int:
switch rv := right.(type) {
case int:
return v >= rv, nil
case float64:
return float64(v) >= rv, nil
default:
return false, fmt.Errorf(
"compare: >=, incompatible type to compare both operands must be numbers, left=%T, right=%T",
left,
right,
)
}
case float64:
switch rv := right.(type) {
case int:
return v >= float64(rv), nil
case float64:
return v >= rv, nil
default:
return false, fmt.Errorf(
"compare: >=, incompatible type to compare both operands must be numbers, left=%T, right=%T",
left,
right,
)
}
default:
return false, fmt.Errorf(
"compare: >=, incompatible type to compare both operands must be numbers, left=%T, right=%T",
left,
right,
)
}
}
func logicalAND(left, right operand) (bool, error) {
switch l := left.(type) {
case bool:
switch r := right.(type) {
case bool:
return l && r, nil
}
}
return false, fmt.Errorf(
"and: incompatible type to and both operands must be booleans, left=%T, right=%T",
left,
right,
)
}
func logicalOR(left, right operand) (bool, error) {
switch l := left.(type) {
case bool:
switch r := right.(type) {
case bool:
return l || r, nil
}
}
return false, fmt.Errorf(
"and: incompatible type to and both operands must be booleans, left=%T, right=%T",
left,
right,
)
}
func keys(v map[string]interface{}) []string {
ks := make([]string, len(v))
i := 0
for k := range v {
ks[i] = k
i++
}
sort.Strings(ks)
return ks
}
func keysEqual(v1, v2 map[string]interface{}) bool {
ks1 := keys(v1)
ks2 := keys(v2)
if len(ks1) != len(ks2) {
return false
}
for i, v := range ks1 {
if v != ks2[i] {
return false
}
}
return true
}