Chromium Code Reviews| Index: service/datastore/dskey/key.go |
| diff --git a/service/datastore/key.go b/service/datastore/dskey/key.go |
| similarity index 65% |
| rename from service/datastore/key.go |
| rename to service/datastore/dskey/key.go |
| index 0e588754b8af7f2af8fbf6601d28f60d28282282..96de9b8fcc765fd456c0f2b855c1a556389f2aad 100644 |
| --- a/service/datastore/key.go |
| +++ b/service/datastore/dskey/key.go |
| @@ -4,25 +4,26 @@ |
| // adapted from github.com/golang/appengine/datastore |
| -package datastore |
| +package dskey |
| import ( |
| "bytes" |
| "encoding/base64" |
| "errors" |
| + "fmt" |
| "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. |
|
dnj (Google)
2015/08/14 21:19:50
(Probably good to mention that it's URLencoded bas
iannucci
2015/08/14 22:13:03
it's not url encoded, it's encoded using the urlsa
dnj (Google)
2015/08/14 22:23:16
Yeah sorry that is what I meant.
|
| // |
| // This encoding is compatible with the SDK-provided encoding and is agnostic |
| // to the underlying implementation of the Key. |
| -func KeyEncode(k Key) string { |
| +func Encode(k ds.Key) string { |
| n := 0 |
| for i := k; i != nil; i = i.Parent() { |
| n++ |
| @@ -63,13 +64,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 +87,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 +98,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 +144,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 +155,27 @@ 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()) |
| + fmt.Println(k.String(), aid == k.AppID(), ns == k.Namespace(), k.Kind(), k.StringID(), k.IntID()) |
| + } |
| + 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() |