forked from pilagod/gorm-cursor-paginator
/
util.go
100 lines (86 loc) · 2.2 KB
/
util.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
package paginator
import (
"encoding/base64"
"fmt"
"reflect"
"strings"
"time"
)
/* public */
// Encode encodes properties in order defined by keys on the struct of v
func Encode(v reflect.Value, keys []string) string {
fields := make([]string, len(keys))
for index, key := range keys {
if v.Kind() == reflect.Ptr {
fields[index] = convert(reflect.Indirect(v).FieldByName(key).Interface())
} else {
fields[index] = convert(v.FieldByName(key).Interface())
}
}
return encodeBase64(fields)
}
// Decode decodes cursor into values in the same order as encoding
func Decode(cursor string) []interface{} {
fieldsWithType := decodeBase64(cursor)
fields := make([]interface{}, len(fieldsWithType))
for index, fieldWithType := range fieldsWithType {
fields[index] = revert(fieldWithType)
}
return fields
}
/* private */
type fieldType string
const (
fieldString fieldType = "STRING"
fieldTime fieldType = "TIME"
)
func convert(field interface{}) string {
switch field.(type) {
case time.Time:
return fmt.Sprintf("%s?%s", field.(time.Time).UTC().Format(time.RFC3339Nano), fieldTime)
default:
return fmt.Sprintf("%v?%s", field, fieldString)
}
}
func revert(fieldWithType string) interface{} {
field, fieldType := parseFieldWithType(fieldWithType)
switch fieldType {
case fieldTime:
t, err := time.Parse(time.RFC3339Nano, field)
if err != nil {
t = time.Now().UTC()
}
return t
default:
return field
}
}
func parseFieldWithType(fieldWithType string) (string, fieldType) {
sep := strings.LastIndex(fieldWithType, "?")
field := fieldWithType[:sep]
fieldType := fieldType(fieldWithType[sep+1:])
return field, fieldType
}
func flip(order Order) Order {
if order == ASC {
return DESC
}
return ASC
}
func reverse(v reflect.Value) reflect.Value {
result := reflect.MakeSlice(v.Type(), 0, v.Cap())
for i := v.Len() - 1; i >= 0; i-- {
result = reflect.Append(result, v.Index(i))
}
return result
}
func encodeBase64(fields []string) string {
return base64.StdEncoding.EncodeToString([]byte(strings.Join(fields, ",")))
}
func decodeBase64(cursor string) []string {
b, err := base64.StdEncoding.DecodeString(cursor)
if err != nil {
return nil
}
return strings.Split(string(b), ",")
}