| Index: service/datastore/dskey/key.go
 | 
| diff --git a/service/datastore/key.go b/service/datastore/dskey/key.go
 | 
| similarity index 66%
 | 
| rename from service/datastore/key.go
 | 
| rename to service/datastore/dskey/key.go
 | 
| index 0e588754b8af7f2af8fbf6601d28f60d28282282..f700d518e35d2765899c0aac995961aa5b86c072 100644
 | 
| --- a/service/datastore/key.go
 | 
| +++ b/service/datastore/dskey/key.go
 | 
| @@ -4,7 +4,7 @@
 | 
|  
 | 
|  // adapted from github.com/golang/appengine/datastore
 | 
|  
 | 
| -package datastore
 | 
| +package dskey
 | 
|  
 | 
|  import (
 | 
|  	"bytes"
 | 
| @@ -13,16 +13,18 @@ import (
 | 
|  	"strconv"
 | 
|  	"strings"
 | 
|  
 | 
| -	pb "github.com/luci/gae/service/datastore/internal/protos/datastore"
 | 
| -
 | 
|  	"github.com/golang/protobuf/proto"
 | 
| +	ds "github.com/luci/gae/service/datastore"
 | 
| +	pb "github.com/luci/gae/service/datastore/internal/protos/datastore"
 | 
|  )
 | 
|  
 | 
| -// KeyEncode encodes the provided key as a base64-encoded protobuf.
 | 
| +// Encode encodes the provided key as a base64-encoded protobuf.
 | 
|  //
 | 
|  // This encoding is compatible with the SDK-provided encoding and is agnostic
 | 
|  // to the underlying implementation of the Key.
 | 
| -func KeyEncode(k Key) string {
 | 
| +//
 | 
| +// It's encoded with the urlsafe base64 table.
 | 
| +func Encode(k ds.Key) string {
 | 
|  	n := 0
 | 
|  	for i := k; i != nil; i = i.Parent() {
 | 
|  		n++
 | 
| @@ -63,13 +65,13 @@ func KeyEncode(k Key) string {
 | 
|  	return strings.TrimRight(base64.URLEncoding.EncodeToString(r), "=")
 | 
|  }
 | 
|  
 | 
| -// KeyToksDecode decodes a base64-encoded protobuf representation of a Key
 | 
| +// ToksDecode decodes a base64-encoded protobuf representation of a Key
 | 
|  // into a tokenized form. This is so that implementations of the gae wrapper
 | 
|  // can decode to their own implementation of Key.
 | 
|  //
 | 
|  // This encoding is compatible with the SDK-provided encoding and is agnostic
 | 
|  // to the underlying implementation of the Key.
 | 
| -func KeyToksDecode(encoded string) (appID, namespace string, toks []KeyTok, err error) {
 | 
| +func ToksDecode(encoded string) (appID, namespace string, toks []ds.KeyTok, err error) {
 | 
|  	// Re-add padding
 | 
|  	if m := len(encoded) % 4; m != 0 {
 | 
|  		encoded += strings.Repeat("=", 4-m)
 | 
| @@ -86,9 +88,9 @@ func KeyToksDecode(encoded string) (appID, namespace string, toks []KeyTok, err
 | 
|  
 | 
|  	appID = r.GetApp()
 | 
|  	namespace = r.GetNameSpace()
 | 
| -	toks = make([]KeyTok, len(r.Path.Element))
 | 
| +	toks = make([]ds.KeyTok, len(r.Path.Element))
 | 
|  	for i, e := range r.Path.Element {
 | 
| -		toks[i] = KeyTok{
 | 
| +		toks[i] = ds.KeyTok{
 | 
|  			Kind:     e.GetType(),
 | 
|  			IntID:    e.GetId(),
 | 
|  			StringID: e.GetName(),
 | 
| @@ -97,35 +99,35 @@ func KeyToksDecode(encoded string) (appID, namespace string, toks []KeyTok, err
 | 
|  	return
 | 
|  }
 | 
|  
 | 
| -// KeyMarshalJSON returns a MarshalJSON-compatible serialization of a Key.
 | 
| -func KeyMarshalJSON(k Key) ([]byte, error) {
 | 
| -	return []byte(`"` + KeyEncode(k) + `"`), nil
 | 
| +// MarshalJSON returns a MarshalJSON-compatible serialization of a Key.
 | 
| +func MarshalJSON(k ds.Key) ([]byte, error) {
 | 
| +	return []byte(`"` + Encode(k) + `"`), nil
 | 
|  }
 | 
|  
 | 
| -// KeyUnmarshalJSON returns the tokenized version of a Key as encoded by
 | 
| -// KeyMarshalJSON.
 | 
| -func KeyUnmarshalJSON(buf []byte) (appID, namespace string, toks []KeyTok, err error) {
 | 
| +// UnmarshalJSON returns the tokenized version of a ds.Key as encoded by
 | 
| +// MarshalJSON.
 | 
| +func UnmarshalJSON(buf []byte) (appID, namespace string, toks []ds.KeyTok, err error) {
 | 
|  	if len(buf) < 2 || buf[0] != '"' || buf[len(buf)-1] != '"' {
 | 
|  		err = errors.New("datastore: bad JSON key")
 | 
|  	} else {
 | 
| -		appID, namespace, toks, err = KeyToksDecode(string(buf[1 : len(buf)-1]))
 | 
| +		appID, namespace, toks, err = ToksDecode(string(buf[1 : len(buf)-1]))
 | 
|  	}
 | 
|  	return
 | 
|  }
 | 
|  
 | 
| -// KeyIncomplete returns true iff k doesn't have an id yet.
 | 
| -func KeyIncomplete(k Key) bool {
 | 
| +// Incomplete returns true iff k doesn't have an id yet.
 | 
| +func Incomplete(k ds.Key) bool {
 | 
|  	return k != nil && k.StringID() == "" && k.IntID() == 0
 | 
|  }
 | 
|  
 | 
| -// KeyValid determines if a key is valid, according to a couple rules:
 | 
| +// Valid determines if a key is valid, according to a couple rules:
 | 
|  //   - k is not nil
 | 
|  //   - every token of k:
 | 
|  //     - (if !allowSpecial) token's kind doesn't start with '__'
 | 
|  //     - token's kind and appid are non-blank
 | 
|  //     - token is not incomplete
 | 
|  //   - all tokens have the same namespace and appid
 | 
| -func KeyValid(k Key, allowSpecial bool, aid, ns string) bool {
 | 
| +func Valid(k ds.Key, allowSpecial bool, aid, ns string) bool {
 | 
|  	if k == nil {
 | 
|  		return false
 | 
|  	}
 | 
| @@ -143,7 +145,7 @@ func KeyValid(k Key, allowSpecial bool, aid, ns string) bool {
 | 
|  			return false
 | 
|  		}
 | 
|  		if k.Parent() != nil {
 | 
| -			if KeyIncomplete(k.Parent()) {
 | 
| +			if k.Parent().Incomplete() {
 | 
|  				return false
 | 
|  			}
 | 
|  			if k.Parent().AppID() != k.AppID() || k.Parent().Namespace() != k.Namespace() {
 | 
| @@ -154,16 +156,26 @@ func KeyValid(k Key, allowSpecial bool, aid, ns string) bool {
 | 
|  	return true
 | 
|  }
 | 
|  
 | 
| -// KeyRoot returns the entity root for the given key.
 | 
| -func KeyRoot(k Key) Key {
 | 
| +// PartialValid returns true iff this key is suitable for use in a Put
 | 
| +// operation. This is the same as Valid(k, false, ...), but also allowing k to
 | 
| +// be Incomplete().
 | 
| +func PartialValid(k ds.Key, aid, ns string) bool {
 | 
| +	if k.Incomplete() {
 | 
| +		k = New(k.AppID(), k.Namespace(), k.Kind(), "", 1, k.Parent())
 | 
| +	}
 | 
| +	return Valid(k, false, aid, ns)
 | 
| +}
 | 
| +
 | 
| +// Root returns the entity root for the given key.
 | 
| +func Root(k ds.Key) ds.Key {
 | 
|  	for k != nil && k.Parent() != nil {
 | 
|  		k = k.Parent()
 | 
|  	}
 | 
|  	return k
 | 
|  }
 | 
|  
 | 
| -// KeysEqual returns true iff the two keys represent identical key values.
 | 
| -func KeysEqual(a, b Key) (ret bool) {
 | 
| +// Equal returns true iff the two keys represent identical key values.
 | 
| +func Equal(a, b ds.Key) (ret bool) {
 | 
|  	ret = (a.Kind() == b.Kind() &&
 | 
|  		a.StringID() == b.StringID() &&
 | 
|  		a.IntID() == b.IntID() &&
 | 
| @@ -173,10 +185,10 @@ func KeysEqual(a, b Key) (ret bool) {
 | 
|  		return
 | 
|  	}
 | 
|  	ap, bp := a.Parent(), b.Parent()
 | 
| -	return (ap == nil && bp == nil) || KeysEqual(ap, bp)
 | 
| +	return (ap == nil && bp == nil) || Equal(ap, bp)
 | 
|  }
 | 
|  
 | 
| -func marshalDSKey(b *bytes.Buffer, k Key) {
 | 
| +func marshalDSKey(b *bytes.Buffer, k ds.Key) {
 | 
|  	if k.Parent() != nil {
 | 
|  		marshalDSKey(b, k.Parent())
 | 
|  	}
 | 
| @@ -190,9 +202,9 @@ func marshalDSKey(b *bytes.Buffer, k Key) {
 | 
|  	}
 | 
|  }
 | 
|  
 | 
| -// KeyString returns a human-readable representation of the key, and is the
 | 
| +// String returns a human-readable representation of the key, and is the
 | 
|  // typical implementation of Key.String() (though it isn't guaranteed to be)
 | 
| -func KeyString(k Key) string {
 | 
| +func String(k ds.Key) string {
 | 
|  	if k == nil {
 | 
|  		return ""
 | 
|  	}
 | 
| @@ -201,14 +213,14 @@ func KeyString(k Key) string {
 | 
|  	return b.String()
 | 
|  }
 | 
|  
 | 
| -// KeySplit splits the key into its constituent parts. Note that if the key is
 | 
| -// not KeyValid, this method may not provide a round-trip for k.
 | 
| -func KeySplit(k Key) (appID, namespace string, toks []KeyTok) {
 | 
| +// Split splits the key into its constituent parts. Note that if the key is
 | 
| +// not Valid, this method may not provide a round-trip for k.
 | 
| +func Split(k ds.Key) (appID, namespace string, toks []ds.KeyTok) {
 | 
|  	if k == nil {
 | 
|  		return
 | 
|  	}
 | 
|  
 | 
| -	if sk, ok := k.(*GenericKey); ok {
 | 
| +	if sk, ok := k.(*Generic); ok {
 | 
|  		if sk == nil {
 | 
|  			return
 | 
|  		}
 | 
| @@ -219,7 +231,7 @@ func KeySplit(k Key) (appID, namespace string, toks []KeyTok) {
 | 
|  	for i := k; i != nil; i = i.Parent() {
 | 
|  		n++
 | 
|  	}
 | 
| -	toks = make([]KeyTok, n)
 | 
| +	toks = make([]ds.KeyTok, n)
 | 
|  	for i := k; i != nil; i = i.Parent() {
 | 
|  		n--
 | 
|  		toks[n].IntID = i.IntID()
 | 
| 
 |