| 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)) {
|
| + 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
|
| +}
|
|
|