Skip to content

Commit 69738bd

Browse files
committed
Merge pull request jmoiron#118 from jmoiron/liaoliaopro-master
tag handling for reflectx
2 parents b468c08 + 621e1ee commit 69738bd

File tree

2 files changed

+46
-8
lines changed

2 files changed

+46
-8
lines changed

reflectx/reflect.go

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,11 @@ type fieldMap map[string][]int
1919
// behaves like most marshallers, optionally obeying a field tag for name
2020
// mapping and a function to provide a basic mapping of fields to names.
2121
type Mapper struct {
22-
cache map[reflect.Type]fieldMap
23-
tagName string
24-
mapFunc func(string) string
25-
mutex sync.Mutex
22+
cache map[reflect.Type]fieldMap
23+
tagName string
24+
tagMapFunc func(string) string
25+
mapFunc func(string) string
26+
mutex sync.Mutex
2627
}
2728

2829
// NewMapper returns a new mapper which optionally obeys the field tag given
@@ -34,6 +35,18 @@ func NewMapper(tagName string) *Mapper {
3435
}
3536
}
3637

38+
// NewMapperTagFunc returns a new mapper which contains a mapper for field names
39+
// AND a mapper for tag values. This is useful for tags like json which can
40+
// have values like "name,omitempty".
41+
func NewMapperTagFunc(tagName string, mapFunc, tagMapFunc func(string) string) *Mapper {
42+
return &Mapper{
43+
cache: make(map[reflect.Type]fieldMap),
44+
tagName: tagName,
45+
mapFunc: mapFunc,
46+
tagMapFunc: tagMapFunc,
47+
}
48+
}
49+
3750
// NewMapperFunc returns a new mapper which optionally obeys a field tag and
3851
// a struct field name mapper func given by f. Tags will take precedence, but
3952
// for any other field, the mapped name will be f(field.Name)
@@ -51,7 +64,7 @@ func (m *Mapper) TypeMap(t reflect.Type) fieldMap {
5164
m.mutex.Lock()
5265
mapping, ok := m.cache[t]
5366
if !ok {
54-
mapping = getMapping(t, m.tagName, m.mapFunc)
67+
mapping = getMapping(t, m.tagName, m.mapFunc, m.tagMapFunc)
5568
m.cache[t] = mapping
5669
}
5770
m.mutex.Unlock()
@@ -202,9 +215,9 @@ func apnd(is []int, i int) []int {
202215
return x
203216
}
204217

205-
// getMapping returns a mapping for the t type, using the tagName and the mapFunc
206-
// to determine the canonical names of fields.
207-
func getMapping(t reflect.Type, tagName string, mapFunc func(string) string) fieldMap {
218+
// getMapping returns a mapping for the t type, using the tagName, mapFunc and
219+
// tagMapFunc to determine the canonical names of fields.
220+
func getMapping(t reflect.Type, tagName string, mapFunc, tagMapFunc func(string) string) fieldMap {
208221
queue := []typeQueue{}
209222
queue = append(queue, typeQueue{Deref(t), []int{}})
210223
m := fieldMap{}
@@ -223,6 +236,8 @@ func getMapping(t reflect.Type, tagName string, mapFunc func(string) string) fie
223236
} else {
224237
name = f.Name
225238
}
239+
} else if tagMapFunc != nil {
240+
name = tagMapFunc(name)
226241
}
227242

228243
// if the name is "-", disabled via a tag, skip it

reflectx/reflect_test.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,29 @@ func TestEmbedded(t *testing.T) {
6868
}
6969
}
7070

71+
func TestTagNameMapping(t *testing.T) {
72+
type Strategy struct {
73+
StrategyId string `protobuf:"bytes,1,opt,name=strategy_id" json:"strategy_id,omitempty"`
74+
StrategyName string
75+
}
76+
77+
m := NewMapperTagFunc("json", strings.ToUpper, func(value string) string {
78+
if strings.Contains(value, ",") {
79+
return strings.Split(value, ",")[0]
80+
} else {
81+
return value
82+
}
83+
})
84+
strategy := Strategy{"1", "Alpah"}
85+
mapping := m.TypeMap(reflect.TypeOf(strategy))
86+
87+
for _, key := range []string{"strategy_id", "STRATEGYNAME"} {
88+
if _, ok := mapping[key]; !ok {
89+
t.Errorf("Expecting to find key %s in mapping but did not.", key)
90+
}
91+
}
92+
}
93+
7194
func TestMapping(t *testing.T) {
7295
type Person struct {
7396
ID int

0 commit comments

Comments
 (0)