/
multisorter.go
86 lines (70 loc) · 1.56 KB
/
multisorter.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
package multisort
import (
"fmt"
"slices"
"sort"
)
// Sorter can sort by multiple criteria.
type Sorter[E any] struct {
defaultSortKeys Keys
fields FieldMap[E]
}
// FieldMap defines the fields that the sorter is capable to sort and provides the corresponsing compare funcs.
type FieldMap[E any] map[string]CompareFn[E]
// Key is the key that will be sorted by.
type Key struct {
ID string
Descending bool
}
type Keys []Key
// New creates a new multisorter.
func New[E any](fields FieldMap[E], defaultSortKeys Keys) *Sorter[E] {
return &Sorter[E]{
defaultSortKeys: defaultSortKeys,
fields: fields,
}
}
// SortBy sorts the given data by the given sort keys.
func (s *Sorter[E]) SortBy(data []E, keys ...Key) error {
if len(keys) == 0 {
keys = s.defaultSortKeys
}
if len(keys) == 0 {
return nil
}
err := s.validate(keys...)
if err != nil {
return err
}
slices.SortStableFunc(data, func(a, b E) int {
for _, key := range keys {
f := s.fields[key.ID]
switch f(a, b, key.Descending) {
case Less:
return -1
case NotEqual:
return 1
}
}
return 0
})
return nil
}
// AvailableKeys returns the available sort keys that this sorter has been initialized with.
func (s *Sorter[E]) AvailableKeys() []string {
var res []string
for k := range s.fields {
res = append(res, k)
}
sort.Strings(res)
return res
}
func (s *Sorter[E]) validate(keys ...Key) error {
for _, key := range keys {
_, ok := s.fields[key.ID]
if !ok {
return fmt.Errorf("sort key does not exist: %s", key.ID)
}
}
return nil
}