/
map.go
95 lines (79 loc) · 2.03 KB
/
map.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
package goq
import (
"errors"
"reflect"
"github.com/ryym/goq/util"
)
// MapCollector collects rows into a map of struct.
//
// Example:
//
// map[int]JapanName{
// 6: JapanName{ Name: "Yamada", Kanji: "山田" },
// 43: JapanName{ Name: "Kato", Kanji: "加藤" },
// }
type MapCollector struct {
elemType reflect.Type
colToFld map[int]int
key Selectable
keyIdx int
keyStore reflect.Value
ptr interface{}
mp reflect.Value
row reflect.Value
}
func (cl *MapCollector) ImplListCollector() {}
func (cl *MapCollector) init(conf *initConf) (bool, error) {
if err := checkPtrKind(cl.ptr, reflect.Map); err != nil {
return false, err
}
cl.mp = reflect.ValueOf(cl.ptr).Elem()
cl.ptr = nil
cl.elemType = cl.mp.Type().Elem()
targets := map[string]int{}
for i := 0; i < cl.elemType.NumField(); i++ {
f := cl.elemType.Field(i)
if f.PkgPath == "" { // exported
targets[util.FldToCol(f.Name)] = i
}
}
cl.colToFld = map[int]int{}
key := cl.key.Selection()
cl.keyIdx = -1
for iC, name := range conf.ColNames {
if name == key.Alias || isKeyCol(&conf.Selects[iC], &key) {
cl.keyIdx = iC
}
}
if cl.keyIdx == -1 {
return false, errors.New("key not found")
}
for iC, name := range conf.ColNames {
if iF, ok := targets[name]; ok && conf.take(iC) {
cl.colToFld[iC] = iF
}
}
mapType := cl.mp.Type()
cl.mp.Set(reflect.MakeMap(reflect.MapOf(mapType.Key(), cl.elemType)))
return len(cl.colToFld) > 0, nil
}
func (cl *MapCollector) afterinit(conf *initConf) error {
if conf.canTake(cl.keyIdx) && !cl.keyStore.IsValid() {
return errors.New(mapKeyNotSelectedErrMsg)
}
return nil
}
func (cl *MapCollector) next(ptrs []interface{}) {
row := reflect.New(cl.elemType).Elem()
cl.row = row.Addr()
for c, f := range cl.colToFld {
ptrs[c] = row.Field(f).Addr().Interface()
}
if cl.keyStore.IsValid() {
ptrs[cl.keyIdx] = cl.keyStore.Addr().Interface()
}
}
func (cl *MapCollector) afterScan(ptrs []interface{}) {
key := reflect.ValueOf(ptrs[cl.keyIdx]).Elem()
cl.mp.SetMapIndex(key, cl.row.Elem())
}