VOL-3190 support nested ordering;
throw errors when fields don't exist

Change-Id: Ia607db45aec03413ffaf0696ee4043e42679803a
diff --git a/pkg/filter/filter.go b/pkg/filter/filter.go
index e704790..2498fa2 100644
--- a/pkg/filter/filter.go
+++ b/pkg/filter/filter.go
@@ -17,7 +17,6 @@
 
 import (
 	"fmt"
-	"log"
 	"reflect"
 	"regexp"
 	"strings"
@@ -97,7 +96,11 @@
 func (f Filter) Process(data interface{}) (interface{}, error) {
 	slice := reflect.ValueOf(data)
 	if slice.Kind() != reflect.Slice {
-		if f.Evaluate(data) {
+		match, err := f.Evaluate(data)
+		if err != nil {
+			return nil, err
+		}
+		if match {
 			return data, nil
 		}
 		return nil, nil
@@ -106,7 +109,11 @@
 	var result []interface{}
 
 	for i := 0; i < slice.Len(); i++ {
-		if f.Evaluate(slice.Index(i).Interface()) {
+		match, err := f.Evaluate(slice.Index(i).Interface())
+		if err != nil {
+			return nil, err
+		}
+		if match {
 			result = append(result, slice.Index(i).Interface())
 		}
 	}
@@ -139,7 +146,7 @@
 	return true
 }
 
-func (f Filter) EvaluateTerm(k string, v FilterTerm, val reflect.Value, recurse bool) bool {
+func (f Filter) EvaluateTerm(k string, v FilterTerm, val reflect.Value, recurse bool) (bool, error) {
 	// If we have been given a pointer, then deference it
 	if val.Kind() == reflect.Ptr {
 		val = reflect.Indirect(val)
@@ -148,18 +155,23 @@
 	// If the user gave us an explicitly named dotted field, then split it
 	if strings.Contains(k, ".") {
 		parts := strings.SplitN(k, ".", 2)
+		if val.Kind() != reflect.Struct {
+			return false, fmt.Errorf("Dotted field name specified in filter did not resolve to a valid field")
+		}
 		field := val.FieldByName(parts[0])
 		if !field.IsValid() {
-			log.Printf("Failed to find dotted field %s while filtering\n", parts[0])
-			return false
+			return false, fmt.Errorf("Failed to find dotted field %s while filtering", parts[0])
 		}
 		return f.EvaluateTerm(parts[1], v, field, false)
 	}
 
+	if val.Kind() != reflect.Struct {
+		return false, fmt.Errorf("Dotted field name specified in filter did not resolve to a valid field")
+	}
+
 	field := val.FieldByName(k)
 	if !field.IsValid() {
-		log.Printf("Failed to find field %s while filtering\n", k)
-		return false
+		return false, fmt.Errorf("Failed to find field %s while filtering", k)
 	}
 
 	if (field.Kind() == reflect.Slice) || (field.Kind() == reflect.Array) {
@@ -177,27 +189,30 @@
 			//          use a dotted notation. Go through the list of fields
 			//          in the struct, recursively check each one.
 			//}
-			return false
+			return false, nil
 		}
 	} else {
 		if !testField(v, field) {
-			return false
+			return false, nil
 		}
 	}
 
-	return true
+	return true, nil
 }
 
-func (f Filter) Evaluate(item interface{}) bool {
+func (f Filter) Evaluate(item interface{}) (bool, error) {
 	val := reflect.ValueOf(item)
 
 	for k, v := range f {
-		matches := f.EvaluateTerm(k, v, val, true)
+		matches, err := f.EvaluateTerm(k, v, val, true)
+		if err != nil {
+			return false, err
+		}
 		if !matches {
 			// If any of the filter fail, the overall match fails
-			return false
+			return false, nil
 		}
 	}
 
-	return true
+	return true, nil
 }