111 lines
1.8 KiB
Go
111 lines
1.8 KiB
Go
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)
|
|
}
|