Index: service/datastore/datastore.go |
diff --git a/service/datastore/datastore.go b/service/datastore/datastore.go |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b2169038ac9e85dcea5248d716cc7e593855eb9d |
--- /dev/null |
+++ b/service/datastore/datastore.go |
@@ -0,0 +1,200 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+package datastore |
+ |
+import ( |
+ "fmt" |
+ "reflect" |
+ |
+ "github.com/luci/luci-go/common/errors" |
+) |
+ |
+type datastoreImpl struct{ RawInterface } |
+ |
+var _ Interface = (*datastoreImpl)(nil) |
+ |
+func (d *datastoreImpl) NewKeyObj(src interface{}) Key { |
+ ret, err := d.NewKeyObjErr(src) |
+ if err != nil { |
+ panic(err) |
+ } |
+ return ret |
+} |
+ |
+func (d *datastoreImpl) NewKeyObjErr(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 { |
+ return cb(k, gc) |
+ }) |
+ } |
+ |
+ t := reflect.TypeOf(proto) |
+ if t.Kind() != reflect.Ptr { |
+ return fmt.Errorf("invalid Run proto type: %T", proto) |
+ } |
+ e := t.Elem() |
+ var mkPLS func() (interface{}, PropertyLoadSaver) |
+ if t.Implements(typeOfPropertyLoadSaver) { |
+ mkPLS = func() (interface{}, PropertyLoadSaver) { |
+ iface := reflect.New(e).Interface() |
+ return iface, iface.(PropertyLoadSaver) |
+ } |
+ } else if e.Kind() == reflect.Struct { |
+ cdc := getCodec(e) |
+ mkPLS = func() (interface{}, PropertyLoadSaver) { |
+ ptr := reflect.New(e) |
+ return ptr.Interface(), &structPLS{ptr.Elem(), cdc} |
+ } |
+ } |
+ if mkPLS == nil { |
+ return fmt.Errorf("invalid Run proto type: %T", proto) |
+ } |
+ |
+ innerErr := error(nil) |
+ err := d.RawInterface.Run(q, func(k Key, pm PropertyMap, gc func() (Cursor, error)) bool { |
+ iface, pls := mkPLS() |
+ if innerErr = pls.Load(pm); innerErr != nil { |
+ return false |
+ } |
+ setKey(pls, k) |
+ return cb(iface, gc) |
+ }) |
+ if err == nil { |
+ err = innerErr |
Vadim Sh.
2015/07/29 16:21:43
are you sure you want to return error(nil) instead
iannucci
2015/08/03 03:56:31
pretty sure it's the same thing. `innerErr := err
|
+ } |
+ return err |
+} |
+ |
+func (d *datastoreImpl) GetAll(q Query, dst interface{}) error { |
+ v := reflect.ValueOf(dst) |
+ if v.IsNil() { |
+ return errors.New("invalid GetAll dst: <nil>") |
+ } |
+ |
+ t := v.Type() |
+ if t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Slice { |
+ return fmt.Errorf("invalid GetAll dst: must have a ptr-to-slice %T", dst) |
+ } |
+ |
+ if keys, ok := dst.(*[]Key); ok { |
+ return d.RawInterface.Run(q.KeysOnly(), func(k Key, _ PropertyMap, _ func() (Cursor, error)) bool { |
+ *keys = append(*keys, k) |
+ return true |
+ }) |
+ } |
+ |
+ slice := v.Elem() |
+ mat := parseArg(t.Elem()) |
+ if !mat.valid || mat.newElem == nil { |
+ return fmt.Errorf("invalid GetAll input type: %T", dst) |
+ } |
+ |
+ lme := errors.LazyMultiError{Size: slice.Len()} |
+ i := 0 |
+ err := d.RawInterface.Run(q, func(k Key, pm PropertyMap, _ func() (Cursor, error)) bool { |
+ itm := mat.newElem() |
+ slice.Set(reflect.Append(slice, itm)) |
+ mat.setKey(itm, k) |
+ lme.Assign(i, mat.setPM(itm, pm)) |
+ i++ |
+ return true |
+ }) |
+ if err == nil { |
+ err = lme.Get() |
+ } |
+ return err |
+} |
+ |
+func (d *datastoreImpl) Get(dst interface{}) (err error) { |
+ return errors.SingleError(d.GetMulti([]interface{}{dst})) |
+} |
+ |
+func (d *datastoreImpl) Put(src interface{}) (err error) { |
+ return errors.SingleError(d.PutMulti([]interface{}{src})) |
+} |
+ |
+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()) |
+ if !mat.valid { |
+ return fmt.Errorf("invalid GetMulti input type: %T", dst) |
+ } |
+ |
+ keys, err := mat.GetKeys(d.NewKey, slice) |
+ if err != nil { |
+ return err |
+ } |
+ |
+ lme := errors.LazyMultiError{Size: len(keys)} |
+ i := 0 |
+ err = d.RawInterface.GetMulti(keys, func(pm PropertyMap, err error) { |
+ if !lme.Assign(i, err) { |
+ lme.Assign(i, mat.setPM(slice.Index(i), pm)) |
+ } |
+ i++ |
+ }) |
+ |
+ if err == nil { |
+ err = lme.Get() |
+ } |
+ return err |
+} |
+ |
+func (d *datastoreImpl) PutMulti(src interface{}) error { |
+ slice := reflect.ValueOf(src) |
+ mat := parseMultiArg(slice.Type()) |
+ if !mat.valid { |
+ return fmt.Errorf("invalid PutMulti input type: %T", src) |
+ } |
+ |
+ keys, err := mat.GetKeys(d.NewKey, slice) |
+ if err != nil { |
+ return err |
+ } |
+ |
+ vals, err := mat.GetPMs(slice) |
+ if err != nil { |
+ return err |
+ } |
+ |
+ lme := errors.LazyMultiError{Size: len(keys)} |
+ i := 0 |
+ err = d.RawInterface.PutMulti(keys, vals, func(key Key, err error) { |
+ mat.setKey(slice.Index(i), key) |
+ lme.Assign(i, err) |
+ i++ |
+ }) |
+ |
+ if err == nil { |
+ err = lme.Get() |
+ } |
+ return err |
+} |
+ |
+func (d *datastoreImpl) DeleteMulti(keys []Key) (err error) { |
+ lme := errors.LazyMultiError{Size: len(keys)} |
+ i := 0 |
+ extErr := d.RawInterface.DeleteMulti(keys, func(internalErr error) { |
+ lme.Assign(i, internalErr) |
+ i++ |
+ }) |
+ err = lme.Get() |
+ if err == nil { |
+ err = extErr |
+ } |
+ return |
+} |
+ |
+func (d *datastoreImpl) Raw() RawInterface { |
+ return d.RawInterface |
+} |