Skip to content

Commit

Permalink
Add the matches/not matches operators to due regex matching on str… (#5)
Browse files Browse the repository at this point in the history
Add the matches/not matches operators to due regex matching on strings
  • Loading branch information
mkeeler authored Jul 19, 2019
2 parents fbf42d9 + aa2071a commit a06e276
Show file tree
Hide file tree
Showing 9 changed files with 405 additions and 248 deletions.
6 changes: 6 additions & 0 deletions ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ const (
MatchNotIn
MatchIsEmpty
MatchIsNotEmpty
MatchMatches
MatchNotMatches
)

func (op MatchOperator) String() string {
Expand All @@ -73,6 +75,10 @@ func (op MatchOperator) String() string {
return "Is Empty"
case MatchIsNotEmpty:
return "Is Not Empty"
case MatchMatches:
return "Matches"
case MatchNotMatches:
return "Not Matches"
default:
return "UNKNOWN"
}
Expand Down
21 changes: 21 additions & 0 deletions evaluate.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ package bexpr
import (
"fmt"
"reflect"
"regexp"
"strings"
)

var byteSliceTyp reflect.Type = reflect.TypeOf([]byte{})

var primitiveEqualityFns = map[reflect.Kind]func(first interface{}, second reflect.Value) bool{
reflect.Bool: doEqualBool,
reflect.Int: doEqualInt,
Expand Down Expand Up @@ -87,6 +90,16 @@ func derefType(rtype reflect.Type) reflect.Type {
return rtype
}

func doMatchMatches(expression *MatchExpression, value reflect.Value) (bool, error) {
if !value.Type().ConvertibleTo(byteSliceTyp) {
return false, fmt.Errorf("Value of type %s is not convertible to []byte", value.Type())
}

re := expression.Value.Converted.(*regexp.Regexp)

return re.Match(value.Convert(byteSliceTyp).Interface().([]byte)), nil
}

func doMatchEqual(expression *MatchExpression, value reflect.Value) (bool, error) {
// NOTE: see preconditions in evaluateMatchExpressionRecurse
eqFn := primitiveEqualityFns[value.Kind()]
Expand Down Expand Up @@ -186,6 +199,14 @@ func evaluateMatchExpressionRecurse(expression *MatchExpression, depth int, rval
return !result, nil
}
return false, err
case MatchMatches:
return doMatchMatches(expression, rvalue)
case MatchNotMatches:
result, err := doMatchMatches(expression, rvalue)
if err == nil {
return !result, nil
}
return false, err
default:
return false, fmt.Errorf("Invalid match operation: %d", expression.Operator)
}
Expand Down
4 changes: 4 additions & 0 deletions evaluate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ var evaluateTests map[string]expressionTest = map[string]expressionTest{
{expression: "part not in String", result: true},
{expression: "unexported == `unexported`", result: false, err: "Selector \"unexported\" is not valid"},
{expression: "Hidden == false", result: false, err: "Selector \"Hidden\" is not valid"},
{expression: "String matches `^ex.*`", result: true, benchQuick: true},
{expression: "String not matches `^anchored.*`", result: true, benchQuick: true},
{expression: "String matches `^anchored.*`", result: false},
{expression: "String not matches `^ex.*`", result: false},
},
},
"Flat Struct Alt Types": {
Expand Down
4 changes: 3 additions & 1 deletion field_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,11 @@ func generateFieldConfigurationInternal(rtype reflect.Type) (*FieldConfiguration
// Handle primitive types
if coerceFn, ok := primitiveCoercionFns[rtype.Kind()]; ok {
ops := []MatchOperator{MatchEqual, MatchNotEqual}

if rtype.Kind() == reflect.String {
ops = append(ops, MatchIn, MatchNotIn)
ops = append(ops, MatchIn, MatchNotIn, MatchMatches, MatchNotMatches)
}

return &FieldConfiguration{
CoerceFn: coerceFn,
SupportedOperations: ops,
Expand Down
19 changes: 9 additions & 10 deletions field_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ var fieldConfigTests map[string]fieldConfigTest = map[string]fieldConfigTest{
"Float32": &FieldConfiguration{StructFieldName: "Float32", CoerceFn: CoerceFloat32, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual}},
"Float64": &FieldConfiguration{StructFieldName: "Float64", CoerceFn: CoerceFloat64, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual}},
"Bool": &FieldConfiguration{StructFieldName: "Bool", CoerceFn: CoerceBool, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual}},
"String": &FieldConfiguration{StructFieldName: "String", CoerceFn: CoerceString, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual, MatchIn, MatchNotIn}},
"String": &FieldConfiguration{StructFieldName: "String", CoerceFn: CoerceString, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual, MatchIn, MatchNotIn, MatchMatches, MatchNotMatches}},
},
benchQuick: true,
},
Expand All @@ -57,12 +57,11 @@ var fieldConfigTests map[string]fieldConfigTest = map[string]fieldConfigTest{
expected: FieldConfigurations{
"Nested": &FieldConfiguration{StructFieldName: "Nested", SubFields: FieldConfigurations{
"Map": &FieldConfiguration{StructFieldName: "Map", SupportedOperations: []MatchOperator{MatchIn, MatchNotIn, MatchIsEmpty, MatchIsNotEmpty}, SubFields: FieldConfigurations{
FieldNameAny: &FieldConfiguration{StructFieldName: "", SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual, MatchIn, MatchNotIn}},
}},
FieldNameAny: &FieldConfiguration{StructFieldName: "", SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual, MatchIn, MatchNotIn, MatchMatches, MatchNotMatches}}}},
"MapOfStructs": &FieldConfiguration{StructFieldName: "MapOfStructs", SupportedOperations: []MatchOperator{MatchIsEmpty, MatchIsNotEmpty, MatchIn, MatchNotIn}, SubFields: FieldConfigurations{
FieldNameAny: &FieldConfiguration{StructFieldName: "", SubFields: FieldConfigurations{
"Foo": &FieldConfiguration{StructFieldName: "Foo", CoerceFn: CoerceInt, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual}},
"Baz": &FieldConfiguration{StructFieldName: "Baz", SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual, MatchIn, MatchNotIn}},
"Baz": &FieldConfiguration{StructFieldName: "Baz", SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual, MatchIn, MatchNotIn, MatchMatches, MatchNotMatches}},
}},
}},
"MapInfInf": &FieldConfiguration{StructFieldName: "MapInfInf", SupportedOperations: []MatchOperator{MatchIsEmpty, MatchIsNotEmpty}},
Expand Down Expand Up @@ -94,7 +93,7 @@ var fieldConfigTests map[string]fieldConfigTest = map[string]fieldConfigTest{
"Float32": &FieldConfiguration{StructFieldName: "Float32", CoerceFn: CoerceFloat32, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual}},
"Float64": &FieldConfiguration{StructFieldName: "Float64", CoerceFn: CoerceFloat64, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual}},
"Bool": &FieldConfiguration{StructFieldName: "Bool", CoerceFn: CoerceBool, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual}},
"String": &FieldConfiguration{StructFieldName: "String", CoerceFn: CoerceString, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual, MatchIn, MatchNotIn}},
"String": &FieldConfiguration{StructFieldName: "String", CoerceFn: CoerceString, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual, MatchIn, MatchNotIn, MatchMatches, MatchNotMatches}},
}},
"bar": &FieldConfiguration{SubFields: FieldConfigurations{
"Int": &FieldConfiguration{StructFieldName: "Int", CoerceFn: CoerceInt, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual}},
Expand All @@ -110,7 +109,7 @@ var fieldConfigTests map[string]fieldConfigTest = map[string]fieldConfigTest{
"Float32": &FieldConfiguration{StructFieldName: "Float32", CoerceFn: CoerceFloat32, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual}},
"Float64": &FieldConfiguration{StructFieldName: "Float64", CoerceFn: CoerceFloat64, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual}},
"Bool": &FieldConfiguration{StructFieldName: "Bool", CoerceFn: CoerceBool, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual}},
"String": &FieldConfiguration{StructFieldName: "String", CoerceFn: CoerceString, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual, MatchIn, MatchNotIn}},
"String": &FieldConfiguration{StructFieldName: "String", CoerceFn: CoerceString, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual, MatchIn, MatchNotIn, MatchMatches, MatchNotMatches}},
}},
"baz": &FieldConfiguration{SubFields: FieldConfigurations{
"Int": &FieldConfiguration{StructFieldName: "Int", CoerceFn: CoerceInt, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual}},
Expand All @@ -126,7 +125,7 @@ var fieldConfigTests map[string]fieldConfigTest = map[string]fieldConfigTest{
"Float32": &FieldConfiguration{StructFieldName: "Float32", CoerceFn: CoerceFloat32, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual}},
"Float64": &FieldConfiguration{StructFieldName: "Float64", CoerceFn: CoerceFloat64, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual}},
"Bool": &FieldConfiguration{StructFieldName: "Bool", CoerceFn: CoerceBool, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual}},
"String": &FieldConfiguration{StructFieldName: "String", CoerceFn: CoerceString, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual, MatchIn, MatchNotIn}},
"String": &FieldConfiguration{StructFieldName: "String", CoerceFn: CoerceString, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual, MatchIn, MatchNotIn, MatchMatches, MatchNotMatches}},
}},
},
benchQuick: true,
Expand All @@ -149,7 +148,7 @@ var fieldConfigTests map[string]fieldConfigTest = map[string]fieldConfigTest{
"Float32": &FieldConfiguration{StructFieldName: "Float32", CoerceFn: CoerceFloat32, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual}},
"Float64": &FieldConfiguration{StructFieldName: "Float64", CoerceFn: CoerceFloat64, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual}},
"Bool": &FieldConfiguration{StructFieldName: "Bool", CoerceFn: CoerceBool, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual}},
"String": &FieldConfiguration{StructFieldName: "String", CoerceFn: CoerceString, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual, MatchIn, MatchNotIn}},
"String": &FieldConfiguration{StructFieldName: "String", CoerceFn: CoerceString, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual, MatchIn, MatchNotIn, MatchMatches, MatchNotMatches}},
}},
"bar": &FieldConfiguration{SubFields: FieldConfigurations{
"Int": &FieldConfiguration{StructFieldName: "Int", CoerceFn: CoerceInt, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual}},
Expand All @@ -165,7 +164,7 @@ var fieldConfigTests map[string]fieldConfigTest = map[string]fieldConfigTest{
"Float32": &FieldConfiguration{StructFieldName: "Float32", CoerceFn: CoerceFloat32, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual}},
"Float64": &FieldConfiguration{StructFieldName: "Float64", CoerceFn: CoerceFloat64, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual}},
"Bool": &FieldConfiguration{StructFieldName: "Bool", CoerceFn: CoerceBool, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual}},
"String": &FieldConfiguration{StructFieldName: "String", CoerceFn: CoerceString, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual, MatchIn, MatchNotIn}},
"String": &FieldConfiguration{StructFieldName: "String", CoerceFn: CoerceString, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual, MatchIn, MatchNotIn, MatchMatches, MatchNotMatches}},
}},
"baz": &FieldConfiguration{SubFields: FieldConfigurations{
"Int": &FieldConfiguration{StructFieldName: "Int", CoerceFn: CoerceInt, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual}},
Expand All @@ -181,7 +180,7 @@ var fieldConfigTests map[string]fieldConfigTest = map[string]fieldConfigTest{
"Float32": &FieldConfiguration{StructFieldName: "Float32", CoerceFn: CoerceFloat32, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual}},
"Float64": &FieldConfiguration{StructFieldName: "Float64", CoerceFn: CoerceFloat64, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual}},
"Bool": &FieldConfiguration{StructFieldName: "Bool", CoerceFn: CoerceBool, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual}},
"String": &FieldConfiguration{StructFieldName: "String", CoerceFn: CoerceString, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual, MatchIn, MatchNotIn}},
"String": &FieldConfiguration{StructFieldName: "String", CoerceFn: CoerceString, SupportedOperations: []MatchOperator{MatchEqual, MatchNotEqual, MatchIn, MatchNotIn, MatchMatches, MatchNotMatches}},
}},
}},
},
Expand Down
Loading

0 comments on commit a06e276

Please sign in to comment.