-
Notifications
You must be signed in to change notification settings - Fork 0
/
fetch_nexus.go
163 lines (150 loc) · 3.46 KB
/
fetch_nexus.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
153
154
155
156
157
158
159
160
161
162
163
package model
import (
"errors"
"reflect"
)
type NWhere struct {
Op string
Value interface{}
}
type NexusValues interface {
DataOf(m interface{}, rel Nexus) interface{}
}
type DefaultNexusValues struct {
data map[interface{}]interface{}
}
func NewNexusValues(data map[interface{}]interface{}) NexusValues {
return &DefaultNexusValues{data}
}
func (nve *DefaultNexusValues) DataOf(m interface{}, rel Nexus) interface{} {
result := make(map[interface{}]interface{})
for k, item := range nve.data {
eq := true
for field, val := range rel {
switch val.(type) {
case string:
a, _ := m.(Mapable).Mapper().colValue(m, val.(string))
b, _ := item.(Mapable).Mapper().colValue(item, field)
if a != b {
eq = false
break
}
}
}
if eq {
result[k] = item
}
}
return result
}
// a nexus result struct to hold the query result of a nexus
type nexusResult struct {
name string
m interface{}
n Nexus
t int
data NexusValues
}
type repoHandler func(m interface{}) (NexusValues, error)
type fornexusHandler func(field, op string, value interface{})
// With tell repo that find nexus defined by model
// if nexus not defined, With will ignore
func (repo *Repo) WithCustom(name string, handler repoHandler) *Repo {
t := t_bad
var ok bool
var m interface{}
var n map[string]interface{}
if m, n, ok = repo.model.(NexusOne).HasOne(name); ok {
t = t_one
} else if m, n, ok = repo.model.(NexusMany).HasMany(name); ok {
t = t_many
}
repo.withs = append(repo.withs, with{
name: name,
m: m,
n: n,
t: t,
handler: handler,
})
return repo
}
func (repo *Repo) With(name string) *Repo {
return repo.WithCustom(name, func(m interface{}) (data NexusValues, err error) {
if d, e := m.(Model).Repo().FetchKey(m.(Model).PK()); e != nil {
err = e
} else {
data = &DefaultNexusValues{d}
}
return
})
}
// nexusValues fetch all nexus result according the repo fetch result
func (repo *Repo) nexusValues(models []interface{}) (result []nexusResult, err error) {
// find each nexus's query where and model
if len(models) == 0 {
return
}
for _, w := range repo.withs {
if w.t == t_bad {
err = &Error{ERR_NEXUS_UNDEFINED, errors.New("nexus " + w.name + " not exists")}
return
}
nm := New(w.m)
r := nm.(Model).Repo()
for af, bf := range w.n {
switch bf.(type) {
case NWhere:
r.Where(af, bf.(NWhere).Op, bf.(NWhere).Value)
case string:
vals := []interface{}{}
for _, m := range models {
if val, e := repo.model.(Mapable).Mapper().colValue(m, bf.(string)); e != nil {
err = e
return
} else {
vals = append(vals, val)
}
}
if len(vals) != 0 {
r.WhereIn(af, vals)
}
}
}
if data, e := w.handler(nm); e != nil {
err = e
return
} else {
result = append(result, nexusResult{w.name, nm, w.n, w.t, data})
}
}
return
}
//
// bind nexus result to each fetched model
//
func (repo *Repo) bindNexus(m interface{}, nr []nexusResult) {
for _, n := range nr {
nm := n.data.DataOf(m, n.n)
if n.t == t_many {
m.(NexusMany).SetMany(n.name, nm)
continue
}
ty := reflect.TypeOf(nm)
switch ty.Kind() {
case reflect.Map:
val := nm.(map[interface{}]interface{})
for _, item := range val {
m.(NexusOne).SetOne(n.name, item)
break
}
case reflect.Slice:
val := nm.([]interface{})
for _, item := range val {
m.(NexusOne).SetOne(n.name, item)
break
}
default:
m.(NexusOne).SetOne(n.name, nm)
}
}
}