Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1112)

Side by Side Diff: service/datastore/key.go

Issue 2302743002: Interface update, per-method Contexts. (Closed)
Patch Set: Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The LUCI Authors. All rights reserved. 1 // Copyright 2015 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0 2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file. 3 // that can be found in the LICENSE file.
4 4
5 package datastore 5 package datastore
6 6
7 import ( 7 import (
8 "bytes" 8 "bytes"
9 "encoding/base64" 9 "encoding/base64"
10 "encoding/json" 10 "encoding/json"
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
46 func (k KeyTok) Less(other KeyTok) bool { 46 func (k KeyTok) Less(other KeyTok) bool {
47 if k.Kind < other.Kind { 47 if k.Kind < other.Kind {
48 return true 48 return true
49 } else if k.Kind > other.Kind { 49 } else if k.Kind > other.Kind {
50 return false 50 return false
51 } 51 }
52 a, b := k.ID(), other.ID() 52 a, b := k.ID(), other.ID()
53 return a.Less(&b) 53 return a.Less(&b)
54 } 54 }
55 55
56 // Key is the type used for all datastore operations. 56 // KeyContext is the context in which a key is generated.
dnj 2016/09/01 15:25:40 Major change here is that KeyContext was introduce
57 type Key struct { 57 type KeyContext struct {
58 » appID string 58 » AppID string
59 » namespace string 59 » Namespace string
60 » toks []KeyTok
61 } 60 }
62 61
63 var _ interface { 62 // Matches returns true iff the AppID and Namespace parameters are the same for
64 » json.Marshaler 63 // the two KeyContext instances.
65 » json.Unmarshaler 64 func (kc KeyContext) Matches(o KeyContext) bool {
66 } = (*Key)(nil) 65 » return (kc.AppID == o.AppID && kc.Namespace == o.Namespace)
66 }
67 67
68 // NewKeyToks creates a new Key. It is the Key implementation returned from the 68 // NewKeyToks creates a new Key. It is the Key implementation returned from
69 // various PropertyMap serialization routines, as well as the native key 69 // the various PropertyMap serialization routines, as well as the native key
70 // implementation for the in-memory implementation of gae. 70 // implementation for the in-memory implementation of gae.
71 // 71 //
72 // See Interface.NewKeyToks for a version of this function which automatically 72 // See NewKeyToks for a version of this function which automatically
73 // provides aid and ns. 73 // provides aid and ns.
74 func NewKeyToks(aid, ns string, toks []KeyTok) *Key { 74 func (kc KeyContext) NewKeyToks(toks []KeyTok) *Key {
75 if len(toks) == 0 { 75 if len(toks) == 0 {
76 return nil 76 return nil
77 } 77 }
78 newToks := make([]KeyTok, len(toks)) 78 newToks := make([]KeyTok, len(toks))
79 copy(newToks, toks) 79 copy(newToks, toks)
80 » return &Key{aid, ns, newToks} 80 » return &Key{kc, newToks}
81 } 81 }
82 82
83 // NewKey is a wrapper around NewToks which has an interface similar 83 // NewKey is a wrapper around NewToks which has an interface similar to NewKey
84 // to NewKey in the SDK. 84 // in the SDK.
85 // 85 //
86 // See Interface.NewKey for a version of this function which automatically 86 // See NewKey for a version of this function which automatically provides aid
87 // provides aid and ns. 87 // and ns.
88 func NewKey(aid, ns, kind, stringID string, intID int64, parent *Key) *Key { 88 func (kc KeyContext) NewKey(kind, stringID string, intID int64, parent *Key) *Ke y {
89 if parent == nil { 89 if parent == nil {
90 » » return &Key{aid, ns, []KeyTok{{kind, intID, stringID}}} 90 » » return &Key{kc, []KeyTok{{kind, intID, stringID}}}
91 } 91 }
92 92
93 toks := parent.toks 93 toks := parent.toks
94 newToks := make([]KeyTok, len(toks), len(toks)+1) 94 newToks := make([]KeyTok, len(toks), len(toks)+1)
95 copy(newToks, toks) 95 copy(newToks, toks)
96 newToks = append(newToks, KeyTok{kind, intID, stringID}) 96 newToks = append(newToks, KeyTok{kind, intID, stringID})
97 » return &Key{aid, ns, newToks} 97 » return &Key{kc, newToks}
98 } 98 }
99 99
100 // MakeKey is a convenience function for manufacturing a *Key. It should only 100 // MakeKey is a convenience function for manufacturing a *Key. It should only
101 // be used when elems... is known statically (e.g. in the code) to be correct. 101 // be used when elems... is known statically (e.g. in the code) to be correct.
102 // 102 //
103 // elems is pairs of (string, string|int|int32|int64) pairs, which correspond to 103 // elems is pairs of (string, string|int|int32|int64) pairs, which correspond to
104 // Kind/id pairs. Example: 104 // Kind/id pairs. Example:
105 // MakeKey("aid", "namespace", "Parent", 1, "Child", "id") 105 // KeyContext{"aid", "namespace"}.MakeKey("Parent", 1, "Child", "id")
106 // 106 //
107 // Would create the key: 107 // Would create the key:
108 // aid:namespace:/Parent,1/Child,id 108 // aid:namespace:/Parent,1/Child,id
109 // 109 //
110 // If elems is not parsable (e.g. wrong length, wrong types, etc.) this method 110 // If elems is not parsable (e.g. wrong length, wrong types, etc.) this method
111 // will panic. 111 // will panic.
112 // 112 //
113 // See Interface.MakeKey for a version of this function which automatically 113 // See MakeKey for a version of this function which automatically
114 // provides aid and ns. 114 // provides aid and ns.
115 func MakeKey(aid, ns string, elems ...interface{}) *Key { 115 func (kc KeyContext) MakeKey(elems ...interface{}) *Key {
116 if len(elems) == 0 { 116 if len(elems) == 0 {
117 return nil 117 return nil
118 } 118 }
119 119
120 if len(elems)%2 != 0 { 120 if len(elems)%2 != 0 {
121 panic(fmt.Errorf("datastore.MakeKey: odd number of tokens: %v", elems)) 121 panic(fmt.Errorf("datastore.MakeKey: odd number of tokens: %v", elems))
122 } 122 }
123 123
124 toks := make([]KeyTok, len(elems)/2) 124 toks := make([]KeyTok, len(elems)/2)
125 for i := 0; len(elems) > 0; i, elems = i+1, elems[2:] { 125 for i := 0; len(elems) > 0; i, elems = i+1, elems[2:] {
(...skipping 14 matching lines...) Expand all
140 t.IntID = int64(x) 140 t.IntID = int64(x)
141 case uint16: 141 case uint16:
142 t.IntID = int64(x) 142 t.IntID = int64(x)
143 case uint32: 143 case uint32:
144 t.IntID = int64(x) 144 t.IntID = int64(x)
145 default: 145 default:
146 panic(fmt.Errorf("datastore.MakeKey: bad id: %v", x)) 146 panic(fmt.Errorf("datastore.MakeKey: bad id: %v", x))
147 } 147 }
148 } 148 }
149 149
150 » return NewKeyToks(aid, ns, toks) 150 » return kc.NewKeyToks(toks)
151 } 151 }
152 152
153 // Key is the type used for all datastore operations.
154 type Key struct {
155 kc KeyContext
156 toks []KeyTok
157 }
158
159 var _ interface {
160 json.Marshaler
161 json.Unmarshaler
162 } = (*Key)(nil)
163
153 // NewKeyEncoded decodes and returns a *Key 164 // NewKeyEncoded decodes and returns a *Key
154 func NewKeyEncoded(encoded string) (ret *Key, err error) { 165 func NewKeyEncoded(encoded string) (ret *Key, err error) {
155 ret = &Key{} 166 ret = &Key{}
156 // Re-add padding 167 // Re-add padding
157 if m := len(encoded) % 4; m != 0 { 168 if m := len(encoded) % 4; m != 0 {
158 encoded += strings.Repeat("=", 4-m) 169 encoded += strings.Repeat("=", 4-m)
159 } 170 }
160 b, err := base64.URLEncoding.DecodeString(encoded) 171 b, err := base64.URLEncoding.DecodeString(encoded)
161 if err != nil { 172 if err != nil {
162 return 173 return
163 } 174 }
164 175
165 r := &pb.Reference{} 176 r := &pb.Reference{}
166 if err = proto.Unmarshal(b, r); err != nil { 177 if err = proto.Unmarshal(b, r); err != nil {
167 return 178 return
168 } 179 }
169 180
170 » ret.appID = r.GetApp() 181 » ret.kc = KeyContext{
171 » ret.namespace = r.GetNameSpace() 182 » » AppID: r.GetApp(),
183 » » Namespace: r.GetNameSpace(),
184 » }
172 ret.toks = make([]KeyTok, len(r.Path.Element)) 185 ret.toks = make([]KeyTok, len(r.Path.Element))
173 for i, e := range r.Path.Element { 186 for i, e := range r.Path.Element {
174 ret.toks[i] = KeyTok{ 187 ret.toks[i] = KeyTok{
175 Kind: e.GetType(), 188 Kind: e.GetType(),
176 IntID: e.GetId(), 189 IntID: e.GetId(),
177 StringID: e.GetName(), 190 StringID: e.GetName(),
178 } 191 }
179 } 192 }
180 return 193 return
181 } 194 }
182 195
183 // LastTok returns the last KeyTok in this Key. Non-nil Keys are always guarante ed 196 // LastTok returns the last KeyTok in this Key. Non-nil Keys are always guarante ed
184 // to have at least one token. 197 // to have at least one token.
185 func (k *Key) LastTok() KeyTok { 198 func (k *Key) LastTok() KeyTok {
186 return k.toks[len(k.toks)-1] 199 return k.toks[len(k.toks)-1]
187 } 200 }
188 201
189 // AppID returns the application ID that this Key is for. 202 // AppID returns the application ID that this Key is for.
190 func (k *Key) AppID() string { return k.appID } 203 func (k *Key) AppID() string { return k.kc.AppID }
191 204
192 // Namespace returns the namespace that this Key is for. 205 // Namespace returns the namespace that this Key is for.
193 func (k *Key) Namespace() string { return k.namespace } 206 func (k *Key) Namespace() string { return k.kc.Namespace }
207
208 // KeyContext returns the KeyContext that this Key is using.
209 func (k *Key) KeyContext() *KeyContext {
210 » kc := k.kc
211 » return &kc
212 }
194 213
195 // Kind returns the Kind of the child KeyTok 214 // Kind returns the Kind of the child KeyTok
196 func (k *Key) Kind() string { return k.toks[len(k.toks)-1].Kind } 215 func (k *Key) Kind() string { return k.toks[len(k.toks)-1].Kind }
197 216
198 // StringID returns the StringID of the child KeyTok 217 // StringID returns the StringID of the child KeyTok
199 func (k *Key) StringID() string { return k.toks[len(k.toks)-1].StringID } 218 func (k *Key) StringID() string { return k.toks[len(k.toks)-1].StringID }
200 219
201 // IntID returns the IntID of the child KeyTok 220 // IntID returns the IntID of the child KeyTok
202 func (k *Key) IntID() int64 { return k.toks[len(k.toks)-1].IntID } 221 func (k *Key) IntID() int64 { return k.toks[len(k.toks)-1].IntID }
203 222
204 // String returns a human-readable representation of the key in the form of 223 // String returns a human-readable representation of the key in the form of
205 // AID:NS:/Kind,id/Kind,id/... 224 // AID:NS:/Kind,id/Kind,id/...
206 func (k *Key) String() string { 225 func (k *Key) String() string {
207 b := bytes.NewBuffer(make([]byte, 0, 512)) 226 b := bytes.NewBuffer(make([]byte, 0, 512))
208 » fmt.Fprintf(b, "%s:%s:", k.appID, k.namespace) 227 » fmt.Fprintf(b, "%s:%s:", k.kc.AppID, k.kc.Namespace)
209 for _, t := range k.toks { 228 for _, t := range k.toks {
210 if t.StringID != "" { 229 if t.StringID != "" {
211 fmt.Fprintf(b, "/%s,%q", t.Kind, t.StringID) 230 fmt.Fprintf(b, "/%s,%q", t.Kind, t.StringID)
212 } else { 231 } else {
213 fmt.Fprintf(b, "/%s,%d", t.Kind, t.IntID) 232 fmt.Fprintf(b, "/%s,%d", t.Kind, t.IntID)
214 } 233 }
215 } 234 }
216 return b.String() 235 return b.String()
217 } 236 }
218 237
219 // IsIncomplete returns true iff k doesn't have an id yet. 238 // IsIncomplete returns true iff k doesn't have an id yet.
220 func (k *Key) IsIncomplete() bool { 239 func (k *Key) IsIncomplete() bool {
221 return k.LastTok().IsIncomplete() 240 return k.LastTok().IsIncomplete()
222 } 241 }
223 242
224 // Valid determines if a key is valid, according to a couple rules: 243 // Valid determines if a key is valid, according to a couple of rules:
225 // - k is not nil 244 // - k is not nil
226 // - every token of k: 245 // - every token of k:
227 // - (if !allowSpecial) token's kind doesn't start with '__' 246 // - (if !allowSpecial) token's kind doesn't start with '__'
228 // - token's kind and appid are non-blank 247 // - token's kind and appid are non-blank
229 // - token is not incomplete 248 // - token is not incomplete
230 // - all tokens have the same namespace and appid 249 // - all tokens have the same namespace and appid
231 func (k *Key) Valid(allowSpecial bool, aid, ns string) bool { 250 func (k *Key) Valid(allowSpecial bool, kc KeyContext) bool {
232 » if aid != k.appID || ns != k.namespace { 251 » if !kc.Matches(k.kc) {
233 return false 252 return false
234 } 253 }
235 for _, t := range k.toks { 254 for _, t := range k.toks {
236 if t.IsIncomplete() { 255 if t.IsIncomplete() {
237 return false 256 return false
238 } 257 }
239 if !allowSpecial && t.Special() { 258 if !allowSpecial && t.Special() {
240 return false 259 return false
241 } 260 }
242 if t.Kind == "" { 261 if t.Kind == "" {
243 return false 262 return false
244 } 263 }
245 if t.StringID != "" && t.IntID != 0 { 264 if t.StringID != "" && t.IntID != 0 {
246 return false 265 return false
247 } 266 }
248 } 267 }
249 return true 268 return true
250 } 269 }
251 270
252 // PartialValid returns true iff this key is suitable for use in a Put 271 // PartialValid returns true iff this key is suitable for use in a Put
253 // operation. This is the same as Valid(k, false, ...), but also allowing k to 272 // operation. This is the same as Valid(k, false, ...), but also allowing k to
254 // be IsIncomplete(). 273 // be IsIncomplete().
255 func (k *Key) PartialValid(aid, ns string) bool { 274 func (k *Key) PartialValid(kc KeyContext) bool {
256 if k.IsIncomplete() { 275 if k.IsIncomplete() {
257 » » k = NewKey(k.AppID(), k.Namespace(), k.Kind(), "", 1, k.Parent() ) 276 » » if !kc.Matches(k.kc) {
277 » » » return false
278 » » }
279 » » k = kc.NewKey(k.Kind(), "", 1, k.Parent())
258 } 280 }
259 » return k.Valid(false, aid, ns) 281 » return k.Valid(false, kc)
260 } 282 }
261 283
262 // Parent returns the parent Key of this *Key, or nil. The parent 284 // Parent returns the parent Key of this *Key, or nil. The parent
263 // will always have the concrete type of *Key. 285 // will always have the concrete type of *Key.
264 func (k *Key) Parent() *Key { 286 func (k *Key) Parent() *Key {
265 if len(k.toks) <= 1 { 287 if len(k.toks) <= 1 {
266 return nil 288 return nil
267 } 289 }
268 » return &Key{k.appID, k.namespace, k.toks[:len(k.toks)-1]} 290 » return k.kc.NewKeyToks(k.toks[:len(k.toks)-1])
269 } 291 }
270 292
271 // MarshalJSON allows this key to be automatically marshaled by encoding/json. 293 // MarshalJSON allows this key to be automatically marshaled by encoding/json.
272 func (k *Key) MarshalJSON() ([]byte, error) { 294 func (k *Key) MarshalJSON() ([]byte, error) {
273 return []byte(`"` + k.Encode() + `"`), nil 295 return []byte(`"` + k.Encode() + `"`), nil
274 } 296 }
275 297
276 // Encode encodes the provided key as a base64-encoded protobuf. 298 // Encode encodes the provided key as a base64-encoded protobuf.
277 // 299 //
278 // This encoding is compatible with the SDK-provided encoding and is agnostic 300 // This encoding is compatible with the SDK-provided encoding and is agnostic
279 // to the underlying implementation of the Key. 301 // to the underlying implementation of the Key.
280 // 302 //
281 // It's encoded with the urlsafe base64 table without padding. 303 // It's encoded with the urlsafe base64 table without padding.
282 func (k *Key) Encode() string { 304 func (k *Key) Encode() string {
283 e := make([]*pb.Path_Element, len(k.toks)) 305 e := make([]*pb.Path_Element, len(k.toks))
284 for i, t := range k.toks { 306 for i, t := range k.toks {
285 t := t 307 t := t
286 e[i] = &pb.Path_Element{ 308 e[i] = &pb.Path_Element{
287 Type: &t.Kind, 309 Type: &t.Kind,
288 } 310 }
289 if t.StringID != "" { 311 if t.StringID != "" {
290 e[i].Name = &t.StringID 312 e[i].Name = &t.StringID
291 } else { 313 } else {
292 e[i].Id = &t.IntID 314 e[i].Id = &t.IntID
293 } 315 }
294 } 316 }
295 var namespace *string 317 var namespace *string
296 » if k.namespace != "" { 318 » if ns := k.kc.Namespace; ns != "" {
297 » » namespace = &k.namespace 319 » » namespace = &ns
298 } 320 }
299 r, err := proto.Marshal(&pb.Reference{ 321 r, err := proto.Marshal(&pb.Reference{
300 » » App: &k.appID, 322 » » App: &k.kc.AppID,
301 NameSpace: namespace, 323 NameSpace: namespace,
302 Path: &pb.Path{ 324 Path: &pb.Path{
303 Element: e, 325 Element: e,
304 }, 326 },
305 }) 327 })
306 if err != nil { 328 if err != nil {
307 panic(err) 329 panic(err)
308 } 330 }
309 331
310 // trim padding 332 // trim padding
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
344 if len(k.toks) > 1 { 366 if len(k.toks) > 1 {
345 ret := *k 367 ret := *k
346 ret.toks = ret.toks[:1] 368 ret.toks = ret.toks[:1]
347 return &ret 369 return &ret
348 } 370 }
349 return k 371 return k
350 } 372 }
351 373
352 // Less returns true iff k would sort before other. 374 // Less returns true iff k would sort before other.
353 func (k *Key) Less(other *Key) bool { 375 func (k *Key) Less(other *Key) bool {
354 » if k.appID < other.appID { 376 » if k.kc.AppID < other.kc.AppID {
355 return true 377 return true
356 » } else if k.appID > other.appID { 378 » } else if k.kc.AppID > other.kc.AppID {
357 return false 379 return false
358 } 380 }
359 381
360 » if k.namespace < other.namespace { 382 » if k.kc.Namespace < other.kc.Namespace {
361 return true 383 return true
362 » } else if k.namespace > other.namespace { 384 » } else if k.kc.Namespace > other.kc.Namespace {
363 return false 385 return false
364 } 386 }
365 387
366 lim := len(k.toks) 388 lim := len(k.toks)
367 if len(other.toks) < lim { 389 if len(other.toks) < lim {
368 lim = len(other.toks) 390 lim = len(other.toks)
369 } 391 }
370 for i := 0; i < lim; i++ { 392 for i := 0; i < lim; i++ {
371 a, b := k.toks[i], other.toks[i] 393 a, b := k.toks[i], other.toks[i]
372 if a.Less(b) { 394 if a.Less(b) {
373 return true 395 return true
374 } else if b.Less(a) { 396 } else if b.Less(a) {
375 return false 397 return false
376 } 398 }
377 } 399 }
378 return len(k.toks) < len(other.toks) 400 return len(k.toks) < len(other.toks)
379 } 401 }
380 402
381 // HasAncestor returns true iff other is an ancestor of k (or if other == k). 403 // HasAncestor returns true iff other is an ancestor of k (or if other == k).
382 func (k *Key) HasAncestor(other *Key) bool { 404 func (k *Key) HasAncestor(other *Key) bool {
383 » if k.appID != other.appID || k.namespace != other.namespace { 405 » if !k.kc.Matches(other.kc) {
384 return false 406 return false
385 } 407 }
386 if len(k.toks) < len(other.toks) { 408 if len(k.toks) < len(other.toks) {
387 return false 409 return false
388 } 410 }
389 for i, tok := range other.toks { 411 for i, tok := range other.toks {
390 if tok != k.toks[i] { 412 if tok != k.toks[i] {
391 return false 413 return false
392 } 414 }
393 } 415 }
394 return true 416 return true
395 } 417 }
396 418
397 // GQL returns a correctly formatted Cloud Datastore GQL key literal. 419 // GQL returns a correctly formatted Cloud Datastore GQL key literal.
398 // 420 //
399 // The flavor of GQL that this emits is defined here: 421 // The flavor of GQL that this emits is defined here:
400 // https://cloud.google.com/datastore/docs/apis/gql/gql_reference 422 // https://cloud.google.com/datastore/docs/apis/gql/gql_reference
401 func (k *Key) GQL() string { 423 func (k *Key) GQL() string {
402 ret := &bytes.Buffer{} 424 ret := &bytes.Buffer{}
403 » fmt.Fprintf(ret, "KEY(DATASET(%s)", gqlQuoteString(k.appID)) 425 » fmt.Fprintf(ret, "KEY(DATASET(%s)", gqlQuoteString(k.kc.AppID))
404 » if k.namespace != "" { 426 » if ns := k.kc.Namespace; ns != "" {
405 » » fmt.Fprintf(ret, ", NAMESPACE(%s)", gqlQuoteString(k.namespace)) 427 » » fmt.Fprintf(ret, ", NAMESPACE(%s)", gqlQuoteString(ns))
406 } 428 }
407 for _, t := range k.toks { 429 for _, t := range k.toks {
408 if t.IntID != 0 { 430 if t.IntID != 0 {
409 fmt.Fprintf(ret, ", %s, %d", gqlQuoteString(t.Kind), t.I ntID) 431 fmt.Fprintf(ret, ", %s, %d", gqlQuoteString(t.Kind), t.I ntID)
410 } else { 432 } else {
411 fmt.Fprintf(ret, ", %s, %s", gqlQuoteString(t.Kind), gql QuoteString(t.StringID)) 433 fmt.Fprintf(ret, ", %s, %s", gqlQuoteString(t.Kind), gql QuoteString(t.StringID))
412 } 434 }
413 } 435 }
414 if _, err := ret.WriteString(")"); err != nil { 436 if _, err := ret.WriteString(")"); err != nil {
415 panic(err) 437 panic(err)
416 } 438 }
417 return ret.String() 439 return ret.String()
418 } 440 }
419 441
420 // Equal returns true iff the two keys represent identical key values. 442 // Equal returns true iff the two keys represent identical key values.
421 func (k *Key) Equal(other *Key) bool { 443 func (k *Key) Equal(other *Key) bool {
422 return k.IncompleteEqual(other) && (k.LastTok() == other.LastTok()) 444 return k.IncompleteEqual(other) && (k.LastTok() == other.LastTok())
423 } 445 }
424 446
425 // IncompleteEqual asserts that, were the two keys incomplete, they would be 447 // IncompleteEqual asserts that, were the two keys incomplete, they would be
426 // equal. 448 // equal.
427 // 449 //
428 // This asserts equality for the full lineage of the key, except for its last 450 // This asserts equality for the full lineage of the key, except for its last
429 // token ID. 451 // token ID.
430 func (k *Key) IncompleteEqual(other *Key) (ret bool) { 452 func (k *Key) IncompleteEqual(other *Key) (ret bool) {
431 » ret = (k.appID == other.appID && 453 » ret = (k.kc.Matches(other.kc) &&
432 » » k.namespace == other.namespace &&
433 len(k.toks) == len(other.toks)) 454 len(k.toks) == len(other.toks))
434 if ret { 455 if ret {
435 for i, t := range k.toks { 456 for i, t := range k.toks {
436 if i == len(k.toks)-1 { 457 if i == len(k.toks)-1 {
437 // Last token: check only Kind. 458 // Last token: check only Kind.
438 if ret = (t.Kind == other.toks[i].Kind); !ret { 459 if ret = (t.Kind == other.toks[i].Kind); !ret {
439 return 460 return
440 } 461 }
441 } else { 462 } else {
442 if ret = t == other.toks[i]; !ret { 463 if ret = t == other.toks[i]; !ret {
443 return 464 return
444 } 465 }
445 } 466 }
446 } 467 }
447 } 468 }
448 return 469 return
449 } 470 }
450 471
451 // Incomplete returns an incomplete version of the key. The ID fields of the 472 // Incomplete returns an incomplete version of the key. The ID fields of the
452 // last token will be set to zero/empty. 473 // last token will be set to zero/empty.
453 func (k *Key) Incomplete() *Key { 474 func (k *Key) Incomplete() *Key {
454 if k.IsIncomplete() { 475 if k.IsIncomplete() {
455 return k 476 return k
456 } 477 }
457 » return NewKey(k.appID, k.namespace, k.Kind(), "", 0, k.Parent()) 478 » return k.kc.NewKey(k.Kind(), "", 0, k.Parent())
458 } 479 }
459 480
460 // WithID returns the key generated by setting the ID of its last token to 481 // WithID returns the key generated by setting the ID of its last token to
461 // the specified value. 482 // the specified value.
462 // 483 //
463 // To generate this, k is reduced to its Incomplete form, then populated with a 484 // To generate this, k is reduced to its Incomplete form, then populated with a
464 // new ID. The resulting key will have the same token linage as k (i.e., will 485 // new ID. The resulting key will have the same token linage as k (i.e., will
465 // be IncompleteEqual). 486 // be IncompleteEqual).
466 func (k *Key) WithID(stringID string, intID int64) *Key { 487 func (k *Key) WithID(stringID string, intID int64) *Key {
467 if k.StringID() == stringID && k.IntID() == intID { 488 if k.StringID() == stringID && k.IntID() == intID {
468 return k 489 return k
469 } 490 }
470 » return NewKey(k.appID, k.namespace, k.Kind(), stringID, intID, k.Parent( )) 491 » return k.kc.NewKey(k.Kind(), stringID, intID, k.Parent())
471 } 492 }
472 493
473 // Split componentizes the key into pieces (AppID, Namespace and tokens) 494 // Split componentizes the key into pieces (AppID, Namespace and tokens)
474 // 495 //
475 // Each token represents one piece of they key's 'path'. 496 // Each token represents one piece of they key's 'path'.
476 // 497 //
477 // toks is guaranteed to be empty if and only if k is nil. If k is non-nil then 498 // toks is guaranteed to be empty if and only if k is nil. If k is non-nil then
478 // it contains at least one token. 499 // it contains at least one token.
479 func (k *Key) Split() (appID, namespace string, toks []KeyTok) { 500 func (k *Key) Split() (appID, namespace string, toks []KeyTok) {
480 » appID = k.appID 501 » appID = k.kc.AppID
481 » namespace = k.namespace 502 » namespace = k.kc.Namespace
482 toks = make([]KeyTok, len(k.toks)) 503 toks = make([]KeyTok, len(k.toks))
483 copy(toks, k.toks) 504 copy(toks, k.toks)
484 return 505 return
485 } 506 }
486 507
487 // EstimateSize estimates the size of a Key. 508 // EstimateSize estimates the size of a Key.
488 // 509 //
489 // It uses https://cloud.google.com/appengine/articles/storage_breakdown?csw=1 510 // It uses https://cloud.google.com/appengine/articles/storage_breakdown?csw=1
490 // as a guide for these values. 511 // as a guide for these values.
491 func (k *Key) EstimateSize() int64 { 512 func (k *Key) EstimateSize() int64 {
492 » ret := int64(len(k.appID)) 513 » ret := int64(len(k.kc.AppID))
493 » ret += int64(len(k.namespace)) 514 » ret += int64(len(k.kc.Namespace))
494 for _, t := range k.toks { 515 for _, t := range k.toks {
495 ret += int64(len(t.Kind)) 516 ret += int64(len(t.Kind))
496 if t.StringID != "" { 517 if t.StringID != "" {
497 ret += int64(len(t.StringID)) 518 ret += int64(len(t.StringID))
498 } else { 519 } else {
499 ret += 8 520 ret += 8
500 } 521 }
501 } 522 }
502 return ret 523 return ret
503 } 524 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698