Index: service/datastore/datastore.go |
diff --git a/service/datastore/datastore.go b/service/datastore/datastore.go |
index 5f9c64c8ce5c7d825bd91da3b03967fdec334ec5..e244c69f536f2ff0a741e1daada888744e88d39a 100644 |
--- a/service/datastore/datastore.go |
+++ b/service/datastore/datastore.go |
@@ -48,6 +48,16 @@ func (d *datastoreImpl) NewKey(kind, stringID string, intID int64, parent *Key) |
return NewKey(d.aid, d.ns, kind, stringID, intID, parent) |
} |
+func (d *datastoreImpl) NewIncompleteKeys(count int, kind string, parent *Key) (keys []*Key) { |
+ if count > 0 { |
+ keys = make([]*Key, count) |
+ for i := range keys { |
+ keys[i] = d.NewKey(kind, "", 0, parent) |
+ } |
+ } |
+ return |
+} |
+ |
func (d *datastoreImpl) NewKeyToks(toks []KeyTok) *Key { |
return NewKeyToks(d.aid, d.ns, toks) |
} |
@@ -56,20 +66,28 @@ func (d *datastoreImpl) NewKeyToks(toks []KeyTok) *Key { |
// |
// obj is any object that Interface.Get is able to accept. |
// |
-// This method will panic if obj is an invalid datastore model. If the key could |
-// not be applied to the object, nothing will happen. |
-func PopulateKey(obj interface{}, key *Key) { |
+// Upon successful application, this method will return true. If the key could |
+// not be applied to the object, this method will return false. It will panic if |
+// obj is an invalid datastore model. |
+func PopulateKey(obj interface{}, key *Key) bool { |
pls := getMGS(obj) |
- if !pls.SetMeta("key", key) { |
- lst := key.LastTok() |
- if lst.StringID != "" { |
- pls.SetMeta("id", lst.StringID) |
- } else { |
- pls.SetMeta("id", lst.IntID) |
+ if pls.SetMeta("key", key) { |
+ return true |
+ } |
+ |
+ lst := key.LastTok() |
+ if lst.StringID != "" { |
+ if !pls.SetMeta("id", lst.StringID) { |
+ return false |
+ } |
+ } else { |
+ if !pls.SetMeta("id", lst.IntID) { |
+ return false |
} |
- pls.SetMeta("kind", lst.Kind) |
- pls.SetMeta("parent", key.Parent()) |
} |
+ pls.SetMeta("kind", lst.Kind) |
+ pls.SetMeta("parent", key.Parent()) |
+ return true |
} |
func checkMultiSliceType(v interface{}) error { |
@@ -129,6 +147,57 @@ func runParseCallback(cbIface interface{}) (isKey, hasErr, hasCursorCB bool, mat |
return |
} |
+func (d *datastoreImpl) AllocateIDs(ent ...interface{}) error { |
+ if len(ent) == 0 { |
+ return nil |
+ } |
+ |
+ mma, err := makeMetaMultiArg(ent, true) |
+ if err != nil { |
+ panic(err) |
+ } |
+ |
+ keys, _, err := mma.getKeysPMs(d.aid, d.ns, false) |
+ if err != nil { |
+ return err |
+ } |
+ if len(keys) == 0 { |
+ return nil |
+ } |
+ |
+ // Convert each key to be partial valid, assigning an integer ID of 0. Confirm |
+ // that each object can be populated with such a key. |
+ for i, key := range keys { |
+ keys[i] = key.Partial() |
+ } |
+ |
+ var et errorTracker |
+ it := mma.iterator(et.init(mma)) |
+ err = filterStop(d.RawInterface.AllocateIDs(keys, func(key *Key, err error) error { |
+ it.next(func(mat *multiArgType, v reflect.Value) error { |
+ if err != nil { |
+ return err |
+ } |
+ |
+ if !mat.setKey(v, key) { |
+ return ErrInvalidKey |
+ } |
+ return nil |
+ }) |
+ |
+ return nil |
+ })) |
+ if err == nil { |
+ err = et.error() |
+ |
+ if err != nil && len(ent) == 1 { |
+ // Single-argument Exists will return a single error. |
+ err = errors.SingleError(err) |
+ } |
+ } |
+ return err |
+} |
+ |
func (d *datastoreImpl) Run(q *Query, cbIface interface{}) error { |
isKey, hasErr, hasCursorCB, mat := runParseCallback(cbIface) |
@@ -257,6 +326,10 @@ func (d *datastoreImpl) GetAll(q *Query, dst interface{}) error { |
} |
func (d *datastoreImpl) Exists(ent ...interface{}) (*ExistsResult, error) { |
+ if len(ent) == 0 { |
+ return nil, nil |
+ } |
+ |
mma, err := makeMetaMultiArg(ent, true) |
if err != nil { |
panic(err) |
@@ -266,15 +339,16 @@ func (d *datastoreImpl) Exists(ent ...interface{}) (*ExistsResult, error) { |
if err != nil { |
return nil, err |
} |
+ if len(keys) == 0 { |
+ return nil, nil |
+ } |
- i := 0 |
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 { |
@@ -297,6 +371,10 @@ func (d *datastoreImpl) ExistsMulti(keys []*Key) (BoolList, error) { |
} |
func (d *datastoreImpl) Get(dst ...interface{}) (err error) { |
+ if len(dst) == 0 { |
+ return nil |
+ } |
+ |
mma, err := makeMetaMultiArg(dst, false) |
if err != nil { |
panic(err) |
@@ -306,8 +384,10 @@ func (d *datastoreImpl) Get(dst ...interface{}) (err error) { |
if err != nil { |
return err |
} |
+ if len(keys) == 0 { |
+ return nil |
+ } |
- i := 0 |
var et errorTracker |
it := mma.iterator(et.init(mma)) |
meta := NewMultiMetaGetter(pms) |
@@ -318,8 +398,6 @@ func (d *datastoreImpl) Get(dst ...interface{}) (err error) { |
} |
return mat.setPM(slot, pm) |
}) |
- |
- i++ |
return nil |
})) |
@@ -342,6 +420,10 @@ func (d *datastoreImpl) GetMulti(dst interface{}) error { |
} |
func (d *datastoreImpl) Put(src ...interface{}) (err error) { |
+ if len(src) == 0 { |
+ return nil |
+ } |
+ |
mma, err := makeMetaMultiArg(src, false) |
if err != nil { |
panic(err) |
@@ -351,6 +433,9 @@ func (d *datastoreImpl) Put(src ...interface{}) (err error) { |
if err != nil { |
return err |
} |
+ if len(keys) == 0 { |
+ return nil |
+ } |
i := 0 |
var et errorTracker |
@@ -389,6 +474,10 @@ func (d *datastoreImpl) PutMulti(src interface{}) error { |
} |
func (d *datastoreImpl) Delete(ent ...interface{}) error { |
+ if len(ent) == 0 { |
+ return nil |
+ } |
+ |
mma, err := makeMetaMultiArg(ent, true) |
if err != nil { |
panic(err) |
@@ -398,15 +487,16 @@ func (d *datastoreImpl) Delete(ent ...interface{}) error { |
if err != nil { |
return err |
} |
+ if len(keys) == 0 { |
+ return nil |
+ } |
- i := 0 |
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 |
})) |