Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(360)

Unified Diff: service/datastore/datastore.go

Issue 1259593005: Add 'user friendly' datastore API. (Closed) Base URL: https://github.com/luci/gae.git@master
Patch Set: Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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
+}

Powered by Google App Engine
This is Rietveld 408576698