Index: service/datastore/datastore.go |
diff --git a/service/datastore/datastore.go b/service/datastore/datastore.go |
index 375066276565ad044864079f33f66b109ebd82ec..3c328c966efcdb947d03c131ed839ce5620a0571 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,23 +66,35 @@ func (d *datastoreImpl) NewKeyToks(toks []KeyTok) *Key { |
// |
// obj is any object that Interface.Get is able to accept. |
// |
+// 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. |
+// |
// 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) { |
- populateKeyMGS(getMGS(obj), key) |
+func PopulateKey(obj interface{}, key *Key) bool { |
+ return populateKeyMGS(getMGS(obj), key) |
} |
-func populateKeyMGS(mgs MetaGetterSetter, key *Key) { |
- if !mgs.SetMeta("key", key) { |
- lst := key.LastTok() |
- if lst.StringID != "" { |
- mgs.SetMeta("id", lst.StringID) |
- } else { |
- mgs.SetMeta("id", lst.IntID) |
+func populateKeyMGS(mgs MetaGetterSetter, key *Key) bool { |
+ if mgs.SetMeta("key", key) { |
+ return true |
+ } |
+ |
+ lst := key.LastTok() |
+ if lst.StringID != "" { |
+ if !mgs.SetMeta("id", lst.StringID) { |
+ return false |
+ } |
+ } else { |
+ if !mgs.SetMeta("id", lst.IntID) { |
+ return false |
} |
- mgs.SetMeta("kind", lst.Kind) |
- mgs.SetMeta("parent", key.Parent()) |
} |
+ |
+ mgs.SetMeta("kind", lst.Kind) |
+ mgs.SetMeta("parent", key.Parent()) |
+ return true |
} |
func checkMultiSliceType(v interface{}) error { |
@@ -111,7 +133,7 @@ func runParseCallback(cbIface interface{}) (isKey, hasErr, hasCursorCB bool, mat |
if firstArg == typeOfKey { |
isKey = true |
} else { |
- mat = mustParseArg(firstArg) |
+ mat = mustParseArg(firstArg, false) |
if mat.newElem == nil { |
badSig() |
} |
@@ -132,6 +154,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, mmaWriteKeys) |
+ 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.Incomplete() |
+ } |
+ |
+ 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) |
@@ -260,7 +333,11 @@ func (d *datastoreImpl) GetAll(q *Query, dst interface{}) error { |
} |
func (d *datastoreImpl) Exists(ent ...interface{}) (*ExistsResult, error) { |
- mma, err := makeMetaMultiArg(ent, true) |
+ if len(ent) == 0 { |
+ return nil, nil |
+ } |
+ |
+ mma, err := makeMetaMultiArg(ent, mmaKeysOnly) |
if err != nil { |
panic(err) |
} |
@@ -269,15 +346,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 { |
@@ -300,7 +378,11 @@ func (d *datastoreImpl) ExistsMulti(keys []*Key) (BoolList, error) { |
} |
func (d *datastoreImpl) Get(dst ...interface{}) (err error) { |
- mma, err := makeMetaMultiArg(dst, false) |
+ if len(dst) == 0 { |
+ return nil |
+ } |
+ |
+ mma, err := makeMetaMultiArg(dst, mmaReadWrite) |
if err != nil { |
panic(err) |
} |
@@ -309,8 +391,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) |
@@ -321,8 +405,6 @@ func (d *datastoreImpl) Get(dst ...interface{}) (err error) { |
} |
return mat.setPM(slot, pm) |
}) |
- |
- i++ |
return nil |
})) |
@@ -345,7 +427,11 @@ func (d *datastoreImpl) GetMulti(dst interface{}) error { |
} |
func (d *datastoreImpl) Put(src ...interface{}) (err error) { |
- mma, err := makeMetaMultiArg(src, false) |
+ if len(src) == 0 { |
+ return nil |
+ } |
+ |
+ mma, err := makeMetaMultiArg(src, mmaReadWrite) |
if err != nil { |
panic(err) |
} |
@@ -354,6 +440,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 |
@@ -392,7 +481,11 @@ func (d *datastoreImpl) PutMulti(src interface{}) error { |
} |
func (d *datastoreImpl) Delete(ent ...interface{}) error { |
- mma, err := makeMetaMultiArg(ent, true) |
+ if len(ent) == 0 { |
+ return nil |
+ } |
+ |
+ mma, err := makeMetaMultiArg(ent, mmaKeysOnly) |
if err != nil { |
panic(err) |
} |
@@ -401,15 +494,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 |
})) |