Index: service/datastore/key.go |
diff --git a/service/datastore/key.go b/service/datastore/key.go |
index faa6ab711806ce121f94d13dd638b1cc5b57655d..4b11735f6a8e7be2a2b6e4da1b00dac23b9c4e35 100644 |
--- a/service/datastore/key.go |
+++ b/service/datastore/key.go |
@@ -23,9 +23,9 @@ type KeyTok struct { |
StringID string |
} |
-// Incomplete returns true iff this token doesn't define either a StringID or |
+// IsIncomplete returns true iff this token doesn't define either a StringID or |
// an IntID. |
-func (k KeyTok) Incomplete() bool { |
+func (k KeyTok) IsIncomplete() bool { |
return k.StringID == "" && k.IntID == 0 |
} |
@@ -216,9 +216,9 @@ func (k *Key) String() string { |
return b.String() |
} |
-// Incomplete returns true iff k doesn't have an id yet. |
-func (k *Key) Incomplete() bool { |
- return k.LastTok().Incomplete() |
+// IsIncomplete returns true iff k doesn't have an id yet. |
+func (k *Key) IsIncomplete() bool { |
+ return k.LastTok().IsIncomplete() |
} |
// Valid determines if a key is valid, according to a couple rules: |
@@ -233,7 +233,7 @@ func (k *Key) Valid(allowSpecial bool, aid, ns string) bool { |
return false |
} |
for _, t := range k.toks { |
- if t.Incomplete() { |
+ if t.IsIncomplete() { |
return false |
} |
if !allowSpecial && t.Special() { |
@@ -251,9 +251,9 @@ func (k *Key) Valid(allowSpecial bool, aid, ns string) bool { |
// 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(). |
+// be IsIncomplete(). |
func (k *Key) PartialValid(aid, ns string) bool { |
- if k.Incomplete() { |
+ if k.IsIncomplete() { |
k = NewKey(k.AppID(), k.Namespace(), k.Kind(), "", 1, k.Parent()) |
} |
return k.Valid(false, aid, ns) |
@@ -418,20 +418,58 @@ func (k *Key) GQL() string { |
} |
// Equal returns true iff the two keys represent identical key values. |
-func (k *Key) Equal(other *Key) (ret bool) { |
+func (k *Key) Equal(other *Key) bool { |
+ return k.IncompleteEqual(other) && (k.LastTok() == other.LastTok()) |
+} |
+ |
+// IncompleteEqual asserts that, were the two keys incomplete, they would be |
+// equal. |
+// |
+// This asserts equality for the full lineage of the key, except for its last |
+// token ID. |
+func (k *Key) IncompleteEqual(other *Key) (ret bool) { |
ret = (k.appID == other.appID && |
k.namespace == other.namespace && |
len(k.toks) == len(other.toks)) |
if ret { |
for i, t := range k.toks { |
- if ret = t == other.toks[i]; !ret { |
- return |
+ if i == len(k.toks)-1 { |
+ // Last token: check only Kind. |
+ if ret = (t.Kind == other.toks[i].Kind); !ret { |
+ return |
+ } |
+ } else { |
+ if ret = t == other.toks[i]; !ret { |
+ return |
+ } |
} |
} |
} |
return |
} |
+// Incomplete returns an incomplete version of the key. The ID fields of the |
+// last token will be set to zero/empty. |
+func (k *Key) Incomplete() *Key { |
+ if k.IsIncomplete() { |
+ return k |
+ } |
+ return NewKey(k.appID, k.namespace, k.Kind(), "", 0, k.Parent()) |
+} |
+ |
+// WithID returns the key generated by setting the ID of its last token to |
+// the specified value. |
+// |
+// To generate this, k is reduced to its Incomplete form, then populated with a |
+// new ID. The resulting key will have the same token linage as k (i.e., will |
+// be IncompleteEqual). |
+func (k *Key) WithID(stringID string, intID int64) *Key { |
+ if k.StringID() == stringID && k.IntID() == intID { |
+ return k |
+ } |
+ return NewKey(k.appID, k.namespace, k.Kind(), stringID, intID, k.Parent()) |
+} |
+ |
// Split componentizes the key into pieces (AppID, Namespace and tokens) |
// |
// Each token represents one piece of they key's 'path'. |