VOL-3190 throw error message when filter or order on struct

Change-Id: If15983350d3f1a6fd21e5bfcec33ae57808cc31f
diff --git a/VERSION b/VERSION
index 2bf1ca5..0659a5b 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.1.7
+1.1.8-dev
diff --git a/pkg/filter/filter.go b/pkg/filter/filter.go
index 2498fa2..ffab11e 100644
--- a/pkg/filter/filter.go
+++ b/pkg/filter/filter.go
@@ -166,7 +166,7 @@
 	}
 
 	if val.Kind() != reflect.Struct {
-		return false, fmt.Errorf("Dotted field name specified in filter did not resolve to a valid field")
+		return false, fmt.Errorf("Field name specified in filter did not resolve to a valid field")
 	}
 
 	field := val.FieldByName(k)
@@ -174,6 +174,15 @@
 		return false, fmt.Errorf("Failed to find field %s while filtering", k)
 	}
 
+	// we might have a pointer to a struct at this time, so dereference it
+	if field.Kind() == reflect.Ptr {
+		field = reflect.Indirect(field)
+	}
+
+	if field.Kind() == reflect.Struct {
+		return false, fmt.Errorf("Cannot filter on a field that is a struct")
+	}
+
 	if (field.Kind() == reflect.Slice) || (field.Kind() == reflect.Array) {
 		// For an array, check to see if any item matches
 		someMatch := false
diff --git a/pkg/filter/filter_test.go b/pkg/filter/filter_test.go
index 874bda3..d08811d 100644
--- a/pkg/filter/filter_test.go
+++ b/pkg/filter/filter_test.go
@@ -30,10 +30,11 @@
 	Two   string
 	Three string
 	Five  TestFilterIncludedStruct
+	Seven *TestFilterIncludedStruct
 }
 
 func TestFilterList(t *testing.T) {
-	f, err := Parse("One=a,Two=b,Five.Six=d")
+	f, err := Parse("One=a,Two=b,Five.Six=d,Seven.Six=e")
 	if err != nil {
 		t.Errorf("Unable to parse filter: %s", err.Error())
 	}
@@ -44,18 +45,21 @@
 			Two:   "b",
 			Three: "c",
 			Five:  TestFilterIncludedStruct{Six: "d"},
+			Seven: &TestFilterIncludedStruct{Six: "e"},
 		},
 		TestFilterStruct{
 			One:   "1",
 			Two:   "2",
 			Three: "3",
 			Five:  TestFilterIncludedStruct{Six: "4"},
+			Seven: &TestFilterIncludedStruct{Six: "5"},
 		},
 		TestFilterStruct{
 			One:   "a",
 			Two:   "b",
 			Three: "z",
 			Five:  TestFilterIncludedStruct{Six: "d"},
+			Seven: &TestFilterIncludedStruct{Six: "e"},
 		},
 	}
 
@@ -231,7 +235,7 @@
 	}
 
 	r, err := f.Process(data)
-	assert.EqualError(t, err, "Dotted field name specified in filter did not resolve to a valid field")
+	assert.EqualError(t, err, "Field name specified in filter did not resolve to a valid field")
 
 	if r != nil {
 		t.Errorf("expected no results, got some")
@@ -252,7 +256,49 @@
 	}
 
 	r, err := f.Process(data)
-	assert.EqualError(t, err, "Dotted field name specified in filter did not resolve to a valid field")
+	assert.EqualError(t, err, "Field name specified in filter did not resolve to a valid field")
+
+	if r != nil {
+		t.Errorf("expected no results, got some")
+	}
+}
+
+func TestFilterOnStruct(t *testing.T) {
+	f, err := Parse("Five=a")
+	if err != nil {
+		t.Errorf("Unable to parse filter: %s", err.Error())
+	}
+
+	data := TestFilterStruct{
+		One:   "a",
+		Two:   "b",
+		Three: "c",
+		Five:  TestFilterIncludedStruct{Six: "w"},
+	}
+
+	r, err := f.Process(data)
+	assert.EqualError(t, err, "Cannot filter on a field that is a struct")
+
+	if r != nil {
+		t.Errorf("expected no results, got some")
+	}
+}
+
+func TestFilterOnPointerStruct(t *testing.T) {
+	f, err := Parse("Seven=a")
+	if err != nil {
+		t.Errorf("Unable to parse filter: %s", err.Error())
+	}
+
+	data := TestFilterStruct{
+		One:   "a",
+		Two:   "b",
+		Three: "c",
+		Seven: &TestFilterIncludedStruct{Six: "w"},
+	}
+
+	r, err := f.Process(data)
+	assert.EqualError(t, err, "Cannot filter on a field that is a struct")
 
 	if r != nil {
 		t.Errorf("expected no results, got some")
diff --git a/pkg/order/order.go b/pkg/order/order.go
index bcf097b..09ef1fc 100644
--- a/pkg/order/order.go
+++ b/pkg/order/order.go
@@ -110,6 +110,16 @@
 	if !field.IsValid() {
 		return field, fmt.Errorf("Failed to find field %s while sorting", name)
 	}
+
+	// we might have a pointer to a struct at this time, so dereference it
+	if field.Kind() == reflect.Ptr {
+		field = reflect.Indirect(field)
+	}
+
+	if field.Kind() == reflect.Struct {
+		return val, fmt.Errorf("Cannot sort on a field that is a struct")
+	}
+
 	return field, nil
 }
 
diff --git a/pkg/order/order_test.go b/pkg/order/order_test.go
index 28132d9..f2d28b4 100644
--- a/pkg/order/order_test.go
+++ b/pkg/order/order_test.go
@@ -32,6 +32,7 @@
 	Three uint
 	Four  int
 	Six   SortIncludedStruct
+	Eight *SortIncludedStruct
 }
 
 var testSetOne = []SortTestStruct{
@@ -42,6 +43,7 @@
 		Three: 10,
 		Four:  1,
 		Six:   SortIncludedStruct{Seven: "o"},
+		Eight: &SortIncludedStruct{Seven: "o"},
 	},
 	{
 		Id:    1,
@@ -50,6 +52,7 @@
 		Three: 1,
 		Four:  10,
 		Six:   SortIncludedStruct{Seven: "p"},
+		Eight: &SortIncludedStruct{Seven: "p"},
 	},
 	{
 		Id:    2,
@@ -58,6 +61,7 @@
 		Three: 2,
 		Four:  1000,
 		Six:   SortIncludedStruct{Seven: "q"},
+		Eight: &SortIncludedStruct{Seven: "q"},
 	},
 	{
 		Id:    3,
@@ -66,6 +70,7 @@
 		Three: 3,
 		Four:  100,
 		Six:   SortIncludedStruct{Seven: "r"},
+		Eight: &SortIncludedStruct{Seven: "r"},
 	},
 	{
 		Id:    4,
@@ -74,6 +79,7 @@
 		Three: 3,
 		Four:  0,
 		Six:   SortIncludedStruct{Seven: "s"},
+		Eight: &SortIncludedStruct{Seven: "s"},
 	},
 }
 
@@ -272,7 +278,22 @@
 	}
 }
 
-func TestInvaliodDotted(t *testing.T) {
+func TestSortDottedPointer(t *testing.T) {
+	s, err := Parse("+Eight.Seven")
+	if err != nil {
+		t.Errorf("Unable to parse sort specification")
+	}
+	o, err := s.Process(testSetOne)
+	if err != nil {
+		t.Errorf("Sort failed: %s", err.Error())
+	}
+
+	if !Verify(o.([]SortTestStruct), []int{0, 1, 2, 3, 4}) {
+		t.Errorf("incorrect sort")
+	}
+}
+
+func TestInvalidDotted(t *testing.T) {
 	s, err := Parse("+Six.Nonexistent")
 	if err != nil {
 		t.Errorf("Unable to parse sort specification")
@@ -296,6 +317,30 @@
 	}
 }
 
+func TestSortOnStuct(t *testing.T) {
+	s, err := Parse("+Six")
+	if err != nil {
+		t.Errorf("Unable to parse sort specification")
+	}
+	o, err := s.Process(testSetOne)
+	assert.EqualError(t, err, "Cannot sort on a field that is a struct")
+	if o != nil {
+		t.Errorf("expected no results, got some")
+	}
+}
+
+func TestSortOnPointerStuct(t *testing.T) {
+	s, err := Parse("+Eight")
+	if err != nil {
+		t.Errorf("Unable to parse sort specification")
+	}
+	o, err := s.Process(testSetOne)
+	assert.EqualError(t, err, "Cannot sort on a field that is a struct")
+	if o != nil {
+		t.Errorf("expected no results, got some")
+	}
+}
+
 func TestTrailingDot(t *testing.T) {
 	s, err := Parse("+Six.Seven.")
 	if err != nil {