Add time.Time type support to where tpl func

`where` tpl function doesn't support `time.Time` type so if people want
to compare such values, it's required that these values are converted
into `int` and compare them.

This improves it. If `time.Time` values are passed to `where`, it
converts them into `int` internally, compares them and returns the
result.

See also
http://discuss.gohugo.io/t/future-posts-and-past-posts/1229/3
This commit is contained in:
Tatsushi Demachi 2015-05-26 19:33:32 +09:00 committed by bep
parent beaa09a7f6
commit 601a2ce124
2 changed files with 108 additions and 3 deletions

View file

@ -17,9 +17,6 @@ import (
"bytes" "bytes"
"errors" "errors"
"fmt" "fmt"
"github.com/spf13/cast"
"github.com/spf13/hugo/helpers"
jww "github.com/spf13/jwalterweatherman"
"html" "html"
"html/template" "html/template"
"os" "os"
@ -27,6 +24,11 @@ import (
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
"time"
"github.com/spf13/cast"
"github.com/spf13/hugo/helpers"
jww "github.com/spf13/jwalterweatherman"
) )
var funcMap template.FuncMap var funcMap template.FuncMap
@ -364,8 +366,16 @@ func First(limit interface{}, seq interface{}) (interface{}, error) {
var ( var (
zero reflect.Value zero reflect.Value
errorType = reflect.TypeOf((*error)(nil)).Elem() errorType = reflect.TypeOf((*error)(nil)).Elem()
timeType = reflect.TypeOf((*time.Time)(nil)).Elem()
) )
func timeUnix(v reflect.Value) int64 {
if v.Type() != timeType {
panic("coding error: argument must be time.Time type reflect Value")
}
return v.MethodByName("Unix").Call([]reflect.Value{})[0].Int()
}
func evaluateSubElem(obj reflect.Value, elemName string) (reflect.Value, error) { func evaluateSubElem(obj reflect.Value, elemName string) (reflect.Value, error) {
if !obj.IsValid() { if !obj.IsValid() {
return zero, errors.New("can't evaluate an invalid value") return zero, errors.New("can't evaluate an invalid value")
@ -459,6 +469,14 @@ func checkCondition(v, mv reflect.Value, op string) (bool, error) {
svp = &sv svp = &sv
smv := mv.String() smv := mv.String()
smvp = &smv smvp = &smv
case reflect.Struct:
switch v.Type() {
case timeType:
iv := timeUnix(v)
ivp = &iv
imv := timeUnix(mv)
imvp = &imv
}
} }
} else { } else {
if mv.Kind() != reflect.Array && mv.Kind() != reflect.Slice { if mv.Kind() != reflect.Array && mv.Kind() != reflect.Slice {
@ -480,6 +498,15 @@ func checkCondition(v, mv reflect.Value, op string) (bool, error) {
for i := 0; i < mv.Len(); i++ { for i := 0; i < mv.Len(); i++ {
sma = append(sma, mv.Index(i).String()) sma = append(sma, mv.Index(i).String())
} }
case reflect.Struct:
switch v.Type() {
case timeType:
iv := timeUnix(v)
ivp = &iv
for i := 0; i < mv.Len(); i++ {
ima = append(ima, timeUnix(mv.Index(i)))
}
}
} }
} }

View file

@ -479,6 +479,28 @@ type TstX struct {
unexported string unexported string
} }
func TestTimeUnix(t *testing.T) {
var sec int64 = 1234567890
tv := reflect.ValueOf(time.Unix(sec, 0))
i := 1
res := timeUnix(tv)
if sec != res {
t.Errorf("[%d] timeUnix got %v but expected %v", i, res, sec)
}
i++
func(t *testing.T) {
defer func() {
if err := recover(); err == nil {
t.Errorf("[%d] timeUnix didn't return an expected error", i)
}
}()
iv := reflect.ValueOf(sec)
timeUnix(iv)
}(t)
}
func TestEvaluateSubElem(t *testing.T) { func TestEvaluateSubElem(t *testing.T) {
tstx := TstX{A: "foo", B: "bar"} tstx := TstX{A: "foo", B: "bar"}
var inner struct { var inner struct {
@ -543,20 +565,76 @@ func TestCheckCondition(t *testing.T) {
}{ }{
{reflect.ValueOf(123), reflect.ValueOf(123), "", expect{true, false}}, {reflect.ValueOf(123), reflect.ValueOf(123), "", expect{true, false}},
{reflect.ValueOf("foo"), reflect.ValueOf("foo"), "", expect{true, false}}, {reflect.ValueOf("foo"), reflect.ValueOf("foo"), "", expect{true, false}},
{
reflect.ValueOf(time.Date(2015, time.May, 26, 19, 18, 56, 12345, time.UTC)),
reflect.ValueOf(time.Date(2015, time.May, 26, 19, 18, 56, 12345, time.UTC)),
"",
expect{true, false},
},
{reflect.ValueOf(123), reflect.ValueOf(456), "!=", expect{true, false}}, {reflect.ValueOf(123), reflect.ValueOf(456), "!=", expect{true, false}},
{reflect.ValueOf("foo"), reflect.ValueOf("bar"), "!=", expect{true, false}}, {reflect.ValueOf("foo"), reflect.ValueOf("bar"), "!=", expect{true, false}},
{
reflect.ValueOf(time.Date(2015, time.May, 26, 19, 18, 56, 12345, time.UTC)),
reflect.ValueOf(time.Date(2015, time.April, 26, 19, 18, 56, 12345, time.UTC)),
"!=",
expect{true, false},
},
{reflect.ValueOf(456), reflect.ValueOf(123), ">=", expect{true, false}}, {reflect.ValueOf(456), reflect.ValueOf(123), ">=", expect{true, false}},
{reflect.ValueOf("foo"), reflect.ValueOf("bar"), ">=", expect{true, false}}, {reflect.ValueOf("foo"), reflect.ValueOf("bar"), ">=", expect{true, false}},
{
reflect.ValueOf(time.Date(2015, time.May, 26, 19, 18, 56, 12345, time.UTC)),
reflect.ValueOf(time.Date(2015, time.April, 26, 19, 18, 56, 12345, time.UTC)),
">=",
expect{true, false},
},
{reflect.ValueOf(456), reflect.ValueOf(123), ">", expect{true, false}}, {reflect.ValueOf(456), reflect.ValueOf(123), ">", expect{true, false}},
{reflect.ValueOf("foo"), reflect.ValueOf("bar"), ">", expect{true, false}}, {reflect.ValueOf("foo"), reflect.ValueOf("bar"), ">", expect{true, false}},
{
reflect.ValueOf(time.Date(2015, time.May, 26, 19, 18, 56, 12345, time.UTC)),
reflect.ValueOf(time.Date(2015, time.April, 26, 19, 18, 56, 12345, time.UTC)),
">",
expect{true, false},
},
{reflect.ValueOf(123), reflect.ValueOf(456), "<=", expect{true, false}}, {reflect.ValueOf(123), reflect.ValueOf(456), "<=", expect{true, false}},
{reflect.ValueOf("bar"), reflect.ValueOf("foo"), "<=", expect{true, false}}, {reflect.ValueOf("bar"), reflect.ValueOf("foo"), "<=", expect{true, false}},
{
reflect.ValueOf(time.Date(2015, time.April, 26, 19, 18, 56, 12345, time.UTC)),
reflect.ValueOf(time.Date(2015, time.May, 26, 19, 18, 56, 12345, time.UTC)),
"<=",
expect{true, false},
},
{reflect.ValueOf(123), reflect.ValueOf(456), "<", expect{true, false}}, {reflect.ValueOf(123), reflect.ValueOf(456), "<", expect{true, false}},
{reflect.ValueOf("bar"), reflect.ValueOf("foo"), "<", expect{true, false}}, {reflect.ValueOf("bar"), reflect.ValueOf("foo"), "<", expect{true, false}},
{
reflect.ValueOf(time.Date(2015, time.April, 26, 19, 18, 56, 12345, time.UTC)),
reflect.ValueOf(time.Date(2015, time.May, 26, 19, 18, 56, 12345, time.UTC)),
"<",
expect{true, false},
},
{reflect.ValueOf(123), reflect.ValueOf([]int{123, 45, 678}), "in", 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("foo"), reflect.ValueOf([]string{"foo", "bar", "baz"}), "in", expect{true, false}},
{
reflect.ValueOf(time.Date(2015, time.May, 26, 19, 18, 56, 12345, time.UTC)),
reflect.ValueOf([]time.Time{
time.Date(2015, time.April, 26, 19, 18, 56, 12345, time.UTC),
time.Date(2015, time.May, 26, 19, 18, 56, 12345, time.UTC),
time.Date(2015, time.June, 26, 19, 18, 56, 12345, time.UTC),
}),
"in",
expect{true, false},
},
{reflect.ValueOf(123), reflect.ValueOf([]int{45, 678}), "not 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([]string{"bar", "baz"}), "not in", expect{true, false}},
{
reflect.ValueOf(time.Date(2015, time.May, 26, 19, 18, 56, 12345, time.UTC)),
reflect.ValueOf([]time.Time{
time.Date(2015, time.February, 26, 19, 18, 56, 12345, time.UTC),
time.Date(2015, time.March, 26, 19, 18, 56, 12345, time.UTC),
time.Date(2015, time.April, 26, 19, 18, 56, 12345, time.UTC),
}),
"not in",
expect{true, false},
},
{reflect.ValueOf("foo"), reflect.ValueOf("bar-foo-baz"), "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.ValueOf("foo"), reflect.ValueOf("bar--baz"), "not in", expect{true, false}},
{reflect.Value{}, reflect.ValueOf("foo"), "", expect{false, false}}, {reflect.Value{}, reflect.ValueOf("foo"), "", expect{false, false}},