-
Notifications
You must be signed in to change notification settings - Fork 0
/
sort.go
110 lines (85 loc) · 1.79 KB
/
sort.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package path
import (
"errors"
"reflect"
"sort"
"time"
"cloud.google.com/go/civil"
"github.com/gopatchy/jsrest"
)
func Sort(objs any, path string) error {
as := newAnySlice(objs, path)
sort.Stable(as)
return as.err
}
func SortReverse(objs any, path string) error {
as := newAnySlice(objs, path)
sort.Stable(sort.Reverse(as))
return as.err
}
type anySlice struct {
path string
slice reflect.Value
swapper func(i, j int)
err error
}
var ErrUnsupportedSortType = errors.New("unsupported _sort type")
func newAnySlice(objs any, path string) *anySlice {
return &anySlice{
path: path,
slice: reflect.ValueOf(objs),
swapper: reflect.Swapper(objs),
}
}
func (as *anySlice) Len() int {
return as.slice.Len()
}
func (as *anySlice) Less(i, j int) bool {
v1, err := Get(as.slice.Index(i).Interface(), as.path)
if err != nil {
as.err = err
// We have to obey the Less() contract even in error cases
return i < j
}
v2, err := Get(as.slice.Index(j).Interface(), as.path)
if err != nil {
as.err = err
return i < j
}
switch {
case v1 == nil && v2 == nil:
return false
case v1 == nil:
return true
case v2 == nil:
return false
}
switch t1 := v1.(type) {
case int:
return t1 < v2.(int)
case int64:
return t1 < v2.(int64)
case uint:
return t1 < v2.(uint)
case uint64:
return t1 < v2.(uint64)
case float32:
return t1 < v2.(float32)
case float64:
return t1 < v2.(float64)
case string:
return t1 < v2.(string)
case bool:
return !t1 && v2.(bool)
case time.Time:
return t1.Before(v2.(time.Time))
case civil.Date:
return t1.Before(v2.(civil.Date))
default:
as.err = jsrest.Errorf(jsrest.ErrBadRequest, "%s: %T (%w)", as.path, t1, ErrUnsupportedSortType)
return i < j
}
}
func (as *anySlice) Swap(i, j int) {
as.swapper(i, j)
}