/
typeinfo.go
86 lines (73 loc) · 1.33 KB
/
typeinfo.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 pg
import (
"reflect"
"strings"
"sync"
)
var (
structs = newStructCache()
)
func isUpper(c byte) bool {
return c >= 'A' && c <= 'Z'
}
func isLower(c byte) bool {
return !isUpper(c)
}
func toLower(c byte) byte {
return c + 32
}
func formatColumnName(s string) string {
b := []byte(s)
r := make([]byte, 0, len(b))
for i := 0; i < len(b); i++ {
c := b[i]
if isUpper(c) {
if i-1 > 0 && i+1 < len(b) && (isLower(b[i-1]) || isLower(b[i+1])) {
r = append(r, '_', toLower(c))
} else {
r = append(r, toLower(c))
}
} else {
r = append(r, c)
}
}
return string(r)
}
type structCache struct {
l sync.RWMutex
m map[reflect.Type]map[string][]int
}
func newStructCache() *structCache {
return &structCache{
m: make(map[reflect.Type]map[string][]int),
}
}
func (c *structCache) Indexes(typ reflect.Type) map[string][]int {
c.l.RLock()
indxs, ok := c.m[typ]
c.l.RUnlock()
if ok {
return indxs
}
numField := typ.NumField()
indxs = make(map[string][]int, numField)
for i := 0; i < numField; i++ {
f := typ.Field(i)
if f.PkgPath != "" {
continue
}
tokens := strings.Split(f.Tag.Get("pg"), ",")
name := tokens[0]
if name == "-" {
continue
}
if name == "" {
name = formatColumnName(f.Name)
}
indxs[name] = f.Index
}
c.l.Lock()
c.m[typ] = indxs
c.l.Unlock()
return indxs
}