VOL-3182 Support dotted syntax for nested filter
Change-Id: Ib4a244c85dd36300bc6f7f7507867a4f1f0d0f38
diff --git a/VERSION b/VERSION
index b08cf5b..e25d8d9 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.1.5-dev
+1.1.5
diff --git a/pkg/filter/filter.go b/pkg/filter/filter.go
index f566d94..e704790 100644
--- a/pkg/filter/filter.go
+++ b/pkg/filter/filter.go
@@ -17,6 +17,7 @@
import (
"fmt"
+ "log"
"reflect"
"regexp"
"strings"
@@ -138,37 +139,65 @@
return true
}
-func (f Filter) Evaluate(item interface{}) bool {
- val := reflect.ValueOf(item)
-
+func (f Filter) EvaluateTerm(k string, v FilterTerm, val reflect.Value, recurse bool) bool {
// If we have been given a pointer, then deference it
if val.Kind() == reflect.Ptr {
val = reflect.Indirect(val)
}
- for k, v := range f {
- field := val.FieldByName(k)
+ // If the user gave us an explicitly named dotted field, then split it
+ if strings.Contains(k, ".") {
+ parts := strings.SplitN(k, ".", 2)
+ field := val.FieldByName(parts[0])
if !field.IsValid() {
+ log.Printf("Failed to find dotted field %s while filtering\n", parts[0])
return false
}
+ return f.EvaluateTerm(parts[1], v, field, false)
+ }
- if (field.Kind() == reflect.Slice) || (field.Kind() == reflect.Array) {
- // For an array, check to see if any item matches
- someMatch := false
- for i := 0; i < field.Len(); i++ {
- arrayElem := field.Index(i)
- if testField(v, arrayElem) {
- someMatch = true
- }
- }
- if !someMatch {
- return false
- }
- } else {
- if !testField(v, field) {
- return false
+ field := val.FieldByName(k)
+ if !field.IsValid() {
+ log.Printf("Failed to find field %s while filtering\n", k)
+ return false
+ }
+
+ if (field.Kind() == reflect.Slice) || (field.Kind() == reflect.Array) {
+ // For an array, check to see if any item matches
+ someMatch := false
+ for i := 0; i < field.Len(); i++ {
+ arrayElem := field.Index(i)
+ if testField(v, arrayElem) {
+ someMatch = true
}
}
+ if !someMatch {
+ //if recurse && val.Kind() == reflect.Struct {
+ // TODO: implement automatic recursion when the user did not
+ // use a dotted notation. Go through the list of fields
+ // in the struct, recursively check each one.
+ //}
+ return false
+ }
+ } else {
+ if !testField(v, field) {
+ return false
+ }
}
+
+ return true
+}
+
+func (f Filter) Evaluate(item interface{}) bool {
+ val := reflect.ValueOf(item)
+
+ for k, v := range f {
+ matches := f.EvaluateTerm(k, v, val, true)
+ if !matches {
+ // If any of the filter fail, the overall match fails
+ return false
+ }
+ }
+
return true
}