Support numeric sort in ByParam
authorAnton Harniakou <anton.harniakou@gmail.com>
Tue, 15 Jan 2019 12:41:54 +0000 (15:41 +0300)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Sun, 20 Jan 2019 13:05:20 +0000 (13:05 +0000)
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
hugolib/pageSort_test.go

index c7766e2a69cc5673702d5aa83b6611003b573e23..454beb473e9f06fa74ed9a06dbfc849a8f7d836e 100644 (file)
@@ -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
        }
 
index 695045ff125e93ade73a8a829400e1a8c3f329f7..915947fd3afa319ffc87d76afdda5164ff481573 100644 (file)
@@ -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)