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

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

Issue 2007123002: datastore: Update AllocateIDs to take keys. (Closed) Base URL: https://chromium.googlesource.com/external/github.com/luci/gae@master
Patch Set: Rebase, comments. Created 4 years, 6 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
« no previous file with comments | « service/datastore/interface.go ('k') | service/datastore/key_test.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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"
11 "errors" 11 "errors"
12 "fmt" 12 "fmt"
13 "strings" 13 "strings"
14 14
15 "github.com/golang/protobuf/proto" 15 "github.com/golang/protobuf/proto"
16 pb "github.com/luci/gae/service/datastore/internal/protos/datastore" 16 pb "github.com/luci/gae/service/datastore/internal/protos/datastore"
17 ) 17 )
18 18
19 // KeyTok is a single token from a multi-part Key. 19 // KeyTok is a single token from a multi-part Key.
20 type KeyTok struct { 20 type KeyTok struct {
21 Kind string 21 Kind string
22 IntID int64 22 IntID int64
23 StringID string 23 StringID string
24 } 24 }
25 25
26 // Incomplete returns true iff this token doesn't define either a StringID or 26 // IsIncomplete returns true iff this token doesn't define either a StringID or
27 // an IntID. 27 // an IntID.
28 func (k KeyTok) Incomplete() bool { 28 func (k KeyTok) IsIncomplete() bool {
29 return k.StringID == "" && k.IntID == 0 29 return k.StringID == "" && k.IntID == 0
30 } 30 }
31 31
32 // Special returns true iff this token begins and ends with "__" 32 // Special returns true iff this token begins and ends with "__"
33 func (k KeyTok) Special() bool { 33 func (k KeyTok) Special() bool {
34 return len(k.Kind) >= 2 && k.Kind[:2] == "__" && k.Kind[len(k.Kind)-2:] == "__" 34 return len(k.Kind) >= 2 && k.Kind[:2] == "__" && k.Kind[len(k.Kind)-2:] == "__"
35 } 35 }
36 36
37 // ID returns the 'active' id as a Property (either the StringID or the IntID). 37 // ID returns the 'active' id as a Property (either the StringID or the IntID).
38 func (k KeyTok) ID() Property { 38 func (k KeyTok) ID() Property {
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after
209 for _, t := range k.toks { 209 for _, t := range k.toks {
210 if t.StringID != "" { 210 if t.StringID != "" {
211 fmt.Fprintf(b, "/%s,%q", t.Kind, t.StringID) 211 fmt.Fprintf(b, "/%s,%q", t.Kind, t.StringID)
212 } else { 212 } else {
213 fmt.Fprintf(b, "/%s,%d", t.Kind, t.IntID) 213 fmt.Fprintf(b, "/%s,%d", t.Kind, t.IntID)
214 } 214 }
215 } 215 }
216 return b.String() 216 return b.String()
217 } 217 }
218 218
219 // Incomplete returns true iff k doesn't have an id yet. 219 // IsIncomplete returns true iff k doesn't have an id yet.
220 func (k *Key) Incomplete() bool { 220 func (k *Key) IsIncomplete() bool {
221 » return k.LastTok().Incomplete() 221 » return k.LastTok().IsIncomplete()
222 } 222 }
223 223
224 // Valid determines if a key is valid, according to a couple rules: 224 // Valid determines if a key is valid, according to a couple rules:
225 // - k is not nil 225 // - k is not nil
226 // - every token of k: 226 // - every token of k:
227 // - (if !allowSpecial) token's kind doesn't start with '__' 227 // - (if !allowSpecial) token's kind doesn't start with '__'
228 // - token's kind and appid are non-blank 228 // - token's kind and appid are non-blank
229 // - token is not incomplete 229 // - token is not incomplete
230 // - all tokens have the same namespace and appid 230 // - all tokens have the same namespace and appid
231 func (k *Key) Valid(allowSpecial bool, aid, ns string) bool { 231 func (k *Key) Valid(allowSpecial bool, aid, ns string) bool {
232 if aid != k.appID || ns != k.namespace { 232 if aid != k.appID || ns != k.namespace {
233 return false 233 return false
234 } 234 }
235 for _, t := range k.toks { 235 for _, t := range k.toks {
236 » » if t.Incomplete() { 236 » » if t.IsIncomplete() {
237 return false 237 return false
238 } 238 }
239 if !allowSpecial && t.Special() { 239 if !allowSpecial && t.Special() {
240 return false 240 return false
241 } 241 }
242 if t.Kind == "" { 242 if t.Kind == "" {
243 return false 243 return false
244 } 244 }
245 if t.StringID != "" && t.IntID != 0 { 245 if t.StringID != "" && t.IntID != 0 {
246 return false 246 return false
247 } 247 }
248 } 248 }
249 return true 249 return true
250 } 250 }
251 251
252 // PartialValid returns true iff this key is suitable for use in a Put 252 // 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 253 // operation. This is the same as Valid(k, false, ...), but also allowing k to
254 // be Incomplete(). 254 // be IsIncomplete().
255 func (k *Key) PartialValid(aid, ns string) bool { 255 func (k *Key) PartialValid(aid, ns string) bool {
256 » if k.Incomplete() { 256 » if k.IsIncomplete() {
257 k = NewKey(k.AppID(), k.Namespace(), k.Kind(), "", 1, k.Parent() ) 257 k = NewKey(k.AppID(), k.Namespace(), k.Kind(), "", 1, k.Parent() )
258 } 258 }
259 return k.Valid(false, aid, ns) 259 return k.Valid(false, aid, ns)
260 } 260 }
261 261
262 // Parent returns the parent Key of this *Key, or nil. The parent 262 // Parent returns the parent Key of this *Key, or nil. The parent
263 // will always have the concrete type of *Key. 263 // will always have the concrete type of *Key.
264 func (k *Key) Parent() *Key { 264 func (k *Key) Parent() *Key {
265 if len(k.toks) <= 1 { 265 if len(k.toks) <= 1 {
266 return nil 266 return nil
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
411 fmt.Fprintf(ret, ", %s, %s", gqlQuoteString(t.Kind), gql QuoteString(t.StringID)) 411 fmt.Fprintf(ret, ", %s, %s", gqlQuoteString(t.Kind), gql QuoteString(t.StringID))
412 } 412 }
413 } 413 }
414 if _, err := ret.WriteString(")"); err != nil { 414 if _, err := ret.WriteString(")"); err != nil {
415 panic(err) 415 panic(err)
416 } 416 }
417 return ret.String() 417 return ret.String()
418 } 418 }
419 419
420 // Equal returns true iff the two keys represent identical key values. 420 // Equal returns true iff the two keys represent identical key values.
421 func (k *Key) Equal(other *Key) (ret bool) { 421 func (k *Key) Equal(other *Key) bool {
422 » return k.IncompleteEqual(other) && (k.LastTok() == other.LastTok())
423 }
424
425 // IncompleteEqual asserts that, were the two keys incomplete, they would be
426 // equal.
427 //
428 // This asserts equality for the full lineage of the key, except for its last
429 // token ID.
430 func (k *Key) IncompleteEqual(other *Key) (ret bool) {
422 ret = (k.appID == other.appID && 431 ret = (k.appID == other.appID &&
423 k.namespace == other.namespace && 432 k.namespace == other.namespace &&
424 len(k.toks) == len(other.toks)) 433 len(k.toks) == len(other.toks))
425 if ret { 434 if ret {
426 for i, t := range k.toks { 435 for i, t := range k.toks {
427 » » » if ret = t == other.toks[i]; !ret { 436 » » » if i == len(k.toks)-1 {
428 » » » » return 437 » » » » // Last token: check only Kind.
438 » » » » if ret = (t.Kind == other.toks[i].Kind); !ret {
439 » » » » » return
440 » » » » }
441 » » » } else {
442 » » » » if ret = t == other.toks[i]; !ret {
443 » » » » » return
444 » » » » }
429 } 445 }
430 } 446 }
431 } 447 }
432 return 448 return
433 } 449 }
434 450
451 // Incomplete returns an incomplete version of the key. The ID fields of the
452 // last token will be set to zero/empty.
453 func (k *Key) Incomplete() *Key {
454 if k.IsIncomplete() {
455 return k
456 }
457 return NewKey(k.appID, k.namespace, k.Kind(), "", 0, k.Parent())
458 }
459
460 // WithID returns the key generated by setting the ID of its last token to
461 // the specified value.
462 //
463 // 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
465 // be IncompleteEqual).
466 func (k *Key) WithID(stringID string, intID int64) *Key {
467 if k.StringID() == stringID && k.IntID() == intID {
468 return k
469 }
470 return NewKey(k.appID, k.namespace, k.Kind(), stringID, intID, k.Parent( ))
471 }
472
435 // Split componentizes the key into pieces (AppID, Namespace and tokens) 473 // Split componentizes the key into pieces (AppID, Namespace and tokens)
436 // 474 //
437 // Each token represents one piece of they key's 'path'. 475 // Each token represents one piece of they key's 'path'.
438 // 476 //
439 // toks is guaranteed to be empty if and only if k is nil. If k is non-nil then 477 // toks is guaranteed to be empty if and only if k is nil. If k is non-nil then
440 // it contains at least one token. 478 // it contains at least one token.
441 func (k *Key) Split() (appID, namespace string, toks []KeyTok) { 479 func (k *Key) Split() (appID, namespace string, toks []KeyTok) {
442 appID = k.appID 480 appID = k.appID
443 namespace = k.namespace 481 namespace = k.namespace
444 toks = make([]KeyTok, len(k.toks)) 482 toks = make([]KeyTok, len(k.toks))
(...skipping 11 matching lines...) Expand all
456 for _, t := range k.toks { 494 for _, t := range k.toks {
457 ret += int64(len(t.Kind)) 495 ret += int64(len(t.Kind))
458 if t.StringID != "" { 496 if t.StringID != "" {
459 ret += int64(len(t.StringID)) 497 ret += int64(len(t.StringID))
460 } else { 498 } else {
461 ret += 8 499 ret += 8
462 } 500 }
463 } 501 }
464 return ret 502 return ret
465 } 503 }
OLDNEW
« no previous file with comments | « service/datastore/interface.go ('k') | service/datastore/key_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698