Index: service/datastore/datastore.go |
diff --git a/service/datastore/datastore.go b/service/datastore/datastore.go |
index 4bb31d4a5de096fdd2e2c9c8edd5ec8df608a14f..ebcab095d33489c0a3c1bf2337eb24bc922486b0 100644 |
--- a/service/datastore/datastore.go |
+++ b/service/datastore/datastore.go |
@@ -27,26 +27,50 @@ func (d *datastoreImpl) KeyForObjErr(src interface{}) (Key, error) { |
return newKeyObjErr(d.NewKey, src) |
} |
-func (d *datastoreImpl) Run(q Query, proto interface{}, cb RunCB) error { |
- if _, ok := proto.(*Key); ok { |
- return d.RawInterface.Run(q.KeysOnly(), func(k Key, _ PropertyMap, gc func() (Cursor, error)) bool { |
+func (d *datastoreImpl) Run(q Query, cbIface interface{}) error { |
+ // TODO(riannucci): Profile and determine if any of this is causing a real |
+ // slowdown. Could potentially cache reflection stuff by cbType? |
+ 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) |
+ badSig = !mat.valid || mat.newElem == nil |
+ } |
+ } else { |
+ badSig = true |
+ } |
+ |
+ 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)) |
+ } |
+ |
+ if isKey { |
+ cb := cbIface.(func(Key, CursorCB) bool) |
+ return d.RawInterface.Run(q.KeysOnly(), func(k Key, _ PropertyMap, gc CursorCB) bool { |
return cb(k, gc) |
}) |
} |
- mat := parseArg(reflect.TypeOf(proto)) |
- if !mat.valid || mat.newElem == nil { |
- return fmt.Errorf("invalid Run proto type: %T", proto) |
- } |
+ cbVal := reflect.ValueOf(cbIface) |
innerErr := error(nil) |
- err := d.RawInterface.Run(q, func(k Key, pm PropertyMap, gc func() (Cursor, error)) bool { |
+ err := d.RawInterface.Run(q, func(k Key, pm PropertyMap, gc CursorCB) bool { |
itm := mat.newElem() |
if innerErr = mat.setPM(itm, pm); innerErr != nil { |
return false |
} |
mat.setKey(itm, k) |
- return cb(itm.Interface(), gc) |
+ return cbVal.Call([]reflect.Value{itm, reflect.ValueOf(gc)})[0].Bool() |
}) |
if err == nil { |
err = innerErr |
@@ -64,7 +88,7 @@ func (d *datastoreImpl) GetAll(q Query, dst interface{}) error { |
} |
if keys, ok := dst.(*[]Key); ok { |
- return d.RawInterface.Run(q.KeysOnly(), func(k Key, _ PropertyMap, _ func() (Cursor, error)) bool { |
+ return d.RawInterface.Run(q.KeysOnly(), func(k Key, _ PropertyMap, _ CursorCB) bool { |
*keys = append(*keys, k) |
return true |
}) |
@@ -78,7 +102,7 @@ func (d *datastoreImpl) GetAll(q Query, dst interface{}) error { |
lme := errors.LazyMultiError{Size: slice.Len()} |
i := 0 |
- err := d.RawInterface.Run(q, func(k Key, pm PropertyMap, _ func() (Cursor, error)) bool { |
+ err := d.RawInterface.Run(q, func(k Key, pm PropertyMap, _ CursorCB) bool { |
slice.Set(reflect.Append(slice, mat.newElem())) |
itm := slice.Index(i) |
mat.setKey(itm, k) |