| Index: service/datastore/interface.go | 
| diff --git a/service/datastore/interface.go b/service/datastore/interface.go | 
| index 718b9c15e0aa2060509a3018b27d71ae6c57a73a..d8dc3dbb6e55bf4d5c5c2ceeae538b47ef408b0d 100644 | 
| --- a/service/datastore/interface.go | 
| +++ b/service/datastore/interface.go | 
| @@ -5,313 +5,690 @@ | 
| package datastore | 
|  | 
| import ( | 
| +	"fmt" | 
| +	"reflect" | 
| + | 
| +	"github.com/luci/luci-go/common/errors" | 
| "golang.org/x/net/context" | 
| ) | 
|  | 
| -// Interface is the 'user-friendly' interface to access the current filtered | 
| -// datastore service implementation. | 
| -// | 
| -// Note that in exchange for userfriendliness, this interface ends up doing | 
| -// a lot of reflection. | 
| -// | 
| -// Methods taking 'interface{}' objects describe what a valid type for that | 
| -// interface are in the comments. | 
| -// | 
| -// Struct objects passed in will be converted to PropertyLoadSaver interfaces | 
| -// using this package's GetPLS function. | 
| -type Interface interface { | 
| -	// AllocateIDs allows you to allocate IDs from the datastore without putting | 
| -	// any data. | 
| -	// | 
| -	// A partial valid key will be constructed from each entity's kind and parent, | 
| -	// if present. An allocation will then be performed against the datastore for | 
| -	// each key, and the partial key will be populated with a unique integer ID. | 
| -	// The resulting keys will be applied to their objects using PopulateKey. If | 
| -	// successful, any existing ID will be destroyed. | 
| -	// | 
| -	// If the object is supplied that cannot accept an integer key, this method | 
| -	// will panic. | 
| -	// | 
| -	// ent must be one of: | 
| -	//	- *S where S is a struct | 
| -	//	- *P where *P is a concrete type implementing PropertyLoadSaver | 
| -	//	- []S or []*S where S is a struct | 
| -	//	- []P or []*P where *P is a concrete type implementing PropertyLoadSaver | 
| -	//	- []I where i is some interface type. Each element of the slice must | 
| -	//	  be non-nil, and its underlying type must be either *S or *P. | 
| -	//	- []*Key, to populate a slice of partial-valid keys. | 
| -	// | 
| -	// If an error is encountered, the returned error value will depend on the | 
| -	// input arguments. If one argument is supplied, the result will be the | 
| -	// encountered error type. If multiple arguments are supplied, the result will | 
| -	// be a MultiError whose error index corresponds to the argument in which the | 
| -	// error was encountered. | 
| -	// | 
| -	// If an ent argument is a slice, its error type will be a MultiError. Note | 
| -	// that in the scenario where multiple slices are provided, this will return a | 
| -	// MultiError containing a nested MultiError for each slice argument. | 
| -	AllocateIDs(ent ...interface{}) error | 
| - | 
| -	// KeyForObj extracts a key from src. | 
| -	// | 
| -	// It is the same as KeyForObjErr, except that if KeyForObjErr would have | 
| -	// returned an error, this method panics. It's safe to use if you know that | 
| -	// src statically meets the metadata constraints described by KeyForObjErr. | 
| -	KeyForObj(src interface{}) *Key | 
| - | 
| -	// MakeKey is a convenience method for manufacturing a *Key. It should only be | 
| -	// used when elems... is known statically (e.g. in the code) to be correct. | 
| -	// | 
| -	// elems is pairs of (string, string|int|int32|int64) pairs, which correspond | 
| -	// to Kind/id pairs. Example: | 
| -	//   dstore.MakeKey("Parent", 1, "Child", "id") | 
| -	// | 
| -	// Would create the key: | 
| -	//   <current appID>:<current Namespace>:/Parent,1/Child,id | 
| -	// | 
| -	// If elems is not parsable (e.g. wrong length, wrong types, etc.) this method | 
| -	// will panic. | 
| -	MakeKey(elems ...interface{}) *Key | 
| - | 
| -	// NewKey constructs a new key in the current appID/Namespace, using the | 
| -	// specified parameters. | 
| -	NewKey(kind, stringID string, intID int64, parent *Key) *Key | 
| - | 
| -	// NewIncompleteKeys allocates count incomplete keys sharing the same kind and | 
| -	// parent. It is useful as input to AllocateIDs. | 
| -	NewIncompleteKeys(count int, kind string, parent *Key) []*Key | 
| - | 
| -	// NewKeyToks constructs a new key in the current appID/Namespace, using the | 
| -	// specified key tokens. | 
| -	NewKeyToks([]KeyTok) *Key | 
| - | 
| -	// KeyForObjErr extracts a key from src. | 
| -	// | 
| -	// src must be one of: | 
| -	//   - *S, where S is a struct | 
| -	//   - a PropertyLoadSaver | 
| -	// | 
| -	// It is expected that the struct exposes the following metadata (as retrieved | 
| -	// by MetaGetter.GetMeta): | 
| -	//   - "key" (type: Key) - The full datastore key to use. Must not be nil. | 
| -	//     OR | 
| -	//   - "id" (type: int64 or string) - The id of the Key to create | 
| -	//   - "kind" (optional, type: string) - The kind of the Key to create. If | 
| -	//     blank or not present, KeyForObjErr will extract the name of the src | 
| -	//     object's type. | 
| -	//   - "parent" (optional, type: Key) - The parent key to use. | 
| -	// | 
| -	// By default, the metadata will be extracted from the struct and its tagged | 
| -	// properties. However, if the struct implements MetaGetterSetter it is | 
| -	// wholly responsible for exporting the required fields. A struct that | 
| -	// implements GetMeta to make some minor tweaks can evoke the defualt behavior | 
| -	// by using GetPLS(s).GetMeta. | 
| -	// | 
| -	// If a required metadata item is missing or of the wrong type, then this will | 
| -	// return an error. | 
| -	KeyForObjErr(src interface{}) (*Key, error) | 
| - | 
| -	// RunInTransaction runs f inside of a transaction. See the appengine SDK's | 
| -	// documentation for full details on the behavior of transactions in the | 
| -	// datastore. | 
| -	// | 
| -	// Note that the behavior of transactions may change depending on what filters | 
| -	// have been installed. It's possible that we'll end up implementing things | 
| -	// like nested/buffered transactions as filters. | 
| -	RunInTransaction(f func(c context.Context) error, opts *TransactionOptions) error | 
| - | 
| -	// Run executes the given query, and calls `cb` for each successfully | 
| -	// retrieved item. | 
| -	// | 
| -	// cb is a callback function whose signature is | 
| -	//   func(obj TYPE[, getCursor CursorCB]) [error] | 
| -	// | 
| -	// Where TYPE is one of: | 
| -	//   - S or *S, where S is a struct | 
| -	//   - P or *P, where *P is a concrete type implementing PropertyLoadSaver | 
| -	//   - *Key (implies a keys-only query) | 
| -	// | 
| -	// If the error is omitted from the signature, this will run until the query | 
| -	// returns all its results, or has an error/times out. | 
| -	// | 
| -	// If error is in the signature, the query will continue as long as the | 
| -	// callback returns nil. If it returns `Stop`, the query will stop and Run | 
| -	// will return nil. Otherwise, the query will stop and Run will return the | 
| -	// user's error. | 
| -	// | 
| -	// Run may also stop on the first datastore error encountered, which can occur | 
| -	// due to flakiness, timeout, etc. If it encounters such an error, it will | 
| -	// be returned. | 
| -	Run(q *Query, cb interface{}) error | 
| - | 
| -	// Count executes the given query and returns the number of entries which | 
| -	// match it. | 
| -	Count(q *Query) (int64, error) | 
| - | 
| -	// DecodeCursor converts a string returned by a Cursor into a Cursor instance. | 
| -	// It will return an error if the supplied string is not valid, or could not | 
| -	// be decoded by the implementation. | 
| -	DecodeCursor(string) (Cursor, error) | 
| - | 
| -	// GetAll retrieves all of the Query results into dst. | 
| -	// | 
| -	// dst must be one of: | 
| -	//   - *[]S or *[]*S, where S is a struct | 
| -	//   - *[]P or *[]*P, where *P is a concrete type implementing | 
| -	//     PropertyLoadSaver | 
| -	//   - *[]*Key implies a keys-only query. | 
| -	GetAll(q *Query, dst interface{}) error | 
| - | 
| -	// Exists tests if the supplied objects are present in the datastore. | 
| -	// | 
| -	// ent must be one of: | 
| -	//	- *S, where S is a struct | 
| -	//	- *P, where *P is a concrete type implementing PropertyLoadSaver | 
| -	//	- []S or []*S, where S is a struct | 
| -	//	- []P or []*P, where *P is a concrete type implementing PropertyLoadSaver | 
| -	//	- []I, where I is some interface type. Each element of the slice must | 
| -	//	  be non-nil, and its underlying type must be either *S or *P. | 
| -	//	- *Key, to check a specific key from the datastore. | 
| -	//	- []*Key, to check a slice of keys from the datastore. | 
| -	// | 
| -	// If an error is encountered, the returned error value will depend on the | 
| -	// input arguments. If one argument is supplied, the result will be the | 
| -	// encountered error type. If multiple arguments are supplied, the result will | 
| -	// be a MultiError whose error index corresponds to the argument in which the | 
| -	// error was encountered. | 
| -	// | 
| -	// If an ent argument is a slice, its error type will be a MultiError. Note | 
| -	// that in the scenario, where multiple slices are provided, this will return a | 
| -	// MultiError containing a nested MultiError for each slice argument. | 
| -	Exists(ent ...interface{}) (*ExistsResult, error) | 
| - | 
| -	// Does a GetMulti for thes keys and returns true iff they exist. Will only | 
| -	// return an error if it's not ErrNoSuchEntity. This is slightly more | 
| -	// efficient than using Get directly, because it uses the underlying | 
| -	// RawInterface to avoid some reflection and copies. | 
| -	// | 
| -	// If an error is encountered, the returned error will be a MultiError whose | 
| -	// error index corresponds to the key for which the error was encountered. | 
| -	// | 
| -	// NOTE: ExistsMulti is obsolete. The vararg-accepting Exists should be used | 
| -	// instead. This is left for backwards compatibility, but will be removed from | 
| -	// this interface at some point in the future. | 
| -	ExistsMulti(k []*Key) (BoolList, error) | 
| - | 
| -	// Get retrieves objects from the datastore. | 
| -	// | 
| -	// Each element in dst must be one of: | 
| -	//	- *S, where S is a struct | 
| -	//	- *P, where *P is a concrete type implementing PropertyLoadSaver | 
| -	//	- []S or []*S, where S is a struct | 
| -	//	- []P or []*P, where *P is a concrete type implementing PropertyLoadSaver | 
| -	//	- []I, where I is some interface type. Each element of the slice must | 
| -	//	  be non-nil, and its underlying type must be either *S or *P. | 
| -	// | 
| -	// If an error is encountered, the returned error value will depend on the | 
| -	// input arguments. If one argument is supplied, the result will be the | 
| -	// encountered error type. If multiple arguments are supplied, the result will | 
| -	// be a MultiError whose error index corresponds to the argument in which the | 
| -	// error was encountered. | 
| -	// | 
| -	// If a dst argument is a slice, its error type will be a MultiError. Note | 
| -	// that in the scenario where multiple slices are provided, this will return a | 
| -	// MultiError containing a nested MultiError for each slice argument. | 
| -	Get(dst ...interface{}) error | 
| - | 
| -	// GetMulti retrieves items from the datastore. | 
| -	// | 
| -	// dst must be one of: | 
| -	//   - []S or []*S, where S is a struct | 
| -	//   - []P or []*P, where *P is a concrete type implementing PropertyLoadSaver | 
| -	//   - []I, where I is some interface type. Each element of the slice must | 
| -	//     be non-nil, and its underlying type must be either *S or *P. | 
| -	// | 
| -	// NOTE: GetMulti is obsolete. The vararg-accepting Get should be used | 
| -	// instead. This is left for backwards compatibility, but will be removed from | 
| -	// this interface at some point in the future. | 
| -	GetMulti(dst interface{}) error | 
| - | 
| -	// Put writes objects into the datastore. | 
| -	// | 
| -	// src must be one of: | 
| -	//	- *S, where S is a struct | 
| -	//	- *P, where *P is a concrete type implementing PropertyLoadSaver | 
| -	//	- []S or []*S, where S is a struct | 
| -	//	- []P or []*P, where *P is a concrete type implementing PropertyLoadSaver | 
| -	//	- []I, where I is some interface type. Each element of the slice must | 
| -	//	  be non-nil, and its underlying type must be either *S or *P. | 
| -	// | 
| -	// A *Key will be extracted from src via KeyForObj. If | 
| -	// extractedKey.Incomplete() is true, then Put will write the resolved (i.e. | 
| -	// automatic datastore-populated) *Key back to src. | 
| -	// | 
| -	// If an error is encountered, the returned error value will depend on the | 
| -	// input arguments. If one argument is supplied, the result will be the | 
| -	// encountered error type. If multiple arguments are supplied, the result will | 
| -	// be a MultiError whose error index corresponds to the argument in which the | 
| -	// error was encountered. | 
| -	// | 
| -	// If a src argument is a slice, its error type will be a MultiError. Note | 
| -	// that in the scenario where multiple slices are provided, this will return a | 
| -	// MultiError containing a nested MultiError for each slice argument. | 
| -	Put(src ...interface{}) error | 
| - | 
| -	// PutMulti writes items to the datastore. | 
| -	// | 
| -	// src must be one of: | 
| -	//	- []S or []*S, where S is a struct | 
| -	//	- []P or []*P, where *P is a concrete type implementing PropertyLoadSaver | 
| -	//	- []I, where I is some interface type. Each element of the slice must | 
| -	//	  be non-nil, and its underlying type must be either *S or *P. | 
| -	// | 
| -	// If items in src resolve to Incomplete keys, PutMulti will write the | 
| -	// resolved keys back to the items in src. | 
| -	// | 
| -	// NOTE: PutMulti is obsolete. The vararg-accepting Put should be used | 
| -	// instead. This is left for backwards compatibility, but will be removed from | 
| -	// this interface at some point in the future. | 
| -	PutMulti(src interface{}) error | 
| - | 
| -	// Delete removes the supplied entities from the datastore. | 
| -	// | 
| -	// ent must be one of: | 
| -	//	- *S, where S is a struct | 
| -	//	- *P, where *P is a concrete type implementing PropertyLoadSaver | 
| -	//	- []S or []*S, where S is a struct | 
| -	//	- []P or []*P, where *P is a concrete type implementing PropertyLoadSaver | 
| -	//	- []I, where I is some interface type. Each element of the slice must | 
| -	//	  be non-nil, and its underlying type must be either *S or *P. | 
| -	//	- *Key, to remove a specific key from the datastore. | 
| -	//	- []*Key, to remove a slice of keys from the datastore. | 
| -	// | 
| -	// If an error is encountered, the returned error value will depend on the | 
| -	// input arguments. If one argument is supplied, the result will be the | 
| -	// encountered error type. If multiple arguments are supplied, the result will | 
| -	// be a MultiError whose error index corresponds to the argument in which the | 
| -	// error was encountered. | 
| -	// | 
| -	// If an ent argument is a slice, its error type will be a MultiError. Note | 
| -	// that in the scenario where multiple slices are provided, this will return a | 
| -	// MultiError containing a nested MultiError for each slice argument. | 
| -	Delete(ent ...interface{}) error | 
| - | 
| -	// DeleteMulti removes keys from the datastore. | 
| -	// | 
| -	// If an error is encountered, the returned error will be a MultiError whose | 
| -	// error index corresponds to the key for which the error was encountered. | 
| -	// | 
| -	// NOTE: DeleteMulti is obsolete. The vararg-accepting Delete should be used | 
| -	// instead. This is left for backwards compatibility, but will be removed from | 
| -	// this interface at some point in the future. | 
| -	DeleteMulti(keys []*Key) error | 
| - | 
| -	// Testable returns the Testable interface for the implementation, or nil if | 
| -	// there is none. | 
| -	Testable() Testable | 
| - | 
| -	// Raw returns the underlying RawInterface. The Interface and RawInterface may | 
| -	// be used interchangably; there's no danger of interleaving access to the | 
| -	// datastore via the two. | 
| -	Raw() RawInterface | 
| +func runParseCallback(cbIface interface{}) (isKey, hasErr, hasCursorCB bool, mat *multiArgType) { | 
| +	badSig := func() { | 
| +		panic(fmt.Errorf( | 
| +			"cb does not match the required callback signature: `%T` != `func(TYPE, [CursorCB]) [error]`", | 
| +			cbIface)) | 
| +	} | 
| + | 
| +	if cbIface == nil { | 
| +		badSig() | 
| +	} | 
| + | 
| +	// TODO(riannucci): Profile and determine if any of this is causing a real | 
| +	// slowdown. Could potentially cache reflection stuff by cbTyp? | 
| +	cbTyp := reflect.TypeOf(cbIface) | 
| + | 
| +	if cbTyp.Kind() != reflect.Func { | 
| +		badSig() | 
| +	} | 
| + | 
| +	numIn := cbTyp.NumIn() | 
| +	if numIn != 1 && numIn != 2 { | 
| +		badSig() | 
| +	} | 
| + | 
| +	firstArg := cbTyp.In(0) | 
| +	if firstArg == typeOfKey { | 
| +		isKey = true | 
| +	} else { | 
| +		mat = mustParseArg(firstArg, false) | 
| +		if mat.newElem == nil { | 
| +			badSig() | 
| +		} | 
| +	} | 
| + | 
| +	hasCursorCB = numIn == 2 | 
| +	if hasCursorCB && cbTyp.In(1) != typeOfCursorCB { | 
| +		badSig() | 
| +	} | 
| + | 
| +	if cbTyp.NumOut() > 1 { | 
| +		badSig() | 
| +	} else if cbTyp.NumOut() == 1 && cbTyp.Out(0) != typeOfError { | 
| +		badSig() | 
| +	} | 
| +	hasErr = cbTyp.NumOut() == 1 | 
| + | 
| +	return | 
| +} | 
| + | 
| +// AllocateIDs allows you to allocate IDs from the datastore without putting | 
| +// any data. | 
| +// | 
| +// A partial valid key will be constructed from each entity's kind and parent, | 
| +// if present. An allocation will then be performed against the datastore for | 
| +// each key, and the partial key will be populated with a unique integer ID. | 
| +// The resulting keys will be applied to their objects using PopulateKey. If | 
| +// successful, any existing ID will be destroyed. | 
| +// | 
| +// If the object is supplied that cannot accept an integer key, this method | 
| +// will panic. | 
| +// | 
| +// ent must be one of: | 
| +//	- *S where S is a struct | 
| +//	- *P where *P is a concrete type implementing PropertyLoadSaver | 
| +//	- []S or []*S where S is a struct | 
| +//	- []P or []*P where *P is a concrete type implementing PropertyLoadSaver | 
| +//	- []I where i is some interface type. Each element of the slice must | 
| +//	  be non-nil, and its underlying type must be either *S or *P. | 
| +//	- []*Key, to populate a slice of partial-valid keys. | 
| +// | 
| +// If an error is encountered, the returned error value will depend on the | 
| +// input arguments. If one argument is supplied, the result will be the | 
| +// encountered error type. If multiple arguments are supplied, the result will | 
| +// be a MultiError whose error index corresponds to the argument in which the | 
| +// error was encountered. | 
| +// | 
| +// If an ent argument is a slice, its error type will be a MultiError. Note | 
| +// that in the scenario where multiple slices are provided, this will return a | 
| +// MultiError containing a nested MultiError for each slice argument. | 
| +func AllocateIDs(c context.Context, ent ...interface{}) error { | 
| +	if len(ent) == 0 { | 
| +		return nil | 
| +	} | 
| + | 
| +	mma, err := makeMetaMultiArg(ent, mmaWriteKeys) | 
| +	if err != nil { | 
| +		panic(err) | 
| +	} | 
| + | 
| +	keys, _, err := mma.getKeysPMs(GetKeyContext(c), false) | 
| +	if err != nil { | 
| +		return maybeSingleError(err, ent) | 
| +	} | 
| +	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(Raw(c).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() | 
| +	} | 
| +	return maybeSingleError(err, ent) | 
| +} | 
| + | 
| +// KeyForObj extracts a key from src. | 
| +// | 
| +// It is the same as KeyForObjErr, except that if KeyForObjErr would have | 
| +// returned an error, this method panics. It's safe to use if you know that | 
| +// src statically meets the metadata constraints described by KeyForObjErr. | 
| +func KeyForObj(c context.Context, src interface{}) *Key { | 
| +	ret, err := KeyForObjErr(c, src) | 
| +	if err != nil { | 
| +		panic(err) | 
| +	} | 
| +	return ret | 
| +} | 
| + | 
| +// KeyForObjErr extracts a key from src. | 
| +// | 
| +// src must be one of: | 
| +//   - *S, where S is a struct | 
| +//   - a PropertyLoadSaver | 
| +// | 
| +// It is expected that the struct exposes the following metadata (as retrieved | 
| +// by MetaGetter.GetMeta): | 
| +//   - "key" (type: Key) - The full datastore key to use. Must not be nil. | 
| +//     OR | 
| +//   - "id" (type: int64 or string) - The id of the Key to create | 
| +//   - "kind" (optional, type: string) - The kind of the Key to create. If | 
| +//     blank or not present, KeyForObjErr will extract the name of the src | 
| +//     object's type. | 
| +//   - "parent" (optional, type: Key) - The parent key to use. | 
| +// | 
| +// By default, the metadata will be extracted from the struct and its tagged | 
| +// properties. However, if the struct implements MetaGetterSetter it is | 
| +// wholly responsible for exporting the required fields. A struct that | 
| +// implements GetMeta to make some minor tweaks can evoke the defualt behavior | 
| +// by using GetPLS(s).GetMeta. | 
| +// | 
| +// If a required metadata item is missing or of the wrong type, then this will | 
| +// return an error. | 
| +func KeyForObjErr(c context.Context, src interface{}) (*Key, error) { | 
| +	return newKeyObjErr(GetKeyContext(c), getMGS(src)) | 
| +} | 
| + | 
| +// MakeKey is a convenience method for manufacturing a *Key. It should only be | 
| +// used when elems... is known statically (e.g. in the code) to be correct. | 
| +// | 
| +// elems is pairs of (string, string|int|int32|int64) pairs, which correspond | 
| +// to Kind/id pairs. Example: | 
| +//   dstore.MakeKey("Parent", 1, "Child", "id") | 
| +// | 
| +// Would create the key: | 
| +//   <current appID>:<current Namespace>:/Parent,1/Child,id | 
| +// | 
| +// If elems is not parsable (e.g. wrong length, wrong types, etc.) this method | 
| +// will panic. | 
| +func MakeKey(c context.Context, elems ...interface{}) *Key { | 
| +	kc := GetKeyContext(c) | 
| +	return kc.MakeKey(elems...) | 
| +} | 
| + | 
| +// NewKey constructs a new key in the current appID/Namespace, using the | 
| +// specified parameters. | 
| +func NewKey(c context.Context, kind, stringID string, intID int64, parent *Key) *Key { | 
| +	kc := GetKeyContext(c) | 
| +	return kc.NewKey(kind, stringID, intID, parent) | 
| +} | 
| + | 
| +// NewIncompleteKeys allocates count incomplete keys sharing the same kind and | 
| +// parent. It is useful as input to AllocateIDs. | 
| +func NewIncompleteKeys(c context.Context, count int, kind string, parent *Key) (keys []*Key) { | 
| +	kc := GetKeyContext(c) | 
| +	if count > 0 { | 
| +		keys = make([]*Key, count) | 
| +		for i := range keys { | 
| +			keys[i] = kc.NewKey(kind, "", 0, parent) | 
| +		} | 
| +	} | 
| +	return | 
| +} | 
| + | 
| +// NewKeyToks constructs a new key in the current appID/Namespace, using the | 
| +// specified key tokens. | 
| +func NewKeyToks(c context.Context, toks []KeyTok) *Key { | 
| +	kc := GetKeyContext(c) | 
| +	return kc.NewKeyToks(toks) | 
| +} | 
| + | 
| +// PopulateKey loads key into obj. | 
| +// | 
| +// 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) bool { | 
| +	return populateKeyMGS(getMGS(obj), key) | 
| +} | 
| + | 
| +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()) | 
| +	return true | 
| +} | 
| + | 
| +// RunInTransaction runs f inside of a transaction. See the appengine SDK's | 
| +// documentation for full details on the behavior of transactions in the | 
| +// datastore. | 
| +// | 
| +// Note that the behavior of transactions may change depending on what filters | 
| +// have been installed. It's possible that we'll end up implementing things | 
| +// like nested/buffered transactions as filters. | 
| +func RunInTransaction(c context.Context, f func(c context.Context) error, opts *TransactionOptions) error { | 
| +	return Raw(c).RunInTransaction(f, opts) | 
| +} | 
| + | 
| +// Run executes the given query, and calls `cb` for each successfully | 
| +// retrieved item. | 
| +// | 
| +// cb is a callback function whose signature is | 
| +//   func(obj TYPE[, getCursor CursorCB]) [error] | 
| +// | 
| +// Where TYPE is one of: | 
| +//   - S or *S, where S is a struct | 
| +//   - P or *P, where *P is a concrete type implementing PropertyLoadSaver | 
| +//   - *Key (implies a keys-only query) | 
| +// | 
| +// If the error is omitted from the signature, this will run until the query | 
| +// returns all its results, or has an error/times out. | 
| +// | 
| +// If error is in the signature, the query will continue as long as the | 
| +// callback returns nil. If it returns `Stop`, the query will stop and Run | 
| +// will return nil. Otherwise, the query will stop and Run will return the | 
| +// user's error. | 
| +// | 
| +// Run may also stop on the first datastore error encountered, which can occur | 
| +// due to flakiness, timeout, etc. If it encounters such an error, it will | 
| +// be returned. | 
| +func Run(c context.Context, q *Query, cb interface{}) error { | 
| +	isKey, hasErr, hasCursorCB, mat := runParseCallback(cb) | 
| + | 
| +	if isKey { | 
| +		q = q.KeysOnly(true) | 
| +	} | 
| +	fq, err := q.Finalize() | 
| +	if err != nil { | 
| +		return err | 
| +	} | 
| + | 
| +	cbVal := reflect.ValueOf(cb) | 
| +	var cbFunc func(reflect.Value, CursorCB) error | 
| +	switch { | 
| +	case hasErr && hasCursorCB: | 
| +		cbFunc = func(v reflect.Value, cb CursorCB) error { | 
| +			err := cbVal.Call([]reflect.Value{v, reflect.ValueOf(cb)})[0].Interface() | 
| +			if err != nil { | 
| +				return err.(error) | 
| +			} | 
| +			return nil | 
| +		} | 
| + | 
| +	case hasErr && !hasCursorCB: | 
| +		cbFunc = func(v reflect.Value, _ CursorCB) error { | 
| +			err := cbVal.Call([]reflect.Value{v})[0].Interface() | 
| +			if err != nil { | 
| +				return err.(error) | 
| +			} | 
| +			return nil | 
| +		} | 
| + | 
| +	case !hasErr && hasCursorCB: | 
| +		cbFunc = func(v reflect.Value, cb CursorCB) error { | 
| +			cbVal.Call([]reflect.Value{v, reflect.ValueOf(cb)}) | 
| +			return nil | 
| +		} | 
| + | 
| +	case !hasErr && !hasCursorCB: | 
| +		cbFunc = func(v reflect.Value, _ CursorCB) error { | 
| +			cbVal.Call([]reflect.Value{v}) | 
| +			return nil | 
| +		} | 
| +	} | 
| + | 
| +	raw := Raw(c) | 
| +	if isKey { | 
| +		err = raw.Run(fq, func(k *Key, _ PropertyMap, gc CursorCB) error { | 
| +			return cbFunc(reflect.ValueOf(k), gc) | 
| +		}) | 
| +	} else { | 
| +		err = raw.Run(fq, func(k *Key, pm PropertyMap, gc CursorCB) error { | 
| +			itm := mat.newElem() | 
| +			if err := mat.setPM(itm, pm); err != nil { | 
| +				return err | 
| +			} | 
| +			mat.setKey(itm, k) | 
| +			return cbFunc(itm, gc) | 
| +		}) | 
| +	} | 
| +	return filterStop(err) | 
| +} | 
| + | 
| +// Count executes the given query and returns the number of entries which | 
| +// match it. | 
| +func Count(c context.Context, q *Query) (int64, error) { | 
| +	fq, err := q.Finalize() | 
| +	if err != nil { | 
| +		return 0, err | 
| +	} | 
| +	v, err := Raw(c).Count(fq) | 
| +	return v, filterStop(err) | 
| +} | 
| + | 
| +// DecodeCursor converts a string returned by a Cursor into a Cursor instance. | 
| +// It will return an error if the supplied string is not valid, or could not | 
| +// be decoded by the implementation. | 
| +func DecodeCursor(c context.Context, s string) (Cursor, error) { | 
| +	return Raw(c).DecodeCursor(s) | 
| +} | 
| + | 
| +// GetAll retrieves all of the Query results into dst. | 
| +// | 
| +// dst must be one of: | 
| +//   - *[]S or *[]*S, where S is a struct | 
| +//   - *[]P or *[]*P, where *P is a concrete type implementing | 
| +//     PropertyLoadSaver | 
| +//   - *[]*Key implies a keys-only query. | 
| +func GetAll(c context.Context, q *Query, dst interface{}) error { | 
| +	v := reflect.ValueOf(dst) | 
| +	if v.Kind() != reflect.Ptr { | 
| +		panic(fmt.Errorf("invalid GetAll dst: must have a ptr-to-slice: %T", dst)) | 
| +	} | 
| +	if !v.IsValid() || v.IsNil() { | 
| +		panic(errors.New("invalid GetAll dst: <nil>")) | 
| +	} | 
| + | 
| +	raw := Raw(c) | 
| +	if keys, ok := dst.(*[]*Key); ok { | 
| +		fq, err := q.KeysOnly(true).Finalize() | 
| +		if err != nil { | 
| +			return err | 
| +		} | 
| + | 
| +		return raw.Run(fq, func(k *Key, _ PropertyMap, _ CursorCB) error { | 
| +			*keys = append(*keys, k) | 
| +			return nil | 
| +		}) | 
| +	} | 
| +	fq, err := q.Finalize() | 
| +	if err != nil { | 
| +		return err | 
| +	} | 
| + | 
| +	slice := v.Elem() | 
| +	mat := mustParseMultiArg(slice.Type()) | 
| +	if mat.newElem == nil { | 
| +		panic(fmt.Errorf("invalid GetAll dst (non-concrete element type): %T", dst)) | 
| +	} | 
| + | 
| +	errs := map[int]error{} | 
| +	i := 0 | 
| +	err = filterStop(raw.Run(fq, func(k *Key, pm PropertyMap, _ CursorCB) error { | 
| +		slice.Set(reflect.Append(slice, mat.newElem())) | 
| +		itm := slice.Index(i) | 
| +		mat.setKey(itm, k) | 
| +		err := mat.setPM(itm, pm) | 
| +		if err != nil { | 
| +			errs[i] = err | 
| +		} | 
| +		i++ | 
| +		return nil | 
| +	})) | 
| +	if err == nil { | 
| +		if len(errs) > 0 { | 
| +			me := make(errors.MultiError, slice.Len()) | 
| +			for i, e := range errs { | 
| +				me[i] = e | 
| +			} | 
| +			err = me | 
| +		} | 
| +	} | 
| +	return err | 
| +} | 
| + | 
| +// Exists tests if the supplied objects are present in the datastore. | 
| +// | 
| +// ent must be one of: | 
| +//	- *S, where S is a struct | 
| +//	- *P, where *P is a concrete type implementing PropertyLoadSaver | 
| +//	- []S or []*S, where S is a struct | 
| +//	- []P or []*P, where *P is a concrete type implementing PropertyLoadSaver | 
| +//	- []I, where I is some interface type. Each element of the slice must | 
| +//	  be non-nil, and its underlying type must be either *S or *P. | 
| +//	- *Key, to check a specific key from the datastore. | 
| +//	- []*Key, to check a slice of keys from the datastore. | 
| +// | 
| +// If an error is encountered, the returned error value will depend on the | 
| +// input arguments. If one argument is supplied, the result will be the | 
| +// encountered error type. If multiple arguments are supplied, the result will | 
| +// be a MultiError whose error index corresponds to the argument in which the | 
| +// error was encountered. | 
| +// | 
| +// If an ent argument is a slice, its error type will be a MultiError. Note | 
| +// that in the scenario, where multiple slices are provided, this will return a | 
| +// MultiError containing a nested MultiError for each slice argument. | 
| +func Exists(c context.Context, ent ...interface{}) (*ExistsResult, error) { | 
| +	if len(ent) == 0 { | 
| +		return nil, nil | 
| +	} | 
| + | 
| +	mma, err := makeMetaMultiArg(ent, mmaKeysOnly) | 
| +	if err != nil { | 
| +		panic(err) | 
| +	} | 
| + | 
| +	keys, _, err := mma.getKeysPMs(GetKeyContext(c), false) | 
| +	if err != nil { | 
| +		return nil, maybeSingleError(err, ent) | 
| +	} | 
| +	if len(keys) == 0 { | 
| +		return nil, nil | 
| +	} | 
| + | 
| +	var bt boolTracker | 
| +	it := mma.iterator(bt.init(mma)) | 
| +	err = filterStop(Raw(c).GetMulti(keys, nil, func(_ PropertyMap, err error) error { | 
| +		it.next(func(*multiArgType, reflect.Value) error { | 
| +			return err | 
| +		}) | 
| +		return nil | 
| +	})) | 
| +	if err == nil { | 
| +		err = bt.error() | 
| +	} | 
| +	return bt.result(), maybeSingleError(err, ent) | 
| +} | 
| + | 
| +// Get retrieves objects from the datastore. | 
| +// | 
| +// Each element in dst must be one of: | 
| +//	- *S, where S is a struct | 
| +//	- *P, where *P is a concrete type implementing PropertyLoadSaver | 
| +//	- []S or []*S, where S is a struct | 
| +//	- []P or []*P, where *P is a concrete type implementing PropertyLoadSaver | 
| +//	- []I, where I is some interface type. Each element of the slice must | 
| +//	  be non-nil, and its underlying type must be either *S or *P. | 
| +// | 
| +// If an error is encountered, the returned error value will depend on the | 
| +// input arguments. If one argument is supplied, the result will be the | 
| +// encountered error type. If multiple arguments are supplied, the result will | 
| +// be a MultiError whose error index corresponds to the argument in which the | 
| +// error was encountered. | 
| +// | 
| +// If a dst argument is a slice, its error type will be a MultiError. Note | 
| +// that in the scenario where multiple slices are provided, this will return a | 
| +// MultiError containing a nested MultiError for each slice argument. | 
| +func Get(c context.Context, dst ...interface{}) error { | 
| +	if len(dst) == 0 { | 
| +		return nil | 
| +	} | 
| + | 
| +	mma, err := makeMetaMultiArg(dst, mmaReadWrite) | 
| +	if err != nil { | 
| +		panic(err) | 
| +	} | 
| + | 
| +	keys, pms, err := mma.getKeysPMs(GetKeyContext(c), true) | 
| +	if err != nil { | 
| +		return maybeSingleError(err, dst) | 
| +	} | 
| +	if len(keys) == 0 { | 
| +		return nil | 
| +	} | 
| + | 
| +	var et errorTracker | 
| +	it := mma.iterator(et.init(mma)) | 
| +	meta := NewMultiMetaGetter(pms) | 
| +	err = filterStop(Raw(c).GetMulti(keys, meta, func(pm PropertyMap, err error) error { | 
| +		it.next(func(mat *multiArgType, slot reflect.Value) error { | 
| +			if err != nil { | 
| +				return err | 
| +			} | 
| +			return mat.setPM(slot, pm) | 
| +		}) | 
| +		return nil | 
| +	})) | 
| + | 
| +	if err == nil { | 
| +		err = et.error() | 
| +	} | 
| +	return maybeSingleError(err, dst) | 
| +} | 
| + | 
| +// Put writes objects into the datastore. | 
| +// | 
| +// src must be one of: | 
| +//	- *S, where S is a struct | 
| +//	- *P, where *P is a concrete type implementing PropertyLoadSaver | 
| +//	- []S or []*S, where S is a struct | 
| +//	- []P or []*P, where *P is a concrete type implementing PropertyLoadSaver | 
| +//	- []I, where I is some interface type. Each element of the slice must | 
| +//	  be non-nil, and its underlying type must be either *S or *P. | 
| +// | 
| +// A *Key will be extracted from src via KeyForObj. If | 
| +// extractedKey.Incomplete() is true, then Put will write the resolved (i.e. | 
| +// automatic datastore-populated) *Key back to src. | 
| +// | 
| +// If an error is encountered, the returned error value will depend on the | 
| +// input arguments. If one argument is supplied, the result will be the | 
| +// encountered error type. If multiple arguments are supplied, the result will | 
| +// be a MultiError whose error index corresponds to the argument in which the | 
| +// error was encountered. | 
| +// | 
| +// If a src argument is a slice, its error type will be a MultiError. Note | 
| +// that in the scenario where multiple slices are provided, this will return a | 
| +// MultiError containing a nested MultiError for each slice argument. | 
| +func Put(c context.Context, src ...interface{}) error { | 
| +	if len(src) == 0 { | 
| +		return nil | 
| +	} | 
| + | 
| +	mma, err := makeMetaMultiArg(src, mmaReadWrite) | 
| +	if err != nil { | 
| +		panic(err) | 
| +	} | 
| + | 
| +	keys, vals, err := mma.getKeysPMs(GetKeyContext(c), false) | 
| +	if err != nil { | 
| +		return maybeSingleError(err, src) | 
| +	} | 
| +	if len(keys) == 0 { | 
| +		return nil | 
| +	} | 
| + | 
| +	i := 0 | 
| +	var et errorTracker | 
| +	it := mma.iterator(et.init(mma)) | 
| +	err = filterStop(Raw(c).PutMulti(keys, vals, func(key *Key, err error) error { | 
| +		it.next(func(mat *multiArgType, slot reflect.Value) error { | 
| +			if err != nil { | 
| +				return err | 
| +			} | 
| +			if key != keys[i] { | 
| +				mat.setKey(slot, key) | 
| +			} | 
| +			return nil | 
| +		}) | 
| + | 
| +		i++ | 
| +		return nil | 
| +	})) | 
| + | 
| +	if err == nil { | 
| +		err = et.error() | 
| +	} | 
| +	return maybeSingleError(err, src) | 
| +} | 
| + | 
| +// Delete removes the supplied entities from the datastore. | 
| +// | 
| +// ent must be one of: | 
| +//	- *S, where S is a struct | 
| +//	- *P, where *P is a concrete type implementing PropertyLoadSaver | 
| +//	- []S or []*S, where S is a struct | 
| +//	- []P or []*P, where *P is a concrete type implementing PropertyLoadSaver | 
| +//	- []I, where I is some interface type. Each element of the slice must | 
| +//	  be non-nil, and its underlying type must be either *S or *P. | 
| +//	- *Key, to remove a specific key from the datastore. | 
| +//	- []*Key, to remove a slice of keys from the datastore. | 
| +// | 
| +// If an error is encountered, the returned error value will depend on the | 
| +// input arguments. If one argument is supplied, the result will be the | 
| +// encountered error type. If multiple arguments are supplied, the result will | 
| +// be a MultiError whose error index corresponds to the argument in which the | 
| +// error was encountered. | 
| +// | 
| +// If an ent argument is a slice, its error type will be a MultiError. Note | 
| +// that in the scenario where multiple slices are provided, this will return a | 
| +// MultiError containing a nested MultiError for each slice argument. | 
| +func Delete(c context.Context, ent ...interface{}) error { | 
| +	if len(ent) == 0 { | 
| +		return nil | 
| +	} | 
| + | 
| +	mma, err := makeMetaMultiArg(ent, mmaKeysOnly) | 
| +	if err != nil { | 
| +		panic(err) | 
| +	} | 
| + | 
| +	keys, _, err := mma.getKeysPMs(GetKeyContext(c), false) | 
| +	if err != nil { | 
| +		return maybeSingleError(err, ent) | 
| +	} | 
| +	if len(keys) == 0 { | 
| +		return nil | 
| +	} | 
| + | 
| +	var et errorTracker | 
| +	it := mma.iterator(et.init(mma)) | 
| +	err = filterStop(Raw(c).DeleteMulti(keys, func(err error) error { | 
| +		it.next(func(*multiArgType, reflect.Value) error { | 
| +			return err | 
| +		}) | 
| + | 
| +		return nil | 
| +	})) | 
| +	if err == nil { | 
| +		err = et.error() | 
| +	} | 
| +	return maybeSingleError(err, ent) | 
| +} | 
| + | 
| +// GetTestable returns the Testable interface for the implementation, or nil if | 
| +// there is none. | 
| +func GetTestable(c context.Context) Testable { | 
| +	return Raw(c).GetTestable() | 
| +} | 
| + | 
| +// maybeSingleError normalizes the error experience between single- and | 
| +// multi-element API calls. | 
| +// | 
| +// Single-element API calls will return a single error for that element, while | 
| +// multi-element API calls will return a MultiError, one for each element. This | 
| +// accepts the slice of elements that is being operated on and determines what | 
| +// sort of error to return. | 
| +func maybeSingleError(err error, elems []interface{}) error { | 
| +	if err == nil { | 
| +		return nil | 
| +	} | 
| +	if len(elems) == 1 { | 
| +		return errors.SingleError(err) | 
| +	} | 
| +	return err | 
| +} | 
| + | 
| +func filterStop(err error) error { | 
| +	if err == Stop { | 
| +		err = nil | 
| +	} | 
| +	return err | 
| } | 
|  |