Index: service/datastore/datastore.go |
diff --git a/service/datastore/datastore.go b/service/datastore/datastore.go |
index 752c99c55779e02a2f97cced14b351645f18a6af..5f9c64c8ce5c7d825bd91da3b03967fdec334ec5 100644 |
--- a/service/datastore/datastore.go |
+++ b/service/datastore/datastore.go |
@@ -37,7 +37,7 @@ func (d *datastoreImpl) KeyForObj(src interface{}) *Key { |
} |
func (d *datastoreImpl) KeyForObjErr(src interface{}) (*Key, error) { |
- return newKeyObjErr(d.aid, d.ns, src) |
+ return newKeyObjErr(d.aid, d.ns, getMGS(src)) |
} |
func (d *datastoreImpl) MakeKey(elems ...interface{}) *Key { |
@@ -72,7 +72,15 @@ func PopulateKey(obj interface{}, key *Key) { |
} |
} |
-func runParseCallback(cbIface interface{}) (isKey, hasErr, hasCursorCB bool, mat multiArgType) { |
+func checkMultiSliceType(v interface{}) error { |
+ if reflect.TypeOf(v).Kind() == reflect.Slice { |
+ return nil |
+ } |
+ return fmt.Errorf("argument must be a slice, not %T", v) |
+ |
+} |
+ |
+func runParseCallback(cbIface interface{}) (isKey, hasErr, hasCursorCB bool, mat *multiArgType) { |
badSig := func() { |
panic(fmt.Errorf( |
"cb does not match the required callback signature: `%T` != `func(TYPE, [CursorCB]) [error]`", |
@@ -100,7 +108,7 @@ func runParseCallback(cbIface interface{}) (isKey, hasErr, hasCursorCB bool, mat |
if firstArg == typeOfKey { |
isKey = true |
} else { |
- mat = parseArg(firstArg, false) |
+ mat = mustParseArg(firstArg) |
if mat.newElem == nil { |
badSig() |
} |
@@ -218,7 +226,7 @@ func (d *datastoreImpl) GetAll(q *Query, dst interface{}) error { |
} |
slice := v.Elem() |
- mat := parseMultiArg(slice.Type()) |
+ mat := mustParseMultiArg(slice.Type()) |
if mat.newElem == nil { |
panic(fmt.Errorf("invalid GetAll dst (non-concrete element type): %T", dst)) |
} |
@@ -248,131 +256,173 @@ func (d *datastoreImpl) GetAll(q *Query, dst interface{}) error { |
return err |
} |
-func isOkType(t reflect.Type) error { |
- if t == nil { |
- return errors.New("no type information") |
- } |
- if t.Implements(typeOfPropertyLoadSaver) { |
- return nil |
- } |
- if t == typeOfKey { |
- return errors.New("not user datatype") |
- } |
- if t.Kind() != reflect.Ptr { |
- return errors.New("not a pointer") |
+func (d *datastoreImpl) Exists(ent ...interface{}) (*ExistsResult, error) { |
+ mma, err := makeMetaMultiArg(ent, true) |
+ if err != nil { |
+ panic(err) |
} |
- if t.Elem().Kind() != reflect.Struct { |
- return errors.New("does not point to a struct") |
+ |
+ keys, _, err := mma.getKeysPMs(d.aid, d.ns, false) |
+ if err != nil { |
+ return nil, err |
} |
- return nil |
-} |
-func (d *datastoreImpl) ExistsMulti(keys []*Key) (BoolList, error) { |
- lme := errors.NewLazyMultiError(len(keys)) |
- ret := make(BoolList, len(keys)) |
i := 0 |
- err := filterStop(d.RawInterface.GetMulti(keys, nil, func(_ PropertyMap, err error) error { |
- if err == nil { |
- ret[i] = true |
- } else if err != ErrNoSuchEntity { |
- lme.Assign(i, err) |
- } |
+ var bt boolTracker |
+ it := mma.iterator(bt.init(mma)) |
+ err = filterStop(d.RawInterface.GetMulti(keys, nil, func(_ PropertyMap, err error) error { |
+ it.next(func(*multiArgType, reflect.Value) error { |
+ return err |
+ }) |
i++ |
return nil |
})) |
- if err != nil { |
- return ret, err |
- } |
- return ret, lme.Get() |
-} |
- |
-func (d *datastoreImpl) Exists(k *Key) (bool, error) { |
- ret, err := d.ExistsMulti([]*Key{k}) |
- return ret[0], errors.SingleError(err) |
-} |
+ if err == nil { |
+ err = bt.error() |
-func (d *datastoreImpl) Get(dst interface{}) (err error) { |
- if err := isOkType(reflect.TypeOf(dst)); err != nil { |
- panic(fmt.Errorf("invalid Get input type (%T): %s", dst, err)) |
+ if err != nil && len(ent) == 1 { |
+ // Single-argument Exists will return a single error. |
+ err = errors.SingleError(err) |
+ } |
} |
- return errors.SingleError(d.GetMulti([]interface{}{dst})) |
+ return bt.result(), err |
} |
-func (d *datastoreImpl) Put(src interface{}) (err error) { |
- if err := isOkType(reflect.TypeOf(src)); err != nil { |
- panic(fmt.Errorf("invalid Put input type (%T): %s", src, err)) |
+func (d *datastoreImpl) ExistsMulti(keys []*Key) (BoolList, error) { |
+ v, err := d.Exists(keys) |
+ if err != nil { |
+ return nil, err |
} |
- return errors.SingleError(d.PutMulti([]interface{}{src})) |
+ return v.List(0), nil |
} |
-func (d *datastoreImpl) Delete(key *Key) (err error) { |
- return errors.SingleError(d.DeleteMulti([]*Key{key})) |
-} |
- |
-func (d *datastoreImpl) GetMulti(dst interface{}) error { |
- slice := reflect.ValueOf(dst) |
- mat := parseMultiArg(slice.Type()) |
+func (d *datastoreImpl) Get(dst ...interface{}) (err error) { |
+ mma, err := makeMetaMultiArg(dst, false) |
+ if err != nil { |
+ panic(err) |
+ } |
- keys, pms, err := mat.GetKeysPMs(d.aid, d.ns, slice, true) |
+ keys, pms, err := mma.getKeysPMs(d.aid, d.ns, true) |
if err != nil { |
return err |
} |
- lme := errors.NewLazyMultiError(len(keys)) |
i := 0 |
+ var et errorTracker |
+ it := mma.iterator(et.init(mma)) |
meta := NewMultiMetaGetter(pms) |
err = filterStop(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)) |
- } |
+ it.next(func(mat *multiArgType, slot reflect.Value) error { |
+ if err != nil { |
+ return err |
+ } |
+ return mat.setPM(slot, pm) |
+ }) |
+ |
i++ |
return nil |
})) |
if err == nil { |
- err = lme.Get() |
+ err = et.error() |
+ |
+ if err != nil && len(dst) == 1 { |
+ // Single-argument Get will return a single error. |
+ err = errors.SingleError(err) |
+ } |
} |
return err |
} |
-func (d *datastoreImpl) PutMulti(src interface{}) error { |
- slice := reflect.ValueOf(src) |
- mat := parseMultiArg(slice.Type()) |
+func (d *datastoreImpl) GetMulti(dst interface{}) error { |
+ if err := checkMultiSliceType(dst); err != nil { |
+ panic(err) |
+ } |
+ return d.Get(dst) |
+} |
- keys, vals, err := mat.GetKeysPMs(d.aid, d.ns, slice, false) |
+func (d *datastoreImpl) Put(src ...interface{}) (err error) { |
+ mma, err := makeMetaMultiArg(src, false) |
+ if err != nil { |
+ panic(err) |
+ } |
+ |
+ keys, vals, err := mma.getKeysPMs(d.aid, d.ns, false) |
if err != nil { |
return err |
} |
- lme := errors.NewLazyMultiError(len(keys)) |
i := 0 |
+ var et errorTracker |
+ it := mma.iterator(et.init(mma)) |
err = filterStop(d.RawInterface.PutMulti(keys, vals, func(key *Key, err error) error { |
- if !lme.Assign(i, err) && key != keys[i] { |
- mat.setKey(slice.Index(i), key) |
- } |
+ it.next(func(mat *multiArgType, slot reflect.Value) error { |
+ if err != nil { |
+ return err |
+ } |
+ if key != keys[i] { |
+ mat.setKey(slot, key) |
+ } |
+ return nil |
+ }) |
+ |
i++ |
return nil |
})) |
if err == nil { |
- err = lme.Get() |
+ err = et.error() |
+ |
+ if err != nil && len(src) == 1 { |
+ // Single-argument Put will return a single error. |
+ err = errors.SingleError(err) |
+ } |
} |
return err |
} |
-func (d *datastoreImpl) DeleteMulti(keys []*Key) (err error) { |
- lme := errors.NewLazyMultiError(len(keys)) |
+func (d *datastoreImpl) PutMulti(src interface{}) error { |
+ if err := checkMultiSliceType(src); err != nil { |
+ panic(err) |
+ } |
+ return d.Put(src) |
+} |
+ |
+func (d *datastoreImpl) Delete(ent ...interface{}) error { |
+ mma, err := makeMetaMultiArg(ent, true) |
+ if err != nil { |
+ panic(err) |
+ } |
+ |
+ keys, _, err := mma.getKeysPMs(d.aid, d.ns, false) |
+ if err != nil { |
+ return err |
+ } |
+ |
i := 0 |
- extErr := filterStop(d.RawInterface.DeleteMulti(keys, func(internalErr error) error { |
- lme.Assign(i, internalErr) |
+ var et errorTracker |
+ it := mma.iterator(et.init(mma)) |
+ err = filterStop(d.RawInterface.DeleteMulti(keys, func(err error) error { |
+ it.next(func(*multiArgType, reflect.Value) error { |
+ return err |
+ }) |
i++ |
+ |
return nil |
})) |
- err = lme.Get() |
if err == nil { |
- err = extErr |
+ err = et.error() |
+ |
+ if err != nil && len(ent) == 1 { |
+ // Single-argument Delete will return a single error. |
+ err = errors.SingleError(err) |
+ } |
} |
- return |
+ return err |
+} |
+ |
+func (d *datastoreImpl) DeleteMulti(keys []*Key) error { |
+ return d.Delete(keys) |
} |
func (d *datastoreImpl) Raw() RawInterface { |