From dd732e84f43570d87dba49a1e42061f8bd4f6afa Mon Sep 17 00:00:00 2001 From: Tatsushi Demachi Date: Sun, 28 Jun 2015 02:15:42 +0900 Subject: [PATCH] Add nil comparison to where tpl function `where` template function's internal condition check function always returns `false` when a target value doesn't exist or it's nil value but this behavior makes it difficult to filter values which doesn't have a particular parameter. To solve it, this adds nil value comparison to the function. `where Values ".Param.key" nil` like clause can be used for the case above. Only "=", "==", "eq", "!=", "<>", "ne" operators are allowed to be used with `nil`. If an other operator is passed with `nil`, the condition check function returns `false` like before. Fix #1232 --- tpl/template_funcs.go | 22 +++++++++++++--------- tpl/template_funcs_test.go | 27 +++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/tpl/template_funcs.go b/tpl/template_funcs.go index 7849aaae1..258591314 100644 --- a/tpl/template_funcs.go +++ b/tpl/template_funcs.go @@ -536,17 +536,21 @@ func evaluateSubElem(obj reflect.Value, elemName string) (reflect.Value, error) } func checkCondition(v, mv reflect.Value, op string) (bool, error) { - if !v.IsValid() || !mv.IsValid() { - return false, nil + v, vIsNil := indirect(v) + if !v.IsValid() { + vIsNil = true } - - var isNil bool - v, isNil = indirect(v) - if isNil { - return false, nil + mv, mvIsNil := indirect(mv) + if !mv.IsValid() { + mvIsNil = true } - mv, isNil = indirect(mv) - if isNil { + if vIsNil || mvIsNil { + switch op { + case "", "=", "==", "eq": + return vIsNil == mvIsNil, nil + case "!=", "<>", "ne": + return vIsNil != mvIsNil, nil + } return false, nil } diff --git a/tpl/template_funcs_test.go b/tpl/template_funcs_test.go index 573b0fe23..81018626a 100644 --- a/tpl/template_funcs_test.go +++ b/tpl/template_funcs_test.go @@ -673,6 +673,7 @@ func TestCheckCondition(t *testing.T) { "", expect{true, false}, }, + {reflect.ValueOf(nil), reflect.ValueOf(nil), "", expect{true, false}}, {reflect.ValueOf(123), reflect.ValueOf(456), "!=", expect{true, false}}, {reflect.ValueOf("foo"), reflect.ValueOf("bar"), "!=", expect{true, false}}, { @@ -681,6 +682,7 @@ func TestCheckCondition(t *testing.T) { "!=", expect{true, false}, }, + {reflect.ValueOf(123), reflect.ValueOf(nil), "!=", expect{true, false}}, {reflect.ValueOf(456), reflect.ValueOf(123), ">=", expect{true, false}}, {reflect.ValueOf("foo"), reflect.ValueOf("bar"), ">=", expect{true, false}}, { @@ -943,6 +945,31 @@ func TestWhere(t *testing.T) { {A: "a", B: "b"}, {A: "e", B: "f"}, }, }, + { + sequence: []map[string]int{ + {"a": 1, "b": 2}, {"a": 3}, {"a": 5, "b": 6}, + }, + key: "b", op: "", match: nil, + expect: []map[string]int{ + {"a": 3}, + }, + }, + { + sequence: []map[string]int{ + {"a": 1, "b": 2}, {"a": 3}, {"a": 5, "b": 6}, + }, + key: "b", op: "!=", match: nil, + expect: []map[string]int{ + {"a": 1, "b": 2}, {"a": 5, "b": 6}, + }, + }, + { + sequence: []map[string]int{ + {"a": 1, "b": 2}, {"a": 3}, {"a": 5, "b": 6}, + }, + key: "b", op: ">", match: nil, + expect: []map[string]int{}, + }, {sequence: (*[]TstX)(nil), key: "A", match: "a", expect: false}, {sequence: TstX{A: "a", B: "b"}, key: "A", match: "a", expect: false}, {sequence: []map[string]*TstX{{"foo": nil}}, key: "foo.B", match: "d", expect: false},