Chromium Code Reviews| Index: service/datastore/datastore.go |
| diff --git a/service/datastore/datastore.go b/service/datastore/datastore.go |
| index a6ae3e9e3509e2a9a0ab6bde7e90cb859d358699..e8ee88dc654655ad4341f1100550ff69d6e29f32 100644 |
| --- a/service/datastore/datastore.go |
| +++ b/service/datastore/datastore.go |
| @@ -44,68 +44,110 @@ func (d *datastoreImpl) NewKeyToks(toks []KeyTok) *Key { |
| return NewKeyToks(d.aid, d.ns, toks) |
| } |
| -func (d *datastoreImpl) Run(q *Query, cbIface interface{}) error { |
| +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
|
| + badSig := func() { |
| + panic(fmt.Errorf( |
| + "cb does not match the required callback signature: `%T` != `func(TYPE, [CursorCB]) [error]`", |
| + cbIface)) |
| + } |
| + |
| if cbIface == nil { |
| - return fmt.Errorf("cannot use nil callback when Running query") |
| + badSig() |
| } |
| // TODO(riannucci): Profile and determine if any of this is causing a real |
| // slowdown. Could potentially cache reflection stuff by cbTyp? |
| cbTyp := reflect.TypeOf(cbIface) |
| - badSig := false |
| - mat := multiArgType{} |
| - isKey := false |
| - |
| - if cbTyp.Kind() == reflect.Func && cbTyp.NumIn() == 2 && cbTyp.NumOut() == 1 { |
| - firstArg := cbTyp.In(0) |
| - if firstArg == typeOfKey { |
| - isKey = true |
| - } else { |
| - mat = parseArg(firstArg, false) |
| - badSig = mat.newElem == nil |
| - } |
| - } else { |
| - badSig = true |
| + if cbTyp.Kind() != reflect.Func { |
| + badSig() |
| } |
| - if badSig || cbTyp.Out(0) != typeOfBool || cbTyp.In(1) != typeOfCursorCB { |
| - panic(fmt.Errorf( |
| - "cb does not match the required callback signature: `%T` != `func(TYPE, CursorCB) bool`", |
| - cbIface)) |
| + numIn := cbTyp.NumIn() |
| + if numIn != 1 && numIn != 2 { |
| + badSig() |
| } |
| - if isKey { |
| - cb := cbIface.(func(*Key, CursorCB) bool) |
| - fq, err := q.KeysOnly(true).Finalize() |
| - if err != nil { |
| - return err |
| + firstArg := cbTyp.In(0) |
| + if firstArg == typeOfKey { |
| + isKey = true |
| + } else { |
| + mat = parseArg(firstArg, false) |
| + if mat.newElem == nil { |
| + badSig() |
| } |
| - return d.RawInterface.Run(fq, func(k *Key, _ PropertyMap, gc CursorCB) bool { |
| - return cb(k, gc) |
| - }) |
| } |
| + hasCursorCB = numIn == 2 |
| + if hasCursorCB && cbTyp.In(1) != typeOfCursorCB { |
| + badSig() |
| + } |
| + |
| + if cbTyp.NumOut() > 1 { |
| + badSig() |
| + } else if cbTyp.NumOut() == 1 && cbTyp.Out(0) != typeOfError { |
| + badSig() |
| + } |
| + hasErr = cbTyp.NumOut() == 1 |
| + |
| + return |
| +} |
| + |
| +func (d *datastoreImpl) Run(q *Query, cbIface interface{}) error { |
| + isKey, hasErr, hasCursorCB, mat := runParseCallback(cbIface) |
| + |
| + if isKey { |
| + q = q.KeysOnly(true) |
| + } |
| fq, err := q.Finalize() |
| if err != nil { |
| return err |
| } |
| cbVal := reflect.ValueOf(cbIface) |
| + 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!
|
| + if hasErr && hasCursorCB { |
| + cb = func(v reflect.Value, cb CursorCB) error { |
| + err := cbVal.Call([]reflect.Value{v, reflect.ValueOf(cb)})[0].Interface() |
| + if err != nil { |
| + return err.(error) |
| + } |
| + return nil |
| + } |
| + } else if hasErr && !hasCursorCB { |
| + cb = func(v reflect.Value, _ CursorCB) error { |
| + err := cbVal.Call([]reflect.Value{v})[0].Interface() |
| + if err != nil { |
| + return err.(error) |
| + } |
| + return nil |
| + } |
| + } else if !hasErr && hasCursorCB { |
| + cb = func(v reflect.Value, cb CursorCB) error { |
| + cbVal.Call([]reflect.Value{v, reflect.ValueOf(cb)}) |
| + return nil |
| + } |
| + } else if !hasErr && !hasCursorCB { |
| + cb = func(v reflect.Value, _ CursorCB) error { |
| + cbVal.Call([]reflect.Value{v}) |
| + return nil |
| + } |
| + } |
| + |
| + if isKey { |
| + return d.RawInterface.Run(fq, func(k *Key, _ PropertyMap, gc CursorCB) error { |
| + return cb(reflect.ValueOf(k), gc) |
| + }) |
| + } |
| - innerErr := error(nil) |
| - err = d.RawInterface.Run(fq, func(k *Key, pm PropertyMap, gc CursorCB) bool { |
| + return d.RawInterface.Run(fq, func(k *Key, pm PropertyMap, gc CursorCB) error { |
| itm := mat.newElem() |
| - if innerErr = mat.setPM(itm, pm); innerErr != nil { |
| - return false |
| + if err := mat.setPM(itm, pm); err != nil { |
| + return err |
| } |
| mat.setKey(itm, k) |
| - return cbVal.Call([]reflect.Value{itm, reflect.ValueOf(gc)})[0].Bool() |
| + return cb(itm, gc) |
| }) |
| - if err == nil { |
| - err = innerErr |
| - } |
| - return err |
| } |
| func (d *datastoreImpl) Count(q *Query) (int64, error) { |
| @@ -131,9 +173,9 @@ func (d *datastoreImpl) GetAll(q *Query, dst interface{}) error { |
| return err |
| } |
| - return d.RawInterface.Run(fq, func(k *Key, _ PropertyMap, _ CursorCB) bool { |
| + return d.RawInterface.Run(fq, func(k *Key, _ PropertyMap, _ CursorCB) error { |
| *keys = append(*keys, k) |
| - return true |
| + return nil |
| }) |
| } |
| fq, err := q.Finalize() |
| @@ -149,7 +191,7 @@ func (d *datastoreImpl) GetAll(q *Query, dst interface{}) error { |
| errs := map[int]error{} |
| i := 0 |
| - err = d.RawInterface.Run(fq, func(k *Key, pm PropertyMap, _ CursorCB) bool { |
| + err = d.RawInterface.Run(fq, func(k *Key, pm PropertyMap, _ CursorCB) error { |
| slice.Set(reflect.Append(slice, mat.newElem())) |
| itm := slice.Index(i) |
| mat.setKey(itm, k) |
| @@ -158,7 +200,7 @@ func (d *datastoreImpl) GetAll(q *Query, dst interface{}) error { |
| errs[i] = err |
| } |
| i++ |
| - return true |
| + return nil |
| }) |
| if err == nil { |
| if len(errs) > 0 { |
| @@ -186,13 +228,14 @@ func (d *datastoreImpl) ExistsMulti(keys []*Key) ([]bool, error) { |
| lme := errors.NewLazyMultiError(len(keys)) |
| ret := make([]bool, len(keys)) |
| i := 0 |
| - err := d.RawInterface.GetMulti(keys, nil, func(_ PropertyMap, err error) { |
| + err := d.RawInterface.GetMulti(keys, nil, func(_ PropertyMap, err error) error { |
| if err == nil { |
| ret[i] = true |
| } else if err != ErrNoSuchEntity { |
| lme.Assign(i, err) |
| } |
| i++ |
| + return nil |
| }) |
| if err != nil { |
| return ret, err |
| @@ -235,11 +278,12 @@ func (d *datastoreImpl) GetMulti(dst interface{}) error { |
| lme := errors.NewLazyMultiError(len(keys)) |
| i := 0 |
| meta := NewMultiMetaGetter(pms) |
| - err = d.RawInterface.GetMulti(keys, meta, func(pm PropertyMap, err error) { |
| + err = d.RawInterface.GetMulti(keys, meta, func(pm PropertyMap, err error) error { |
| if !lme.Assign(i, err) { |
| lme.Assign(i, mat.setPM(slice.Index(i), pm)) |
| } |
| i++ |
| + return nil |
| }) |
| if err == nil { |
| @@ -259,12 +303,13 @@ func (d *datastoreImpl) PutMulti(src interface{}) error { |
| lme := errors.NewLazyMultiError(len(keys)) |
| i := 0 |
| - err = d.RawInterface.PutMulti(keys, vals, func(key *Key, err error) { |
| + err = d.RawInterface.PutMulti(keys, vals, func(key *Key, err error) error { |
| if key != keys[i] { |
| mat.setKey(slice.Index(i), key) |
| } |
| lme.Assign(i, err) |
| i++ |
| + return nil |
| }) |
| if err == nil { |
| @@ -276,9 +321,10 @@ func (d *datastoreImpl) PutMulti(src interface{}) error { |
| func (d *datastoreImpl) DeleteMulti(keys []*Key) (err error) { |
| lme := errors.NewLazyMultiError(len(keys)) |
| i := 0 |
| - extErr := d.RawInterface.DeleteMulti(keys, func(internalErr error) { |
| + extErr := d.RawInterface.DeleteMulti(keys, func(internalErr error) error { |
| lme.Assign(i, internalErr) |
| i++ |
| + return nil |
| }) |
| err = lme.Get() |
| if err == nil { |