mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-21 20:46:30 -05:00
Add operator argument to where
template function
It allows to use `where` template function like SQL `where` clause. For example, {{ range where .Data.Pages "Type" "!=" "post" }} {{ .Content }} {{ end }} Now these operators are implemented: =, ==, eq, !=, <>, ne, >=, ge, >, gt, <=, le, <, lt, in, not in It also fixes `TestWhere` more readable
This commit is contained in:
parent
ae9c25afc0
commit
0d17ee7ed4
3 changed files with 409 additions and 32 deletions
|
@ -79,6 +79,25 @@ e.g.
|
||||||
{{ .Content}}
|
{{ .Content}}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
|
It can also be used with an operator like `!=`, `>=`, `in` etc. Without an operator (like above), `where` compares a given field with a matching value in a way like `=` is specified.
|
||||||
|
|
||||||
|
e.g.
|
||||||
|
|
||||||
|
{{ range where .Data.Pages "Section" "!=" "post" }}
|
||||||
|
{{ .Content}}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
Following operators are now available
|
||||||
|
|
||||||
|
- `=`, `==`, `eq`: True if a given field value equals a matching value
|
||||||
|
- `!=`, `<>`, `ne`: True if a given field value doesn't equal a matching value
|
||||||
|
- `>=`, `ge`: True if a given field value is greater than or equal to a matching value
|
||||||
|
- `>`, `gt`: True if a given field value is greater than a matching value
|
||||||
|
- `<=`, `le`: True if a given field value is lesser than or equal to a matching value
|
||||||
|
- `<`, `lt`: True if a given field value is lesser than a matching value
|
||||||
|
- `in`: True if a given field value is included in a matching value. A matching value must be an array or a slice
|
||||||
|
- `not in`: True if a given field value isn't included in a matching value. A matching value must be an array or a slice
|
||||||
|
|
||||||
*where and first can be stacked*
|
*where and first can be stacked*
|
||||||
|
|
||||||
e.g.
|
e.g.
|
||||||
|
|
148
tpl/template.go
148
tpl/template.go
|
@ -368,10 +368,141 @@ func evaluateSubElem(obj reflect.Value, elemName string) (reflect.Value, error)
|
||||||
return zero, fmt.Errorf("%s is neither a struct field, a method nor a map element of type %s", elemName, typ)
|
return zero, fmt.Errorf("%s is neither a struct field, a method nor a map element of type %s", elemName, typ)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Where(seq, key, match interface{}) (r interface{}, err error) {
|
func checkCondition(v, mv reflect.Value, op string) (bool, error) {
|
||||||
|
if !v.IsValid() || !mv.IsValid() {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var isNil bool
|
||||||
|
v, isNil = indirect(v)
|
||||||
|
if isNil {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
mv, isNil = indirect(mv)
|
||||||
|
if isNil {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var ivp, imvp *int64
|
||||||
|
var svp, smvp *string
|
||||||
|
var ima []int64
|
||||||
|
var sma []string
|
||||||
|
if mv.Type() == v.Type() {
|
||||||
|
switch v.Kind() {
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
iv := v.Int()
|
||||||
|
ivp = &iv
|
||||||
|
imv := mv.Int()
|
||||||
|
imvp = &imv
|
||||||
|
case reflect.String:
|
||||||
|
sv := v.String()
|
||||||
|
svp = &sv
|
||||||
|
smv := mv.String()
|
||||||
|
smvp = &smv
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if mv.Kind() != reflect.Array && mv.Kind() != reflect.Slice {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
if mv.Type().Elem() != v.Type() {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
switch v.Kind() {
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
iv := v.Int()
|
||||||
|
ivp = &iv
|
||||||
|
for i := 0; i < mv.Len(); i++ {
|
||||||
|
ima = append(ima, mv.Index(i).Int())
|
||||||
|
}
|
||||||
|
case reflect.String:
|
||||||
|
sv := v.String()
|
||||||
|
svp = &sv
|
||||||
|
for i := 0; i < mv.Len(); i++ {
|
||||||
|
sma = append(sma, mv.Index(i).String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch op {
|
||||||
|
case "", "=", "==", "eq":
|
||||||
|
if ivp != nil && imvp != nil {
|
||||||
|
return *ivp == *imvp, nil
|
||||||
|
} else if svp != nil && smvp != nil {
|
||||||
|
return *svp == *smvp, nil
|
||||||
|
}
|
||||||
|
case "!=", "<>", "ne":
|
||||||
|
if ivp != nil && imvp != nil {
|
||||||
|
return *ivp != *imvp, nil
|
||||||
|
} else if svp != nil && smvp != nil {
|
||||||
|
return *svp != *smvp, nil
|
||||||
|
}
|
||||||
|
case ">=", "ge":
|
||||||
|
if ivp != nil && imvp != nil {
|
||||||
|
return *ivp >= *imvp, nil
|
||||||
|
} else if svp != nil && smvp != nil {
|
||||||
|
return *svp >= *smvp, nil
|
||||||
|
}
|
||||||
|
case ">", "gt":
|
||||||
|
if ivp != nil && imvp != nil {
|
||||||
|
return *ivp > *imvp, nil
|
||||||
|
} else if svp != nil && smvp != nil {
|
||||||
|
return *svp > *smvp, nil
|
||||||
|
}
|
||||||
|
case "<=", "le":
|
||||||
|
if ivp != nil && imvp != nil {
|
||||||
|
return *ivp <= *imvp, nil
|
||||||
|
} else if svp != nil && smvp != nil {
|
||||||
|
return *svp <= *smvp, nil
|
||||||
|
}
|
||||||
|
case "<", "lt":
|
||||||
|
if ivp != nil && imvp != nil {
|
||||||
|
return *ivp < *imvp, nil
|
||||||
|
} else if svp != nil && smvp != nil {
|
||||||
|
return *svp < *smvp, nil
|
||||||
|
}
|
||||||
|
case "in", "not in":
|
||||||
|
var r bool
|
||||||
|
if ivp != nil && len(ima) > 0 {
|
||||||
|
r = In(ima, *ivp)
|
||||||
|
} else if svp != nil {
|
||||||
|
if len(sma) > 0 {
|
||||||
|
r = In(sma, *svp)
|
||||||
|
} else if smvp != nil {
|
||||||
|
r = In(*smvp, *svp)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
if op == "not in" {
|
||||||
|
return !r, nil
|
||||||
|
} else {
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return false, errors.New("no such an operator")
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Where(seq, key interface{}, args ...interface{}) (r interface{}, err error) {
|
||||||
seqv := reflect.ValueOf(seq)
|
seqv := reflect.ValueOf(seq)
|
||||||
kv := reflect.ValueOf(key)
|
kv := reflect.ValueOf(key)
|
||||||
mv := reflect.ValueOf(match)
|
|
||||||
|
var mv reflect.Value
|
||||||
|
var op string
|
||||||
|
switch len(args) {
|
||||||
|
case 1:
|
||||||
|
mv = reflect.ValueOf(args[0])
|
||||||
|
case 2:
|
||||||
|
var ok bool
|
||||||
|
if op, ok = args[0].(string); !ok {
|
||||||
|
return nil, errors.New("operator argument must be string type")
|
||||||
|
}
|
||||||
|
op = strings.TrimSpace(strings.ToLower(op))
|
||||||
|
mv = reflect.ValueOf(args[1])
|
||||||
|
default:
|
||||||
|
return nil, errors.New("can't evaluate the array by no match argument or more than or equal to two arguments")
|
||||||
|
}
|
||||||
|
|
||||||
seqv, isNil := indirect(seqv)
|
seqv, isNil := indirect(seqv)
|
||||||
if isNil {
|
if isNil {
|
||||||
|
@ -403,17 +534,10 @@ func Where(seq, key, match interface{}) (r interface{}, err error) {
|
||||||
vvv = vv.MapIndex(kv)
|
vvv = vv.MapIndex(kv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if vvv.IsValid() && mv.Type() == vvv.Type() {
|
if ok, err := checkCondition(vvv, mv, op); ok {
|
||||||
switch mv.Kind() {
|
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
||||||
if mv.Int() == vvv.Int() {
|
|
||||||
rv = reflect.Append(rv, rvv)
|
rv = reflect.Append(rv, rvv)
|
||||||
}
|
} else if err != nil {
|
||||||
case reflect.String:
|
return nil, err
|
||||||
if mv.String() == vvv.String() {
|
|
||||||
rv = reflect.Append(rv, rvv)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return rv.Interface(), nil
|
return rv.Interface(), nil
|
||||||
|
|
|
@ -388,6 +388,62 @@ func TestEvaluateSubElem(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCheckCondition(t *testing.T) {
|
||||||
|
type expect struct {
|
||||||
|
result bool
|
||||||
|
isError bool
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, this := range []struct {
|
||||||
|
value reflect.Value
|
||||||
|
match reflect.Value
|
||||||
|
op string
|
||||||
|
expect
|
||||||
|
}{
|
||||||
|
{reflect.ValueOf(123), reflect.ValueOf(123), "", expect{true, false}},
|
||||||
|
{reflect.ValueOf("foo"), reflect.ValueOf("foo"), "", expect{true, false}},
|
||||||
|
{reflect.ValueOf(123), reflect.ValueOf(456), "!=", expect{true, false}},
|
||||||
|
{reflect.ValueOf("foo"), reflect.ValueOf("bar"), "!=", expect{true, false}},
|
||||||
|
{reflect.ValueOf(456), reflect.ValueOf(123), ">=", expect{true, false}},
|
||||||
|
{reflect.ValueOf("foo"), reflect.ValueOf("bar"), ">=", expect{true, false}},
|
||||||
|
{reflect.ValueOf(456), reflect.ValueOf(123), ">", expect{true, false}},
|
||||||
|
{reflect.ValueOf("foo"), reflect.ValueOf("bar"), ">", expect{true, false}},
|
||||||
|
{reflect.ValueOf(123), reflect.ValueOf(456), "<=", expect{true, false}},
|
||||||
|
{reflect.ValueOf("bar"), reflect.ValueOf("foo"), "<=", expect{true, false}},
|
||||||
|
{reflect.ValueOf(123), reflect.ValueOf(456), "<", expect{true, false}},
|
||||||
|
{reflect.ValueOf("bar"), reflect.ValueOf("foo"), "<", expect{true, false}},
|
||||||
|
{reflect.ValueOf(123), reflect.ValueOf([]int{123, 45, 678}), "in", expect{true, false}},
|
||||||
|
{reflect.ValueOf("foo"), reflect.ValueOf([]string{"foo", "bar", "baz"}), "in", expect{true, false}},
|
||||||
|
{reflect.ValueOf(123), reflect.ValueOf([]int{45, 678}), "not in", expect{true, false}},
|
||||||
|
{reflect.ValueOf("foo"), reflect.ValueOf([]string{"bar", "baz"}), "not in", expect{true, false}},
|
||||||
|
{reflect.ValueOf("foo"), reflect.ValueOf("bar-foo-baz"), "in", expect{true, false}},
|
||||||
|
{reflect.ValueOf("foo"), reflect.ValueOf("bar--baz"), "not in", expect{true, false}},
|
||||||
|
{reflect.Value{}, reflect.ValueOf("foo"), "", expect{false, false}},
|
||||||
|
{reflect.ValueOf("foo"), reflect.Value{}, "", expect{false, false}},
|
||||||
|
{reflect.ValueOf((*TstX)(nil)), reflect.ValueOf("foo"), "", expect{false, false}},
|
||||||
|
{reflect.ValueOf("foo"), reflect.ValueOf((*TstX)(nil)), "", expect{false, false}},
|
||||||
|
{reflect.ValueOf("foo"), reflect.ValueOf(map[int]string{}), "", expect{false, false}},
|
||||||
|
{reflect.ValueOf("foo"), reflect.ValueOf([]int{1, 2}), "", expect{false, false}},
|
||||||
|
{reflect.ValueOf(123), reflect.ValueOf([]int{}), "in", expect{false, false}},
|
||||||
|
{reflect.ValueOf(123), reflect.ValueOf(123), "op", expect{false, true}},
|
||||||
|
} {
|
||||||
|
result, err := checkCondition(this.value, this.match, this.op)
|
||||||
|
if this.expect.isError {
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("[%d] checkCondition didn't return an expected error", i)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("[%d] failed: %s", i, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if result != this.expect.result {
|
||||||
|
t.Errorf("[%d] check condition %v %s %v, got %v but expected %v", i, this.value, this.op, this.match, result, this.expect.result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestWhere(t *testing.T) {
|
func TestWhere(t *testing.T) {
|
||||||
// TODO(spf): Put these page tests back in
|
// TODO(spf): Put these page tests back in
|
||||||
//page1 := &Page{contentType: "v", Source: Source{File: *source.NewFile("/x/y/z/source.md")}}
|
//page1 := &Page{contentType: "v", Source: Source{File: *source.NewFile("/x/y/z/source.md")}}
|
||||||
|
@ -400,30 +456,192 @@ func TestWhere(t *testing.T) {
|
||||||
for i, this := range []struct {
|
for i, this := range []struct {
|
||||||
sequence interface{}
|
sequence interface{}
|
||||||
key interface{}
|
key interface{}
|
||||||
|
op string
|
||||||
match interface{}
|
match interface{}
|
||||||
expect interface{}
|
expect interface{}
|
||||||
}{
|
}{
|
||||||
{[]map[int]string{{1: "a", 2: "m"}, {1: "c", 2: "d"}, {1: "e", 3: "m"}}, 2, "m", []map[int]string{{1: "a", 2: "m"}}},
|
{
|
||||||
{[]map[string]int{{"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "x": 4}}, "b", 4, []map[string]int{{"a": 3, "b": 4}}},
|
sequence: []map[int]string{
|
||||||
{[]TstX{{A: "a", B: "b"}, {A: "c", B: "d"}, {A: "e", B: "f"}}, "B", "f", []TstX{{A: "e", B: "f"}}},
|
{1: "a", 2: "m"}, {1: "c", 2: "d"}, {1: "e", 3: "m"},
|
||||||
{[]*map[int]string{&map[int]string{1: "a", 2: "m"}, &map[int]string{1: "c", 2: "d"}, &map[int]string{1: "e", 3: "m"}}, 2, "m", []*map[int]string{&map[int]string{1: "a", 2: "m"}}},
|
},
|
||||||
{[]*TstX{&TstX{A: "a", B: "b"}, &TstX{A: "c", B: "d"}, &TstX{A: "e", B: "f"}}, "B", "f", []*TstX{&TstX{A: "e", B: "f"}}},
|
key: 2, match: "m",
|
||||||
{[]*TstX{&TstX{A: "a", B: "b"}, &TstX{A: "c", B: "d"}, &TstX{A: "e", B: "c"}}, "TstRp", "rc", []*TstX{&TstX{A: "c", B: "d"}}},
|
expect: []map[int]string{
|
||||||
{[]TstX{TstX{A: "a", B: "b"}, TstX{A: "c", B: "d"}, TstX{A: "e", B: "c"}}, "TstRv", "rc", []TstX{TstX{A: "e", B: "c"}}},
|
{1: "a", 2: "m"},
|
||||||
{[]map[string]TstX{{"foo": TstX{A: "a", B: "b"}}, {"foo": TstX{A: "c", B: "d"}}, {"foo": TstX{A: "e", B: "f"}}}, "foo.B", "d", []map[string]TstX{{"foo": TstX{A: "c", B: "d"}}}},
|
},
|
||||||
{[]map[string]TstX{{"foo": TstX{A: "a", B: "b"}}, {"foo": TstX{A: "c", B: "d"}}, {"foo": TstX{A: "e", B: "f"}}}, ".foo.B", "d", []map[string]TstX{{"foo": TstX{A: "c", B: "d"}}}},
|
},
|
||||||
{[]map[string]TstX{{"foo": TstX{A: "a", B: "b"}}, {"foo": TstX{A: "c", B: "d"}}, {"foo": TstX{A: "e", B: "f"}}}, "foo.TstRv", "rd", []map[string]TstX{{"foo": TstX{A: "c", B: "d"}}}},
|
{
|
||||||
{[]map[string]*TstX{{"foo": &TstX{A: "a", B: "b"}}, {"foo": &TstX{A: "c", B: "d"}}, {"foo": &TstX{A: "e", B: "f"}}}, "foo.TstRp", "rc", []map[string]*TstX{{"foo": &TstX{A: "c", B: "d"}}}},
|
sequence: []map[string]int{
|
||||||
{[]map[string]Mid{{"foo": Mid{Tst: TstX{A: "a", B: "b"}}}, {"foo": Mid{Tst: TstX{A: "c", B: "d"}}}, {"foo": Mid{Tst: TstX{A: "e", B: "f"}}}}, "foo.Tst.B", "d", []map[string]Mid{{"foo": Mid{Tst: TstX{A: "c", B: "d"}}}}},
|
{"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "x": 4},
|
||||||
{[]map[string]Mid{{"foo": Mid{Tst: TstX{A: "a", B: "b"}}}, {"foo": Mid{Tst: TstX{A: "c", B: "d"}}}, {"foo": Mid{Tst: TstX{A: "e", B: "f"}}}}, "foo.Tst.TstRv", "rd", []map[string]Mid{{"foo": Mid{Tst: TstX{A: "c", B: "d"}}}}},
|
},
|
||||||
{[]map[string]*Mid{{"foo": &Mid{Tst: TstX{A: "a", B: "b"}}}, {"foo": &Mid{Tst: TstX{A: "c", B: "d"}}}, {"foo": &Mid{Tst: TstX{A: "e", B: "f"}}}}, "foo.Tst.TstRp", "rc", []map[string]*Mid{{"foo": &Mid{Tst: TstX{A: "c", B: "d"}}}}},
|
key: "b", match: 4,
|
||||||
{(*[]TstX)(nil), "A", "a", false},
|
expect: []map[string]int{
|
||||||
{TstX{A: "a", B: "b"}, "A", "a", false},
|
{"a": 3, "b": 4},
|
||||||
{[]map[string]*TstX{{"foo": nil}}, "foo.B", "d", false},
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sequence: []TstX{
|
||||||
|
{A: "a", B: "b"}, {A: "c", B: "d"}, {A: "e", B: "f"},
|
||||||
|
},
|
||||||
|
key: "B", match: "f",
|
||||||
|
expect: []TstX{
|
||||||
|
{A: "e", B: "f"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sequence: []*map[int]string{
|
||||||
|
&map[int]string{1: "a", 2: "m"}, &map[int]string{1: "c", 2: "d"}, &map[int]string{1: "e", 3: "m"},
|
||||||
|
},
|
||||||
|
key: 2, match: "m",
|
||||||
|
expect: []*map[int]string{
|
||||||
|
&map[int]string{1: "a", 2: "m"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sequence: []*TstX{
|
||||||
|
&TstX{A: "a", B: "b"}, &TstX{A: "c", B: "d"}, &TstX{A: "e", B: "f"},
|
||||||
|
},
|
||||||
|
key: "B", match: "f",
|
||||||
|
expect: []*TstX{
|
||||||
|
&TstX{A: "e", B: "f"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sequence: []*TstX{
|
||||||
|
&TstX{A: "a", B: "b"}, &TstX{A: "c", B: "d"}, &TstX{A: "e", B: "c"},
|
||||||
|
},
|
||||||
|
key: "TstRp", match: "rc",
|
||||||
|
expect: []*TstX{
|
||||||
|
&TstX{A: "c", B: "d"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sequence: []TstX{
|
||||||
|
TstX{A: "a", B: "b"}, TstX{A: "c", B: "d"}, TstX{A: "e", B: "c"},
|
||||||
|
},
|
||||||
|
key: "TstRv", match: "rc",
|
||||||
|
expect: []TstX{
|
||||||
|
TstX{A: "e", B: "c"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sequence: []map[string]TstX{
|
||||||
|
{"foo": TstX{A: "a", B: "b"}}, {"foo": TstX{A: "c", B: "d"}}, {"foo": TstX{A: "e", B: "f"}},
|
||||||
|
},
|
||||||
|
key: "foo.B", match: "d",
|
||||||
|
expect: []map[string]TstX{
|
||||||
|
{"foo": TstX{A: "c", B: "d"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sequence: []map[string]TstX{
|
||||||
|
{"foo": TstX{A: "a", B: "b"}}, {"foo": TstX{A: "c", B: "d"}}, {"foo": TstX{A: "e", B: "f"}},
|
||||||
|
},
|
||||||
|
key: ".foo.B", match: "d",
|
||||||
|
expect: []map[string]TstX{
|
||||||
|
{"foo": TstX{A: "c", B: "d"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sequence: []map[string]TstX{
|
||||||
|
{"foo": TstX{A: "a", B: "b"}}, {"foo": TstX{A: "c", B: "d"}}, {"foo": TstX{A: "e", B: "f"}},
|
||||||
|
},
|
||||||
|
key: "foo.TstRv", match: "rd",
|
||||||
|
expect: []map[string]TstX{
|
||||||
|
{"foo": TstX{A: "c", B: "d"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sequence: []map[string]*TstX{
|
||||||
|
{"foo": &TstX{A: "a", B: "b"}}, {"foo": &TstX{A: "c", B: "d"}}, {"foo": &TstX{A: "e", B: "f"}},
|
||||||
|
},
|
||||||
|
key: "foo.TstRp", match: "rc",
|
||||||
|
expect: []map[string]*TstX{
|
||||||
|
{"foo": &TstX{A: "c", B: "d"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sequence: []map[string]Mid{
|
||||||
|
{"foo": Mid{Tst: TstX{A: "a", B: "b"}}}, {"foo": Mid{Tst: TstX{A: "c", B: "d"}}}, {"foo": Mid{Tst: TstX{A: "e", B: "f"}}},
|
||||||
|
},
|
||||||
|
key: "foo.Tst.B", match: "d",
|
||||||
|
expect: []map[string]Mid{
|
||||||
|
{"foo": Mid{Tst: TstX{A: "c", B: "d"}}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sequence: []map[string]Mid{
|
||||||
|
{"foo": Mid{Tst: TstX{A: "a", B: "b"}}}, {"foo": Mid{Tst: TstX{A: "c", B: "d"}}}, {"foo": Mid{Tst: TstX{A: "e", B: "f"}}},
|
||||||
|
},
|
||||||
|
key: "foo.Tst.TstRv", match: "rd",
|
||||||
|
expect: []map[string]Mid{
|
||||||
|
{"foo": Mid{Tst: TstX{A: "c", B: "d"}}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sequence: []map[string]*Mid{
|
||||||
|
{"foo": &Mid{Tst: TstX{A: "a", B: "b"}}}, {"foo": &Mid{Tst: TstX{A: "c", B: "d"}}}, {"foo": &Mid{Tst: TstX{A: "e", B: "f"}}},
|
||||||
|
},
|
||||||
|
key: "foo.Tst.TstRp", match: "rc",
|
||||||
|
expect: []map[string]*Mid{
|
||||||
|
{"foo": &Mid{Tst: TstX{A: "c", B: "d"}}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sequence: []map[string]int{
|
||||||
|
{"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "b": 6},
|
||||||
|
},
|
||||||
|
key: "b", op: ">", match: 3,
|
||||||
|
expect: []map[string]int{
|
||||||
|
{"a": 3, "b": 4}, {"a": 5, "b": 6},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sequence: []TstX{
|
||||||
|
{A: "a", B: "b"}, {A: "c", B: "d"}, {A: "e", B: "f"},
|
||||||
|
},
|
||||||
|
key: "B", op: "!=", match: "f",
|
||||||
|
expect: []TstX{
|
||||||
|
{A: "a", B: "b"}, {A: "c", B: "d"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sequence: []map[string]int{
|
||||||
|
{"a": 1, "b": 2}, {"a": 3, "b": 4}, {"a": 5, "b": 6},
|
||||||
|
},
|
||||||
|
key: "b", op: "in", match: []int{3, 4, 5},
|
||||||
|
expect: []map[string]int{
|
||||||
|
{"a": 3, "b": 4},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sequence: []TstX{
|
||||||
|
{A: "a", B: "b"}, {A: "c", B: "d"}, {A: "e", B: "f"},
|
||||||
|
},
|
||||||
|
key: "B", op: "not in", match: []string{"c", "d", "e"},
|
||||||
|
expect: []TstX{
|
||||||
|
{A: "a", B: "b"}, {A: "e", B: "f"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{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},
|
||||||
|
{
|
||||||
|
sequence: []TstX{
|
||||||
|
{A: "a", B: "b"}, {A: "c", B: "d"}, {A: "e", B: "f"},
|
||||||
|
},
|
||||||
|
key: "B", op: "op", match: "f",
|
||||||
|
expect: false,
|
||||||
|
},
|
||||||
//{[]*Page{page1, page2}, "Type", "v", []*Page{page1}},
|
//{[]*Page{page1, page2}, "Type", "v", []*Page{page1}},
|
||||||
//{[]*Page{page1, page2}, "Section", "y", []*Page{page2}},
|
//{[]*Page{page1, page2}, "Section", "y", []*Page{page2}},
|
||||||
} {
|
} {
|
||||||
results, err := Where(this.sequence, this.key, this.match)
|
var results interface{}
|
||||||
|
var err error
|
||||||
|
if len(this.op) > 0 {
|
||||||
|
results, err = Where(this.sequence, this.key, this.op, this.match)
|
||||||
|
} else {
|
||||||
|
results, err = Where(this.sequence, this.key, this.match)
|
||||||
|
}
|
||||||
if b, ok := this.expect.(bool); ok && !b {
|
if b, ok := this.expect.(bool); ok && !b {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("[%d] Where didn't return an expected error", i)
|
t.Errorf("[%d] Where didn't return an expected error", i)
|
||||||
|
@ -438,6 +656,22 @@ func TestWhere(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
_, err = Where(map[string]int{"a": 1, "b": 2}, "a", []byte("="), 1)
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Where called with none string op value didn't return an expected error")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = Where(map[string]int{"a": 1, "b": 2}, "a", []byte("="), 1, 2)
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Where called with more than two variable arguments didn't return an expected error")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = Where(map[string]int{"a": 1, "b": 2}, "a")
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Where called with no variable arguments didn't return an expected error")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDelimit(t *testing.T) {
|
func TestDelimit(t *testing.T) {
|
||||||
|
|
Loading…
Reference in a new issue