-
Notifications
You must be signed in to change notification settings - Fork 0
/
struct_cache.go
152 lines (124 loc) · 3.91 KB
/
struct_cache.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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package dm
import (
"fmt"
"reflect"
"sync"
)
var structs = newStructCache(true)
type structIndexInfo struct {
indexField *reflect.StructField // 主键索引对应的结构体字段
invertFields []reflect.StructField // 倒排索引对应的结构体字段
fieldName2Idx map[string]int // 字段名 -> 字段编号的映射
fieldName2InvertIdx map[string]int // 字段名 -> invertFields数组索引
}
// 获取主键索引的字段名
func (s *structIndexInfo) getIndexFieldName() string {
if s == nil {
return ""
}
if s.indexField == nil {
return ""
}
return s.indexField.Name
}
// 根据倒排字段名获取倒排字段的序号
func (s *structIndexInfo) getInvertIdxByName(fieldName string) int {
fieldIdx, has := s.fieldName2InvertIdx[fieldName]
if !has {
return -1
}
if fieldIdx >= len(s.invertFields) {
return -1
}
return fieldIdx
}
// 根据倒排字段名获取倒排字段结构
func (s *structIndexInfo) getInvertByName(fieldName string) (structField *reflect.StructField) {
fieldIdx := s.getInvertIdxByName(fieldName)
if fieldIdx == -1 {
return
}
return &(s.invertFields[fieldIdx])
}
// 根据倒排字段名获取倒排字段类型
func (s *structIndexInfo) getInvertTypeByName(fieldName string) (fieldType reflect.Type) {
fieldIdx := s.getInvertIdxByName(fieldName)
if fieldIdx == -1 {
return
}
return s.invertFields[fieldIdx].Type
}
// structCache 对结构体进行分析 -> 缓存结构体类型对应的字段分析结果
type structCache struct {
use bool
cache sync.Map
}
func newStructCache(use bool) *structCache {
return &structCache{
use: use,
}
}
func (m *structCache) getIndexInfo(typ reflect.Type) (*structIndexInfo, error) {
if typ.Kind() == reflect.Ptr {
typ = typ.Elem()
}
// 类型不是结构体
if typ.Kind() != reflect.Struct {
return nil, fmt.Errorf("input type:%s is non struct", typ.Name())
}
// 使用结构体解析缓存
if m.use {
if v, ok := m.cache.Load(typ); ok {
return v.(*structIndexInfo), nil
}
sii, err := m.analyseIndexInfo(typ)
if err != nil {
return nil, err
}
m.cache.Store(typ, sii)
return sii, nil
}
return m.analyseIndexInfo(typ)
}
// 分析结构体 -> 解析其中的主键索引 + 倒排索引
func (m *structCache) analyseIndexInfo(typ reflect.Type) (*structIndexInfo, error) {
count := typ.NumField()
info := &structIndexInfo{
invertFields: make([]reflect.StructField, 0, count),
fieldName2Idx: make(map[string]int, count),
fieldName2InvertIdx: make(map[string]int, count),
}
// invertFields的索引
invertIdx := 0
for i := 0; i < count; i++ {
field := typ.Field(i)
// 存储字段名 -> 字段编号的映射
if len(field.Index) > 0 {
info.fieldName2Idx[field.Name] = field.Index[0]
}
// 导出字段的PkgPath为空
// 过滤非导出字段
if field.PkgPath != "" {
continue
}
switch field.Tag.Get(TAG_NAME) {
case TAG_SKIP:
continue
case IDX_NAME:
// 主键索引字段重复
if info.indexField != nil {
return nil, fmt.Errorf("[analyseIndexInfo] input typ:[%s] index field duplication", typ.Name())
}
info.indexField = &field
case IVT_NAME:
info.invertFields = append(info.invertFields, field)
info.fieldName2InvertIdx[field.Name] = invertIdx
invertIdx++
}
}
// 类型没有主键索引字段
if info.indexField == nil {
return nil, fmt.Errorf("[analyseIndexInfo] input typ:[%s] has no index field", typ.Name())
}
return info, nil
}