func DeleteMulti(c appengine.Context, key []*Key) error {
	if len(key) == 0 {
		return nil
	}
	if err := multiValid(key); err != nil {
		return err
	}
	req := &pb.DeleteRequest{
		Key: multiKeyToProto(c.FullyQualifiedAppID(), key),
	}
	res := &pb.DeleteResponse{}
	return c.Call("datastore_v3", "Delete", req, res, nil)
}
DeleteMulti is a batch version of Delete.
package datastore
import (
	"errors"
	"fmt"
	"reflect"
	"time"
	"appengine"
	"appengine_internal"
	"goprotobuf.googlecode.com/hg/proto"
	pb "appengine_internal/datastore"
)
const maxIndexedProperties = 5000
const maxBlobLen = 1 << 20
type Time int64
func SecondsToTime(n int64) Time {
	return Time(n * 1e6)
}
func (t Time) Time() *time.Time {
	return time.SecondsToUTC(int64(t) / 1e6)
}
type Map map[string]interface{}
var (
	ErrInvalidEntityType = errors.New("datastore: invalid entity type")
	ErrInvalidKey = errors.New("datastore: invalid key")
	ErrNoSuchEntity = errors.New("datastore: no such entity")
)
type ErrFieldMismatch struct {
	Key        *Key
	StructType reflect.Type
	FieldName  string
	Reason     string
}
func (e *ErrFieldMismatch) String() string {
	return fmt.Sprintf("datastore: cannot load field %q from key %q into a %q: %s",
		e.FieldName, e.Key, e.StructType, e.Reason)
}
func (e *ErrFieldMismatch) Error() string {
	return fmt.Sprintf("datastore: cannot load field %q from key %q into a %q: %s",
		e.FieldName, e.Key, e.StructType, e.Reason)
}
type ErrMulti []error
func (m ErrMulti) Error() string {
	s, n := "", 0
	for _, e := range m {
		if e == nil {
			continue
		}
		if n == 0 {
			s = e.Error()
		}
		n++
	}
	switch n {
	case 0:
		return "(0 errors)"
	case 1:
		return s
	case 2:
		return s + " (and 1 other error)"
	}
	return fmt.Sprintf("%s (and %d other errors)", s, n-1)
}
func protoToKey(r *pb.Reference) (k *Key, err error) {
	appID := proto.GetString(r.App)
	for _, e := range r.Path.Element {
		k = &Key{
			kind:     proto.GetString(e.Type),
			stringID: proto.GetString(e.Name),
			intID:    proto.GetInt64(e.Id),
			parent:   k,
			appID:    appID,
		}
		if !k.valid() {
			return nil, ErrInvalidKey
		}
	}
	return
}
func keyToProto(defaultAppID string, k *Key) *pb.Reference {
	appID := k.appID
	if appID == "" {
		appID = defaultAppID
	}
	n := 0
	for i := k; i != nil; i = i.parent {
		n++
	}
	e := make([]*pb.Path_Element, n)
	for i := k; i != nil; i = i.parent {
		n--
		e[n] = &pb.Path_Element{
			Type: &i.kind,
		}
		if i.stringID != "" {
			e[n].Name = &i.stringID
		} else if i.intID != 0 {
			e[n].Id = &i.intID
		}
	}
	return &pb.Reference{
		App: proto.String(appID),
		Path: &pb.Path{
			Element: e,
		},
	}
}
func multiKeyToProto(appID string, key []*Key) []*pb.Reference {
	ret := make([]*pb.Reference, len(key))
	for i, k := range key {
		ret[i] = keyToProto(appID, k)
	}
	return ret
}
func multiValid(key []*Key) error {
	invalid := false
	for _, k := range key {
		if !k.valid() {
			invalid = true
			break
		}
	}
	if !invalid {
		return nil
	}
	err := make(ErrMulti, len(key))
	for i, k := range key {
		if !k.valid() {
			err[i] = ErrInvalidKey
		}
	}
	return err
}
func referenceValueToKey(r *pb.PropertyValue_ReferenceValue) (k *Key, err error) {
	appID := proto.GetString(r.App)
	for _, e := range r.Pathelement {
		k = &Key{
			kind:     proto.GetString(e.Type),
			stringID: proto.GetString(e.Name),
			intID:    proto.GetInt64(e.Id),
			parent:   k,
			appID:    appID,
		}
		if !k.valid() {
			return nil, ErrInvalidKey
		}
	}
	return
}
func keyToReferenceValue(defaultAppID string, k *Key) *pb.PropertyValue_ReferenceValue {
	ref := keyToProto(defaultAppID, k)
	pe := make([]*pb.PropertyValue_ReferenceValue_PathElement, len(ref.Path.Element))
	for i, e := range ref.Path.Element {
		pe[i] = &pb.PropertyValue_ReferenceValue_PathElement{
			Type: e.Type,
			Id:   e.Id,
			Name: e.Name,
		}
	}
	return &pb.PropertyValue_ReferenceValue{
		App:         ref.App,
		Pathelement: pe,
	}
}
func asStructValue(x interface{}) (reflect.Value, error) {
	pv := reflect.ValueOf(x)
	if pv.Kind() != reflect.Ptr || pv.Elem().Kind() != reflect.Struct {
		return reflect.Value{}, ErrInvalidEntityType
	}
	return pv.Elem(), nil
}
func Get(c appengine.Context, key *Key, dst interface{}) error {
	err := GetMulti(c, []*Key{key}, []interface{}{dst})
	if errMulti, ok := err.(ErrMulti); ok {
		return errMulti[0]
	}
	return err
}
func GetMulti(c appengine.Context, key []*Key, dst []interface{}) error {
	if len(key) != len(dst) {
		return errors.New("datastore: key and dst slices have different length")
	}
	if len(key) == 0 {
		return nil
	}
	if err := multiValid(key); err != nil {
		return err
	}
	req := &pb.GetRequest{
		Key: multiKeyToProto(c.FullyQualifiedAppID(), key),
	}
	res := &pb.GetResponse{}
	err := c.Call("datastore_v3", "Get", req, res, nil)
	if err != nil {
		return err
	}
	if len(key) != len(res.Entity) {
		return errors.New("datastore: internal error: server returned the wrong number of entities")
	}
	errMulti := make(ErrMulti, len(key))
	for i, e := range res.Entity {
		if e.Entity == nil {
			errMulti[i] = ErrNoSuchEntity
			continue
		}
		if m, ok := dst[i].(Map); ok {
			errMulti[i] = loadMap(m, key[i], e.Entity)
			continue
		}
		sv, err := asStructValue(dst[i])
		if err != nil {
			errMulti[i] = err
			continue
		}
		errMulti[i] = loadStruct(sv, key[i], e.Entity)
	}
	for _, e := range errMulti {
		if e != nil {
			return errMulti
		}
	}
	return nil
}
func Put(c appengine.Context, key *Key, src interface{}) (*Key, error) {
	k, err := PutMulti(c, []*Key{key}, []interface{}{src})
	if err != nil {
		if errMulti, ok := err.(ErrMulti); ok {
			return nil, errMulti[0]
		}
		return nil, err
	}
	return k[0], nil
}
func PutMulti(c appengine.Context, key []*Key, src []interface{}) ([]*Key, error) {
	if len(key) != len(src) {
		return nil, errors.New("datastore: key and src slices have different length")
	}
	if len(key) == 0 {
		return nil, nil
	}
	appID := c.FullyQualifiedAppID()
	if err := multiValid(key); err != nil {
		return nil, err
	}
	req := &pb.PutRequest{}
	for i, sIface := range src {
		if m, ok := sIface.(Map); ok {
			sProto, err := saveMap(appID, key[i], m)
			if err != nil {
				return nil, err
			}
			req.Entity = append(req.Entity, sProto)
		} else {
			sv, err := asStructValue(sIface)
			if err != nil {
				return nil, err
			}
			sProto, err := saveStruct(appID, key[i], sv)
			if err != nil {
				return nil, err
			}
			req.Entity = append(req.Entity, sProto)
		}
	}
	res := &pb.PutResponse{}
	err := c.Call("datastore_v3", "Put", req, res, nil)
	if err != nil {
		return nil, err
	}
	if len(key) != len(res.Key) {
		return nil, errors.New("datastore: internal error: server returned the wrong number of keys")
	}
	ret := make([]*Key, len(key))
	for i := range ret {
		ret[i], err = protoToKey(res.Key[i])
		if err != nil || ret[i].Incomplete() {
			return nil, errors.New("datastore: internal error: server returned an invalid key")
		}
	}
	return ret, nil
}
func Delete(c appengine.Context, key *Key) error {
	err := DeleteMulti(c, []*Key{key})
	if errMulti, ok := err.(ErrMulti); ok {
		return errMulti[0]
	}
	return err
}