From 26f75edb7a76c816349749a05edf98fb36dc338a Mon Sep 17 00:00:00 2001 From: Anton Harniakou Date: Tue, 15 Jan 2019 15:41:54 +0300 Subject: [PATCH] Support numeric sort in ByParam With this commit ByParam takes into account a type of a value under a key. If both values are numeric then they're coerced into float64 and then get compared. If any value isn't numeric, for example it's nil or string, then both values coerced into string and get compared as strings (lexicographicaly) Nil values are always sent to the end. Numeric values confirm to any type listed below: uint8, uint16, uint32, uint64, int, int8, int16, int32, int64, float32, float64 Closes #5305 --- hugolib/pageSort.go | 26 ++++++++++++++++++------ hugolib/pageSort_test.go | 43 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 6 deletions(-) diff --git a/hugolib/pageSort.go b/hugolib/pageSort.go index c7766e2a6..454beb473 100644 --- a/hugolib/pageSort.go +++ b/hugolib/pageSort.go @@ -291,7 +291,6 @@ func (p Pages) Reverse() Pages { // Adjacent invocations on the same receiver with the same paramsKey will return a cached result. // // This may safely be executed in parallel. - func (p Pages) ByParam(paramsKey interface{}) Pages { paramsKeyStr := cast.ToString(paramsKey) key := "pageSort.ByParam." + paramsKeyStr @@ -299,16 +298,31 @@ func (p Pages) ByParam(paramsKey interface{}) Pages { paramsKeyComparator := func(p1, p2 *Page) bool { v1, _ := p1.Param(paramsKeyStr) v2, _ := p2.Param(paramsKeyStr) - s1 := cast.ToString(v1) - s2 := cast.ToString(v2) - // Sort nils last. - if s1 == "" { + if v1 == nil { return false - } else if s2 == "" { + } + + if v2 == nil { return true } + isNumeric := func(v interface{}) bool { + switch v.(type) { + case uint8, uint16, uint32, uint64, int, int8, int16, int32, int64, float32, float64: + return true + default: + return false + } + } + + if isNumeric(v1) && isNumeric(v2) { + return cast.ToFloat64(v1) < cast.ToFloat64(v2) + } + + s1 := cast.ToString(v1) + s2 := cast.ToString(v2) + return s1 < s2 } diff --git a/hugolib/pageSort_test.go b/hugolib/pageSort_test.go index 695045ff1..915947fd3 100644 --- a/hugolib/pageSort_test.go +++ b/hugolib/pageSort_test.go @@ -179,6 +179,49 @@ func TestPageSortByParam(t *testing.T) { assert.Equal(t, unsetValue, unsetSortedValue) } +func TestPageSortByParamNumeric(t *testing.T) { + t.Parallel() + var k interface{} = "arbitrarily.nested" + s := newTestSite(t) + + n := 10 + unsorted := createSortTestPages(s, n) + for i := 0; i < n; i++ { + v := 100 - i + if i%2 == 0 { + v = 100.0 - i + } + + unsorted[i].params = map[string]interface{}{ + "arbitrarily": map[string]interface{}{ + "nested": v, + }, + } + } + delete(unsorted[9].params, "arbitrarily") + + firstSetValue, _ := unsorted[0].Param(k) + secondSetValue, _ := unsorted[1].Param(k) + lastSetValue, _ := unsorted[8].Param(k) + unsetValue, _ := unsorted[9].Param(k) + + assert.Equal(t, 100, firstSetValue) + assert.Equal(t, 99, secondSetValue) + assert.Equal(t, 92, lastSetValue) + assert.Equal(t, nil, unsetValue) + + sorted := unsorted.ByParam("arbitrarily.nested") + firstSetSortedValue, _ := sorted[0].Param(k) + secondSetSortedValue, _ := sorted[1].Param(k) + lastSetSortedValue, _ := sorted[8].Param(k) + unsetSortedValue, _ := sorted[9].Param(k) + + assert.Equal(t, 92, firstSetSortedValue) + assert.Equal(t, 93, secondSetSortedValue) + assert.Equal(t, 100, lastSetSortedValue) + assert.Equal(t, unsetValue, unsetSortedValue) +} + func BenchmarkSortByWeightAndReverse(b *testing.B) { s := newTestSite(b) p := createSortTestPages(s, 300)