Skip to content

Commit

Permalink
Support numeric sort in ByParam
Browse files Browse the repository at this point in the history
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 gohugoio#5305
  • Loading branch information
tryzniak authored and bep committed Jan 20, 2019
1 parent e1a66c7 commit 26f75ed
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 6 deletions.
26 changes: 20 additions & 6 deletions hugolib/pageSort.go
Original file line number Diff line number Diff line change
Expand Up @@ -291,24 +291,38 @@ 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

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
}

Expand Down
43 changes: 43 additions & 0 deletions hugolib/pageSort_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit 26f75ed

Please sign in to comment.