Chromium Code Reviews| Index: service/datastore/datastore.go |
| diff --git a/service/datastore/datastore.go b/service/datastore/datastore.go |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..b4f1220b0f1311b5753a4c8b511b811415e1883a |
| --- /dev/null |
| +++ b/service/datastore/datastore.go |
| @@ -0,0 +1,199 @@ |
| +// 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) KeyForObj(src interface{}) Key { |
| + ret, err := d.KeyForObjErr(src) |
| + if err != nil { |
| + panic(err) |
| + } |
| + return ret |
| +} |
| + |
| +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 { |
| + return cb(k, gc) |
| + }) |
| + } |
| + |
| + mat := parseArg(reflect.TypeOf(proto)) |
| + if !mat.valid || mat.newElem == 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 { |
| + itm := mat.newElem() |
| + if innerErr = mat.setPM(itm, pm); innerErr != nil { |
| + return false |
| + } |
| + mat.setKey(itm, k) |
| + return cb(itm.Interface(), gc) |
| + }) |
| + if err == nil { |
| + err = innerErr |
| + } |
| + return err |
| +} |
| + |
| +func (d *datastoreImpl) GetAll(q Query, dst interface{}) error { |
| + v := reflect.ValueOf(dst) |
| + if v.Kind() != reflect.Ptr { |
| + return fmt.Errorf("invalid GetAll dst: must have a ptr-to-slice: %T", dst) |
| + } |
| + if !v.IsValid() || v.IsNil() { |
| + return errors.New("invalid GetAll dst: <nil>") |
| + } |
| + |
| + 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 := parseMultiArg(slice.Type()) |
| + 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 { |
| + slice.Set(reflect.Append(slice, mat.newElem())) |
| + itm := slice.Index(i) |
| + mat.setKey(itm, k) |
| + lme.Assign(i, mat.setPM(itm, pm)) |
| + i++ |
| + return true |
| + }) |
| + if err == nil { |
| + err = lme.Get() |
| + } |
| + return err |
| +} |
| + |
| +func isOkType(v reflect.Type) bool { |
| + if v.Implements(typeOfPropertyLoadSaver) { |
| + return true |
| + } |
| + if v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct { |
| + return true |
| + } |
| + return false |
| +} |
| + |
| +func (d *datastoreImpl) Get(dst interface{}) (err error) { |
| + if !isOkType(reflect.TypeOf(dst)) { |
| + return fmt.Errorf("invalid Get input type: %T", dst) |
| + } |
| + return errors.SingleError(d.GetMulti([]interface{}{dst})) |
| +} |
| + |
| +func (d *datastoreImpl) Put(src interface{}) (err error) { |
| + if !isOkType(reflect.TypeOf(src)) { |
|
Vadim Sh.
2015/08/03 21:25:12
so Put requires passing values by pointer? Does it
iannucci
2015/08/03 21:51:48
Yeah, it requires pass by pointer. It COULD make s
|
| + return fmt.Errorf("invalid Put input type: %T", src) |
| + } |
| + 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) { |
| + if key != keys[i] { |
| + 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 |
| +} |