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

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: 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
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) {
dnj 2015/12/14 22:35:03 My overall concern here is that now the only allus
iannucci 2015/12/14 23:03:09 Discussed offline. I'm not a fan of having a metho
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
dnj 2015/12/14 22:35:03 Either: (a) Organize this more hierarchically: if
iannucci 2015/12/14 23:03:09 switch! done!
109 if hasErr && hasCursorCB {
110 cb = func(v reflect.Value, cb CursorCB) error {
111 err := cbVal.Call([]reflect.Value{v, reflect.ValueOf(cb) })[0].Interface()
112 if err != nil {
113 return err.(error)
114 }
115 return nil
116 }
117 } else if hasErr && !hasCursorCB {
118 cb = func(v reflect.Value, _ CursorCB) error {
119 err := cbVal.Call([]reflect.Value{v})[0].Interface()
120 if err != nil {
121 return err.(error)
122 }
123 return nil
124 }
125 } else if !hasErr && hasCursorCB {
126 cb = func(v reflect.Value, cb CursorCB) error {
127 cbVal.Call([]reflect.Value{v, reflect.ValueOf(cb)})
128 return nil
129 }
130 } else if !hasErr && !hasCursorCB {
131 cb = func(v reflect.Value, _ CursorCB) error {
132 cbVal.Call([]reflect.Value{v})
133 return nil
134 }
135 }
95 136
96 » innerErr := error(nil) 137 » if isKey {
97 » err = d.RawInterface.Run(fq, func(k *Key, pm PropertyMap, gc CursorCB) b ool { 138 » » return d.RawInterface.Run(fq, func(k *Key, _ PropertyMap, gc Cur sorCB) error {
139 » » » return cb(reflect.ValueOf(k), gc)
140 » » })
141 » }
142
143 » return d.RawInterface.Run(fq, func(k *Key, pm PropertyMap, gc CursorCB) error {
98 itm := mat.newElem() 144 itm := mat.newElem()
99 » » if innerErr = mat.setPM(itm, pm); innerErr != nil { 145 » » if err := mat.setPM(itm, pm); err != nil {
100 » » » return false 146 » » » return err
101 } 147 }
102 mat.setKey(itm, k) 148 mat.setKey(itm, k)
103 » » return cbVal.Call([]reflect.Value{itm, reflect.ValueOf(gc)})[0]. Bool() 149 » » return cb(itm, gc)
104 }) 150 })
105 if err == nil {
106 err = innerErr
107 }
108 return err
109 } 151 }
110 152
111 func (d *datastoreImpl) Count(q *Query) (int64, error) { 153 func (d *datastoreImpl) Count(q *Query) (int64, error) {
112 fq, err := q.Finalize() 154 fq, err := q.Finalize()
113 if err != nil { 155 if err != nil {
114 return 0, err 156 return 0, err
115 } 157 }
116 return d.RawInterface.Count(fq) 158 return d.RawInterface.Count(fq)
117 } 159 }
118 160
119 func (d *datastoreImpl) GetAll(q *Query, dst interface{}) error { 161 func (d *datastoreImpl) GetAll(q *Query, dst interface{}) error {
120 v := reflect.ValueOf(dst) 162 v := reflect.ValueOf(dst)
121 if v.Kind() != reflect.Ptr { 163 if v.Kind() != reflect.Ptr {
122 return fmt.Errorf("invalid GetAll dst: must have a ptr-to-slice: %T", dst) 164 return fmt.Errorf("invalid GetAll dst: must have a ptr-to-slice: %T", dst)
123 } 165 }
124 if !v.IsValid() || v.IsNil() { 166 if !v.IsValid() || v.IsNil() {
125 return errors.New("invalid GetAll dst: <nil>") 167 return errors.New("invalid GetAll dst: <nil>")
126 } 168 }
127 169
128 if keys, ok := dst.(*[]*Key); ok { 170 if keys, ok := dst.(*[]*Key); ok {
129 fq, err := q.KeysOnly(true).Finalize() 171 fq, err := q.KeysOnly(true).Finalize()
130 if err != nil { 172 if err != nil {
131 return err 173 return err
132 } 174 }
133 175
134 » » return d.RawInterface.Run(fq, func(k *Key, _ PropertyMap, _ Curs orCB) bool { 176 » » return d.RawInterface.Run(fq, func(k *Key, _ PropertyMap, _ Curs orCB) error {
135 *keys = append(*keys, k) 177 *keys = append(*keys, k)
136 » » » return true 178 » » » return nil
137 }) 179 })
138 } 180 }
139 fq, err := q.Finalize() 181 fq, err := q.Finalize()
140 if err != nil { 182 if err != nil {
141 return err 183 return err
142 } 184 }
143 185
144 slice := v.Elem() 186 slice := v.Elem()
145 mat := parseMultiArg(slice.Type()) 187 mat := parseMultiArg(slice.Type())
146 if mat.newElem == nil { 188 if mat.newElem == nil {
147 return fmt.Errorf("invalid GetAll input type: %T", dst) 189 return fmt.Errorf("invalid GetAll input type: %T", dst)
148 } 190 }
149 191
150 errs := map[int]error{} 192 errs := map[int]error{}
151 i := 0 193 i := 0
152 » err = d.RawInterface.Run(fq, func(k *Key, pm PropertyMap, _ CursorCB) bo ol { 194 » err = d.RawInterface.Run(fq, func(k *Key, pm PropertyMap, _ CursorCB) er ror {
153 slice.Set(reflect.Append(slice, mat.newElem())) 195 slice.Set(reflect.Append(slice, mat.newElem()))
154 itm := slice.Index(i) 196 itm := slice.Index(i)
155 mat.setKey(itm, k) 197 mat.setKey(itm, k)
156 err := mat.setPM(itm, pm) 198 err := mat.setPM(itm, pm)
157 if err != nil { 199 if err != nil {
158 errs[i] = err 200 errs[i] = err
159 } 201 }
160 i++ 202 i++
161 » » return true 203 » » return nil
162 }) 204 })
163 if err == nil { 205 if err == nil {
164 if len(errs) > 0 { 206 if len(errs) > 0 {
165 me := make(errors.MultiError, slice.Len()) 207 me := make(errors.MultiError, slice.Len())
166 for i, e := range errs { 208 for i, e := range errs {
167 me[i] = e 209 me[i] = e
168 } 210 }
169 err = me 211 err = me
170 } 212 }
171 } 213 }
172 return err 214 return err
173 } 215 }
174 216
175 func isOkType(v reflect.Type) bool { 217 func isOkType(v reflect.Type) bool {
176 if v.Implements(typeOfPropertyLoadSaver) { 218 if v.Implements(typeOfPropertyLoadSaver) {
177 return true 219 return true
178 } 220 }
179 if v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct { 221 if v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct {
180 return true 222 return true
181 } 223 }
182 return false 224 return false
183 } 225 }
184 226
185 func (d *datastoreImpl) ExistsMulti(keys []*Key) ([]bool, error) { 227 func (d *datastoreImpl) ExistsMulti(keys []*Key) ([]bool, error) {
186 lme := errors.NewLazyMultiError(len(keys)) 228 lme := errors.NewLazyMultiError(len(keys))
187 ret := make([]bool, len(keys)) 229 ret := make([]bool, len(keys))
188 i := 0 230 i := 0
189 » err := d.RawInterface.GetMulti(keys, nil, func(_ PropertyMap, err error) { 231 » err := d.RawInterface.GetMulti(keys, nil, func(_ PropertyMap, err error) error {
190 if err == nil { 232 if err == nil {
191 ret[i] = true 233 ret[i] = true
192 } else if err != ErrNoSuchEntity { 234 } else if err != ErrNoSuchEntity {
193 lme.Assign(i, err) 235 lme.Assign(i, err)
194 } 236 }
195 i++ 237 i++
238 return nil
196 }) 239 })
197 if err != nil { 240 if err != nil {
198 return ret, err 241 return ret, err
199 } 242 }
200 return ret, lme.Get() 243 return ret, lme.Get()
201 } 244 }
202 245
203 func (d *datastoreImpl) Exists(k *Key) (bool, error) { 246 func (d *datastoreImpl) Exists(k *Key) (bool, error) {
204 ret, err := d.ExistsMulti([]*Key{k}) 247 ret, err := d.ExistsMulti([]*Key{k})
205 return ret[0], errors.SingleError(err) 248 return ret[0], errors.SingleError(err)
(...skipping 22 matching lines...) Expand all
228 mat := parseMultiArg(slice.Type()) 271 mat := parseMultiArg(slice.Type())
229 272
230 keys, pms, err := mat.GetKeysPMs(d.aid, d.ns, slice, true) 273 keys, pms, err := mat.GetKeysPMs(d.aid, d.ns, slice, true)
231 if err != nil { 274 if err != nil {
232 return err 275 return err
233 } 276 }
234 277
235 lme := errors.NewLazyMultiError(len(keys)) 278 lme := errors.NewLazyMultiError(len(keys))
236 i := 0 279 i := 0
237 meta := NewMultiMetaGetter(pms) 280 meta := NewMultiMetaGetter(pms)
238 » err = d.RawInterface.GetMulti(keys, meta, func(pm PropertyMap, err error ) { 281 » err = d.RawInterface.GetMulti(keys, meta, func(pm PropertyMap, err error ) error {
239 if !lme.Assign(i, err) { 282 if !lme.Assign(i, err) {
240 lme.Assign(i, mat.setPM(slice.Index(i), pm)) 283 lme.Assign(i, mat.setPM(slice.Index(i), pm))
241 } 284 }
242 i++ 285 i++
286 return nil
243 }) 287 })
244 288
245 if err == nil { 289 if err == nil {
246 err = lme.Get() 290 err = lme.Get()
247 } 291 }
248 return err 292 return err
249 } 293 }
250 294
251 func (d *datastoreImpl) PutMulti(src interface{}) error { 295 func (d *datastoreImpl) PutMulti(src interface{}) error {
252 slice := reflect.ValueOf(src) 296 slice := reflect.ValueOf(src)
253 mat := parseMultiArg(slice.Type()) 297 mat := parseMultiArg(slice.Type())
254 298
255 keys, vals, err := mat.GetKeysPMs(d.aid, d.ns, slice, false) 299 keys, vals, err := mat.GetKeysPMs(d.aid, d.ns, slice, false)
256 if err != nil { 300 if err != nil {
257 return err 301 return err
258 } 302 }
259 303
260 lme := errors.NewLazyMultiError(len(keys)) 304 lme := errors.NewLazyMultiError(len(keys))
261 i := 0 305 i := 0
262 » err = d.RawInterface.PutMulti(keys, vals, func(key *Key, err error) { 306 » err = d.RawInterface.PutMulti(keys, vals, func(key *Key, err error) erro r {
263 if key != keys[i] { 307 if key != keys[i] {
264 mat.setKey(slice.Index(i), key) 308 mat.setKey(slice.Index(i), key)
265 } 309 }
266 lme.Assign(i, err) 310 lme.Assign(i, err)
267 i++ 311 i++
312 return nil
268 }) 313 })
269 314
270 if err == nil { 315 if err == nil {
271 err = lme.Get() 316 err = lme.Get()
272 } 317 }
273 return err 318 return err
274 } 319 }
275 320
276 func (d *datastoreImpl) DeleteMulti(keys []*Key) (err error) { 321 func (d *datastoreImpl) DeleteMulti(keys []*Key) (err error) {
277 lme := errors.NewLazyMultiError(len(keys)) 322 lme := errors.NewLazyMultiError(len(keys))
278 i := 0 323 i := 0
279 » extErr := d.RawInterface.DeleteMulti(keys, func(internalErr error) { 324 » extErr := d.RawInterface.DeleteMulti(keys, func(internalErr error) error {
280 lme.Assign(i, internalErr) 325 lme.Assign(i, internalErr)
281 i++ 326 i++
327 return nil
282 }) 328 })
283 err = lme.Get() 329 err = lme.Get()
284 if err == nil { 330 if err == nil {
285 err = extErr 331 err = extErr
286 } 332 }
287 return 333 return
288 } 334 }
289 335
290 func (d *datastoreImpl) Raw() RawInterface { 336 func (d *datastoreImpl) Raw() RawInterface {
291 return d.RawInterface 337 return d.RawInterface
292 } 338 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698