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