Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(426)

Side by Side Diff: service/datastore/datastore.go

Issue 1521823003: Clean up callback interfaces. (Closed) Base URL: https://github.com/luci/gae.git@extra
Patch Set: fixins Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « service/datastore/checkfilter_test.go ('k') | service/datastore/datastore_test.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package datastore 5 package datastore
6 6
7 import ( 7 import (
8 "fmt" 8 "fmt"
9 "reflect" 9 "reflect"
10 10
(...skipping 26 matching lines...) Expand all
37 } 37 }
38 38
39 func (d *datastoreImpl) NewKey(kind, stringID string, intID int64, parent *Key) *Key { 39 func (d *datastoreImpl) NewKey(kind, stringID string, intID int64, parent *Key) *Key {
40 return NewKey(d.aid, d.ns, kind, stringID, intID, parent) 40 return NewKey(d.aid, d.ns, kind, stringID, intID, parent)
41 } 41 }
42 42
43 func (d *datastoreImpl) NewKeyToks(toks []KeyTok) *Key { 43 func (d *datastoreImpl) NewKeyToks(toks []KeyTok) *Key {
44 return NewKeyToks(d.aid, d.ns, toks) 44 return NewKeyToks(d.aid, d.ns, toks)
45 } 45 }
46 46
47 func (d *datastoreImpl) Run(q *Query, cbIface interface{}) error { 47 func runParseCallback(cbIface interface{}) (isKey, hasErr, hasCursorCB bool, mat multiArgType) {
48 » badSig := func() {
49 » » panic(fmt.Errorf(
50 » » » "cb does not match the required callback signature: `%T` != `func(TYPE, [CursorCB]) [error]`",
51 » » » cbIface))
52 » }
53
48 if cbIface == nil { 54 if cbIface == nil {
49 » » return fmt.Errorf("cannot use nil callback when Running query") 55 » » badSig()
50 } 56 }
51 57
52 // TODO(riannucci): Profile and determine if any of this is causing a re al 58 // TODO(riannucci): Profile and determine if any of this is causing a re al
53 // slowdown. Could potentially cache reflection stuff by cbTyp? 59 // slowdown. Could potentially cache reflection stuff by cbTyp?
54 cbTyp := reflect.TypeOf(cbIface) 60 cbTyp := reflect.TypeOf(cbIface)
55 61
56 » badSig := false 62 » if cbTyp.Kind() != reflect.Func {
57 » mat := multiArgType{} 63 » » badSig()
58 » isKey := false
59
60 » if cbTyp.Kind() == reflect.Func && cbTyp.NumIn() == 2 && cbTyp.NumOut() == 1 {
61 » » firstArg := cbTyp.In(0)
62 » » if firstArg == typeOfKey {
63 » » » isKey = true
64 » » } else {
65 » » » mat = parseArg(firstArg, false)
66 » » » badSig = mat.newElem == nil
67 » » }
68 » } else {
69 » » badSig = true
70 } 64 }
71 65
72 » if badSig || cbTyp.Out(0) != typeOfBool || cbTyp.In(1) != typeOfCursorCB { 66 » numIn := cbTyp.NumIn()
73 » » panic(fmt.Errorf( 67 » if numIn != 1 && numIn != 2 {
74 » » » "cb does not match the required callback signature: `%T` != `func(TYPE, CursorCB) bool`", 68 » » badSig()
75 » » » cbIface))
76 } 69 }
77 70
78 » if isKey { 71 » firstArg := cbTyp.In(0)
79 » » cb := cbIface.(func(*Key, CursorCB) bool) 72 » if firstArg == typeOfKey {
80 » » fq, err := q.KeysOnly(true).Finalize() 73 » » isKey = true
81 » » if err != nil { 74 » } else {
82 » » » return err 75 » » mat = parseArg(firstArg, false)
76 » » if mat.newElem == nil {
77 » » » badSig()
83 } 78 }
84 return d.RawInterface.Run(fq, func(k *Key, _ PropertyMap, gc Cur sorCB) bool {
85 return cb(k, gc)
86 })
87 } 79 }
88 80
81 hasCursorCB = numIn == 2
82 if hasCursorCB && cbTyp.In(1) != typeOfCursorCB {
83 badSig()
84 }
85
86 if cbTyp.NumOut() > 1 {
87 badSig()
88 } else if cbTyp.NumOut() == 1 && cbTyp.Out(0) != typeOfError {
89 badSig()
90 }
91 hasErr = cbTyp.NumOut() == 1
92
93 return
94 }
95
96 func (d *datastoreImpl) Run(q *Query, cbIface interface{}) error {
97 isKey, hasErr, hasCursorCB, mat := runParseCallback(cbIface)
98
99 if isKey {
100 q = q.KeysOnly(true)
101 }
89 fq, err := q.Finalize() 102 fq, err := q.Finalize()
90 if err != nil { 103 if err != nil {
91 return err 104 return err
92 } 105 }
93 106
94 cbVal := reflect.ValueOf(cbIface) 107 cbVal := reflect.ValueOf(cbIface)
108 var cb func(reflect.Value, CursorCB) error
109 switch {
110 case hasErr && hasCursorCB:
111 cb = func(v reflect.Value, cb CursorCB) error {
112 err := cbVal.Call([]reflect.Value{v, reflect.ValueOf(cb) })[0].Interface()
113 if err != nil {
114 return err.(error)
115 }
116 return nil
117 }
95 118
96 » innerErr := error(nil) 119 » case hasErr && !hasCursorCB:
97 » err = d.RawInterface.Run(fq, func(k *Key, pm PropertyMap, gc CursorCB) b ool { 120 » » cb = func(v reflect.Value, _ CursorCB) error {
121 » » » err := cbVal.Call([]reflect.Value{v})[0].Interface()
122 » » » if err != nil {
123 » » » » return err.(error)
124 » » » }
125 » » » return nil
126 » » }
127
128 » case !hasErr && hasCursorCB:
129 » » cb = func(v reflect.Value, cb CursorCB) error {
130 » » » cbVal.Call([]reflect.Value{v, reflect.ValueOf(cb)})
131 » » » return nil
132 » » }
133
134 » case !hasErr && !hasCursorCB:
135 » » cb = func(v reflect.Value, _ CursorCB) error {
136 » » » cbVal.Call([]reflect.Value{v})
137 » » » return nil
138 » » }
139 » }
140
141 » if isKey {
142 » » return d.RawInterface.Run(fq, func(k *Key, _ PropertyMap, gc Cur sorCB) error {
143 » » » return cb(reflect.ValueOf(k), gc)
144 » » })
145 » }
146
147 » return d.RawInterface.Run(fq, func(k *Key, pm PropertyMap, gc CursorCB) error {
98 itm := mat.newElem() 148 itm := mat.newElem()
99 » » if innerErr = mat.setPM(itm, pm); innerErr != nil { 149 » » if err := mat.setPM(itm, pm); err != nil {
100 » » » return false 150 » » » return err
101 } 151 }
102 mat.setKey(itm, k) 152 mat.setKey(itm, k)
103 » » return cbVal.Call([]reflect.Value{itm, reflect.ValueOf(gc)})[0]. Bool() 153 » » return cb(itm, gc)
104 }) 154 })
105 if err == nil {
106 err = innerErr
107 }
108 return err
109 } 155 }
110 156
111 func (d *datastoreImpl) Count(q *Query) (int64, error) { 157 func (d *datastoreImpl) Count(q *Query) (int64, error) {
112 fq, err := q.Finalize() 158 fq, err := q.Finalize()
113 if err != nil { 159 if err != nil {
114 return 0, err 160 return 0, err
115 } 161 }
116 return d.RawInterface.Count(fq) 162 return d.RawInterface.Count(fq)
117 } 163 }
118 164
119 func (d *datastoreImpl) GetAll(q *Query, dst interface{}) error { 165 func (d *datastoreImpl) GetAll(q *Query, dst interface{}) error {
120 v := reflect.ValueOf(dst) 166 v := reflect.ValueOf(dst)
121 if v.Kind() != reflect.Ptr { 167 if v.Kind() != reflect.Ptr {
122 return fmt.Errorf("invalid GetAll dst: must have a ptr-to-slice: %T", dst) 168 return fmt.Errorf("invalid GetAll dst: must have a ptr-to-slice: %T", dst)
123 } 169 }
124 if !v.IsValid() || v.IsNil() { 170 if !v.IsValid() || v.IsNil() {
125 return errors.New("invalid GetAll dst: <nil>") 171 return errors.New("invalid GetAll dst: <nil>")
126 } 172 }
127 173
128 if keys, ok := dst.(*[]*Key); ok { 174 if keys, ok := dst.(*[]*Key); ok {
129 fq, err := q.KeysOnly(true).Finalize() 175 fq, err := q.KeysOnly(true).Finalize()
130 if err != nil { 176 if err != nil {
131 return err 177 return err
132 } 178 }
133 179
134 » » return d.RawInterface.Run(fq, func(k *Key, _ PropertyMap, _ Curs orCB) bool { 180 » » return d.RawInterface.Run(fq, func(k *Key, _ PropertyMap, _ Curs orCB) error {
135 *keys = append(*keys, k) 181 *keys = append(*keys, k)
136 » » » return true 182 » » » return nil
137 }) 183 })
138 } 184 }
139 fq, err := q.Finalize() 185 fq, err := q.Finalize()
140 if err != nil { 186 if err != nil {
141 return err 187 return err
142 } 188 }
143 189
144 slice := v.Elem() 190 slice := v.Elem()
145 mat := parseMultiArg(slice.Type()) 191 mat := parseMultiArg(slice.Type())
146 if mat.newElem == nil { 192 if mat.newElem == nil {
147 return fmt.Errorf("invalid GetAll input type: %T", dst) 193 return fmt.Errorf("invalid GetAll input type: %T", dst)
148 } 194 }
149 195
150 errs := map[int]error{} 196 errs := map[int]error{}
151 i := 0 197 i := 0
152 » err = d.RawInterface.Run(fq, func(k *Key, pm PropertyMap, _ CursorCB) bo ol { 198 » err = d.RawInterface.Run(fq, func(k *Key, pm PropertyMap, _ CursorCB) er ror {
153 slice.Set(reflect.Append(slice, mat.newElem())) 199 slice.Set(reflect.Append(slice, mat.newElem()))
154 itm := slice.Index(i) 200 itm := slice.Index(i)
155 mat.setKey(itm, k) 201 mat.setKey(itm, k)
156 err := mat.setPM(itm, pm) 202 err := mat.setPM(itm, pm)
157 if err != nil { 203 if err != nil {
158 errs[i] = err 204 errs[i] = err
159 } 205 }
160 i++ 206 i++
161 » » return true 207 » » return nil
162 }) 208 })
163 if err == nil { 209 if err == nil {
164 if len(errs) > 0 { 210 if len(errs) > 0 {
165 me := make(errors.MultiError, slice.Len()) 211 me := make(errors.MultiError, slice.Len())
166 for i, e := range errs { 212 for i, e := range errs {
167 me[i] = e 213 me[i] = e
168 } 214 }
169 err = me 215 err = me
170 } 216 }
171 } 217 }
172 return err 218 return err
173 } 219 }
174 220
175 func isOkType(v reflect.Type) bool { 221 func isOkType(v reflect.Type) bool {
176 if v.Implements(typeOfPropertyLoadSaver) { 222 if v.Implements(typeOfPropertyLoadSaver) {
177 return true 223 return true
178 } 224 }
179 if v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct { 225 if v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct {
180 return true 226 return true
181 } 227 }
182 return false 228 return false
183 } 229 }
184 230
185 func (d *datastoreImpl) ExistsMulti(keys []*Key) ([]bool, error) { 231 func (d *datastoreImpl) ExistsMulti(keys []*Key) ([]bool, error) {
186 lme := errors.NewLazyMultiError(len(keys)) 232 lme := errors.NewLazyMultiError(len(keys))
187 ret := make([]bool, len(keys)) 233 ret := make([]bool, len(keys))
188 i := 0 234 i := 0
189 » err := d.RawInterface.GetMulti(keys, nil, func(_ PropertyMap, err error) { 235 » err := d.RawInterface.GetMulti(keys, nil, func(_ PropertyMap, err error) error {
190 if err == nil { 236 if err == nil {
191 ret[i] = true 237 ret[i] = true
192 } else if err != ErrNoSuchEntity { 238 } else if err != ErrNoSuchEntity {
193 lme.Assign(i, err) 239 lme.Assign(i, err)
194 } 240 }
195 i++ 241 i++
242 return nil
196 }) 243 })
197 if err != nil { 244 if err != nil {
198 return ret, err 245 return ret, err
199 } 246 }
200 return ret, lme.Get() 247 return ret, lme.Get()
201 } 248 }
202 249
203 func (d *datastoreImpl) Exists(k *Key) (bool, error) { 250 func (d *datastoreImpl) Exists(k *Key) (bool, error) {
204 ret, err := d.ExistsMulti([]*Key{k}) 251 ret, err := d.ExistsMulti([]*Key{k})
205 return ret[0], errors.SingleError(err) 252 return ret[0], errors.SingleError(err)
(...skipping 22 matching lines...) Expand all
228 mat := parseMultiArg(slice.Type()) 275 mat := parseMultiArg(slice.Type())
229 276
230 keys, pms, err := mat.GetKeysPMs(d.aid, d.ns, slice, true) 277 keys, pms, err := mat.GetKeysPMs(d.aid, d.ns, slice, true)
231 if err != nil { 278 if err != nil {
232 return err 279 return err
233 } 280 }
234 281
235 lme := errors.NewLazyMultiError(len(keys)) 282 lme := errors.NewLazyMultiError(len(keys))
236 i := 0 283 i := 0
237 meta := NewMultiMetaGetter(pms) 284 meta := NewMultiMetaGetter(pms)
238 » err = d.RawInterface.GetMulti(keys, meta, func(pm PropertyMap, err error ) { 285 » err = d.RawInterface.GetMulti(keys, meta, func(pm PropertyMap, err error ) error {
239 if !lme.Assign(i, err) { 286 if !lme.Assign(i, err) {
240 lme.Assign(i, mat.setPM(slice.Index(i), pm)) 287 lme.Assign(i, mat.setPM(slice.Index(i), pm))
241 } 288 }
242 i++ 289 i++
290 return nil
243 }) 291 })
244 292
245 if err == nil { 293 if err == nil {
246 err = lme.Get() 294 err = lme.Get()
247 } 295 }
248 return err 296 return err
249 } 297 }
250 298
251 func (d *datastoreImpl) PutMulti(src interface{}) error { 299 func (d *datastoreImpl) PutMulti(src interface{}) error {
252 slice := reflect.ValueOf(src) 300 slice := reflect.ValueOf(src)
253 mat := parseMultiArg(slice.Type()) 301 mat := parseMultiArg(slice.Type())
254 302
255 keys, vals, err := mat.GetKeysPMs(d.aid, d.ns, slice, false) 303 keys, vals, err := mat.GetKeysPMs(d.aid, d.ns, slice, false)
256 if err != nil { 304 if err != nil {
257 return err 305 return err
258 } 306 }
259 307
260 lme := errors.NewLazyMultiError(len(keys)) 308 lme := errors.NewLazyMultiError(len(keys))
261 i := 0 309 i := 0
262 » err = d.RawInterface.PutMulti(keys, vals, func(key *Key, err error) { 310 » err = d.RawInterface.PutMulti(keys, vals, func(key *Key, err error) erro r {
263 if key != keys[i] { 311 if key != keys[i] {
264 mat.setKey(slice.Index(i), key) 312 mat.setKey(slice.Index(i), key)
265 } 313 }
266 lme.Assign(i, err) 314 lme.Assign(i, err)
267 i++ 315 i++
316 return nil
268 }) 317 })
269 318
270 if err == nil { 319 if err == nil {
271 err = lme.Get() 320 err = lme.Get()
272 } 321 }
273 return err 322 return err
274 } 323 }
275 324
276 func (d *datastoreImpl) DeleteMulti(keys []*Key) (err error) { 325 func (d *datastoreImpl) DeleteMulti(keys []*Key) (err error) {
277 lme := errors.NewLazyMultiError(len(keys)) 326 lme := errors.NewLazyMultiError(len(keys))
278 i := 0 327 i := 0
279 » extErr := d.RawInterface.DeleteMulti(keys, func(internalErr error) { 328 » extErr := d.RawInterface.DeleteMulti(keys, func(internalErr error) error {
280 lme.Assign(i, internalErr) 329 lme.Assign(i, internalErr)
281 i++ 330 i++
331 return nil
282 }) 332 })
283 err = lme.Get() 333 err = lme.Get()
284 if err == nil { 334 if err == nil {
285 err = extErr 335 err = extErr
286 } 336 }
287 return 337 return
288 } 338 }
289 339
290 func (d *datastoreImpl) Raw() RawInterface { 340 func (d *datastoreImpl) Raw() RawInterface {
291 return d.RawInterface 341 return d.RawInterface
292 } 342 }
OLDNEW
« no previous file with comments | « service/datastore/checkfilter_test.go ('k') | service/datastore/datastore_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698