/
encoder.go
104 lines (87 loc) · 2.09 KB
/
encoder.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
// Copyright © 2017 The Things Network
// Use of this source code is governed by the MIT license that can be found in the LICENSE file.
package storage
import (
"encoding"
"encoding/json"
"fmt"
"reflect"
"github.com/fatih/structs"
)
// StringStringMapEncoder encodes the given properties of the input to a map[string]string for storage in Redis
type StringStringMapEncoder func(input interface{}, properties ...string) (map[string]string, error)
type isZeroer interface {
IsZero() bool
}
type isEmptier interface {
IsEmpty() bool
}
func buildDefaultStructEncoder(tagName string) StringStringMapEncoder {
if tagName == "" {
tagName = defaultTagName
}
return func(input interface{}, properties ...string) (map[string]string, error) {
vmap := make(map[string]string)
s := structs.New(input)
s.TagName = tagName
if len(properties) == 0 {
properties = s.Names()
}
for _, field := range s.Fields() {
if !field.IsExported() {
continue
}
if !stringInSlice(field.Name(), properties) {
continue
}
tagName, opts := parseTag(field.Tag(tagName))
if tagName == "" || tagName == "-" {
continue
}
val := field.Value()
if opts.Has("omitempty") {
if field.IsZero() {
continue
}
if z, ok := val.(isZeroer); ok && z.IsZero() {
continue
}
if z, ok := val.(isEmptier); ok && z.IsEmpty() {
continue
}
}
if v, ok := val.(string); ok {
vmap[tagName] = v
continue
}
if !field.IsZero() {
if m, ok := val.(encoding.TextMarshaler); ok {
txt, err := m.MarshalText()
if err != nil {
return nil, err
}
vmap[tagName] = string(txt)
continue
}
if m, ok := val.(json.Marshaler); ok {
txt, err := m.MarshalJSON()
if err != nil {
return nil, err
}
vmap[tagName] = string(txt)
continue
}
}
if field.Kind() == reflect.String {
vmap[tagName] = fmt.Sprint(val)
continue
}
if txt, err := json.Marshal(val); err == nil {
vmap[tagName] = string(txt)
continue
}
vmap[tagName] = fmt.Sprintf("%v", val)
}
return vmap, nil
}
}