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

Side by Side Diff: service/rawdatastore/datastore_key.go

Issue 1243323002: Refactor a bit. (Closed) Base URL: https://github.com/luci/gae.git@master
Patch Set: fix golint Created 5 years, 5 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/rawdatastore/datastore_impl.go ('k') | service/rawdatastore/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 Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // adapted from github.com/golang/appengine/datastore 5 // adapted from github.com/golang/appengine/datastore
6 6
7 package helper 7 package rawdatastore
8 8
9 import ( 9 import (
10 "bytes" 10 "bytes"
11 "encoding/base64" 11 "encoding/base64"
12 "errors" 12 "errors"
13 "strconv" 13 "strconv"
14 "strings" 14 "strings"
15 15
16 » "github.com/luci/gae" 16 » pb "github.com/luci/gae/service/rawdatastore/internal/protos/datastore"
17 » pb "github.com/luci/gae/helper/internal/protos/datastore"
18 17
19 "github.com/golang/protobuf/proto" 18 "github.com/golang/protobuf/proto"
20 ) 19 )
21 20
22 // DSKeyEncode encodes the provided key as a base64-encoded protobuf. 21 // KeyEncode encodes the provided key as a base64-encoded protobuf.
23 // 22 //
24 // This encoding is compatible with the SDK-provided encoding and is agnostic 23 // This encoding is compatible with the SDK-provided encoding and is agnostic
25 // to the underlying implementation of the DSKey. 24 // to the underlying implementation of the Key.
26 func DSKeyEncode(k gae.DSKey) string { 25 func KeyEncode(k Key) string {
27 n := 0 26 n := 0
28 for i := k; i != nil; i = i.Parent() { 27 for i := k; i != nil; i = i.Parent() {
29 n++ 28 n++
30 } 29 }
31 e := make([]*pb.Path_Element, n) 30 e := make([]*pb.Path_Element, n)
32 for i := k; i != nil; i = i.Parent() { 31 for i := k; i != nil; i = i.Parent() {
33 n-- 32 n--
34 kind := i.Kind() 33 kind := i.Kind()
35 e[n] = &pb.Path_Element{ 34 e[n] = &pb.Path_Element{
36 Type: &kind, 35 Type: &kind,
(...skipping 20 matching lines...) Expand all
57 }, 56 },
58 }) 57 })
59 if err != nil { 58 if err != nil {
60 panic(err) 59 panic(err)
61 } 60 }
62 61
63 // trim padding 62 // trim padding
64 return strings.TrimRight(base64.URLEncoding.EncodeToString(r), "=") 63 return strings.TrimRight(base64.URLEncoding.EncodeToString(r), "=")
65 } 64 }
66 65
67 // DSKeyToksDecode decodes a base64-encoded protobuf representation of a DSKey 66 // KeyToksDecode decodes a base64-encoded protobuf representation of a Key
68 // into a tokenized form. This is so that implementations of the gae wrapper 67 // into a tokenized form. This is so that implementations of the gae wrapper
69 // can decode to their own implementation of DSKey. 68 // can decode to their own implementation of Key.
70 // 69 //
71 // This encoding is compatible with the SDK-provided encoding and is agnostic 70 // This encoding is compatible with the SDK-provided encoding and is agnostic
72 // to the underlying implementation of the DSKey. 71 // to the underlying implementation of the Key.
73 func DSKeyToksDecode(encoded string) (appID, namespace string, toks []gae.DSKeyT ok, err error) { 72 func KeyToksDecode(encoded string) (appID, namespace string, toks []KeyTok, err error) {
74 // Re-add padding 73 // Re-add padding
75 if m := len(encoded) % 4; m != 0 { 74 if m := len(encoded) % 4; m != 0 {
76 encoded += strings.Repeat("=", 4-m) 75 encoded += strings.Repeat("=", 4-m)
77 } 76 }
78 b, err := base64.URLEncoding.DecodeString(encoded) 77 b, err := base64.URLEncoding.DecodeString(encoded)
79 if err != nil { 78 if err != nil {
80 return 79 return
81 } 80 }
82 81
83 r := &pb.Reference{} 82 r := &pb.Reference{}
84 if err = proto.Unmarshal(b, r); err != nil { 83 if err = proto.Unmarshal(b, r); err != nil {
85 return 84 return
86 } 85 }
87 86
88 appID = r.GetApp() 87 appID = r.GetApp()
89 namespace = r.GetNameSpace() 88 namespace = r.GetNameSpace()
90 » toks = make([]gae.DSKeyTok, len(r.Path.Element)) 89 » toks = make([]KeyTok, len(r.Path.Element))
91 for i, e := range r.Path.Element { 90 for i, e := range r.Path.Element {
92 » » toks[i] = gae.DSKeyTok{ 91 » » toks[i] = KeyTok{
93 Kind: e.GetType(), 92 Kind: e.GetType(),
94 IntID: e.GetId(), 93 IntID: e.GetId(),
95 StringID: e.GetName(), 94 StringID: e.GetName(),
96 } 95 }
97 } 96 }
98 return 97 return
99 } 98 }
100 99
101 // DSKeyMarshalJSON returns a MarshalJSON-compatible serialization of a DSKey. 100 // KeyMarshalJSON returns a MarshalJSON-compatible serialization of a Key.
102 func DSKeyMarshalJSON(k gae.DSKey) ([]byte, error) { 101 func KeyMarshalJSON(k Key) ([]byte, error) {
103 » return []byte(`"` + DSKeyEncode(k) + `"`), nil 102 » return []byte(`"` + KeyEncode(k) + `"`), nil
104 } 103 }
105 104
106 // DSKeyUnmarshalJSON returns the tokenized version of a DSKey as encoded by 105 // KeyUnmarshalJSON returns the tokenized version of a Key as encoded by
107 // DSKeyMarshalJSON. 106 // KeyMarshalJSON.
108 func DSKeyUnmarshalJSON(buf []byte) (appID, namespace string, toks []gae.DSKeyTo k, err error) { 107 func KeyUnmarshalJSON(buf []byte) (appID, namespace string, toks []KeyTok, err e rror) {
109 if len(buf) < 2 || buf[0] != '"' || buf[len(buf)-1] != '"' { 108 if len(buf) < 2 || buf[0] != '"' || buf[len(buf)-1] != '"' {
110 err = errors.New("datastore: bad JSON key") 109 err = errors.New("datastore: bad JSON key")
111 } else { 110 } else {
112 » » appID, namespace, toks, err = DSKeyToksDecode(string(buf[1 : len (buf)-1])) 111 » » appID, namespace, toks, err = KeyToksDecode(string(buf[1 : len(b uf)-1]))
113 } 112 }
114 return 113 return
115 } 114 }
116 115
117 // DSKeyIncomplete returns true iff k doesn't have an id yet. 116 // KeyIncomplete returns true iff k doesn't have an id yet.
118 func DSKeyIncomplete(k gae.DSKey) bool { 117 func KeyIncomplete(k Key) bool {
119 return k != nil && k.StringID() == "" && k.IntID() == 0 118 return k != nil && k.StringID() == "" && k.IntID() == 0
120 } 119 }
121 120
122 // DSKeyValid determines if a key is valid, according to a couple rules: 121 // KeyValid determines if a key is valid, according to a couple rules:
123 // - k is not nil 122 // - k is not nil
124 // - k's namespace matches ns 123 // - k's namespace matches ns
125 // - every token of k: 124 // - every token of k:
126 // - (if !allowSpecial) token's kind doesn't start with '__' 125 // - (if !allowSpecial) token's kind doesn't start with '__'
127 // - token's kind and appid are non-blank 126 // - token's kind and appid are non-blank
128 // - token is not incomplete 127 // - token is not incomplete
129 // - all tokens have the same namespace and appid 128 // - all tokens have the same namespace and appid
130 func DSKeyValid(k gae.DSKey, ns string, allowSpecial bool) bool { 129 func KeyValid(k Key, ns string, allowSpecial bool) bool {
131 if k == nil { 130 if k == nil {
132 return false 131 return false
133 } 132 }
134 // since we do "client-side" validation of namespaces in local 133 // since we do "client-side" validation of namespaces in local
135 // implementations, it's convenient to check this here. 134 // implementations, it's convenient to check this here.
136 if k.Namespace() != ns { 135 if k.Namespace() != ns {
137 return false 136 return false
138 } 137 }
139 for ; k != nil; k = k.Parent() { 138 for ; k != nil; k = k.Parent() {
140 if !allowSpecial && len(k.Kind()) >= 2 && k.Kind()[:2] == "__" { 139 if !allowSpecial && len(k.Kind()) >= 2 && k.Kind()[:2] == "__" {
141 return false 140 return false
142 } 141 }
143 if k.Kind() == "" || k.AppID() == "" { 142 if k.Kind() == "" || k.AppID() == "" {
144 return false 143 return false
145 } 144 }
146 if k.StringID() != "" && k.IntID() != 0 { 145 if k.StringID() != "" && k.IntID() != 0 {
147 return false 146 return false
148 } 147 }
149 if k.Parent() != nil { 148 if k.Parent() != nil {
150 » » » if DSKeyIncomplete(k.Parent()) { 149 » » » if KeyIncomplete(k.Parent()) {
151 return false 150 return false
152 } 151 }
153 if k.Parent().AppID() != k.AppID() || k.Parent().Namespa ce() != k.Namespace() { 152 if k.Parent().AppID() != k.AppID() || k.Parent().Namespa ce() != k.Namespace() {
154 return false 153 return false
155 } 154 }
156 } 155 }
157 } 156 }
158 return true 157 return true
159 } 158 }
160 159
161 // DSKeyRoot returns the entity root for the given key. 160 // KeyRoot returns the entity root for the given key.
162 func DSKeyRoot(k gae.DSKey) gae.DSKey { 161 func KeyRoot(k Key) Key {
163 for k != nil && k.Parent() != nil { 162 for k != nil && k.Parent() != nil {
164 k = k.Parent() 163 k = k.Parent()
165 } 164 }
166 return k 165 return k
167 } 166 }
168 167
169 // DSKeysEqual returns true iff the two keys represent identical key values. 168 // KeysEqual returns true iff the two keys represent identical key values.
170 func DSKeysEqual(a, b gae.DSKey) (ret bool) { 169 func KeysEqual(a, b Key) (ret bool) {
171 ret = (a.Kind() == b.Kind() && 170 ret = (a.Kind() == b.Kind() &&
172 a.StringID() == b.StringID() && 171 a.StringID() == b.StringID() &&
173 a.IntID() == b.IntID() && 172 a.IntID() == b.IntID() &&
174 a.AppID() == b.AppID() && 173 a.AppID() == b.AppID() &&
175 a.Namespace() == b.Namespace()) 174 a.Namespace() == b.Namespace())
176 if !ret { 175 if !ret {
177 return 176 return
178 } 177 }
179 ap, bp := a.Parent(), b.Parent() 178 ap, bp := a.Parent(), b.Parent()
180 » return (ap == nil && bp == nil) || DSKeysEqual(ap, bp) 179 » return (ap == nil && bp == nil) || KeysEqual(ap, bp)
181 } 180 }
182 181
183 func marshalDSKey(b *bytes.Buffer, k gae.DSKey) { 182 func marshalDSKey(b *bytes.Buffer, k Key) {
184 if k.Parent() != nil { 183 if k.Parent() != nil {
185 marshalDSKey(b, k.Parent()) 184 marshalDSKey(b, k.Parent())
186 } 185 }
187 b.WriteByte('/') 186 b.WriteByte('/')
188 b.WriteString(k.Kind()) 187 b.WriteString(k.Kind())
189 b.WriteByte(',') 188 b.WriteByte(',')
190 if k.StringID() != "" { 189 if k.StringID() != "" {
191 b.WriteString(k.StringID()) 190 b.WriteString(k.StringID())
192 } else { 191 } else {
193 b.WriteString(strconv.FormatInt(k.IntID(), 10)) 192 b.WriteString(strconv.FormatInt(k.IntID(), 10))
194 } 193 }
195 } 194 }
196 195
197 // DSKeyString returns a human-readable representation of the key, and is the 196 // KeyString returns a human-readable representation of the key, and is the
198 // typical implementation of DSKey.String() (though it isn't guaranteed to be) 197 // typical implementation of Key.String() (though it isn't guaranteed to be)
199 func DSKeyString(k gae.DSKey) string { 198 func KeyString(k Key) string {
200 if k == nil { 199 if k == nil {
201 return "" 200 return ""
202 } 201 }
203 b := bytes.NewBuffer(make([]byte, 0, 512)) 202 b := bytes.NewBuffer(make([]byte, 0, 512))
204 marshalDSKey(b, k) 203 marshalDSKey(b, k)
205 return b.String() 204 return b.String()
206 } 205 }
207 206
208 // DSKeySplit splits the key into its constituent parts. Note that if the key is 207 // KeySplit splits the key into its constituent parts. Note that if the key is
209 // not DSKeyValid, this method may not provide a round-trip for k. 208 // not KeyValid, this method may not provide a round-trip for k.
210 func DSKeySplit(k gae.DSKey) (appID, namespace string, toks []gae.DSKeyTok) { 209 func KeySplit(k Key) (appID, namespace string, toks []KeyTok) {
211 if k == nil { 210 if k == nil {
212 return 211 return
213 } 212 }
214 213
215 » if sk, ok := k.(*GenericDSKey); ok { 214 » if sk, ok := k.(*GenericKey); ok {
216 if sk == nil { 215 if sk == nil {
217 return 216 return
218 } 217 }
219 return sk.appID, sk.namespace, sk.toks 218 return sk.appID, sk.namespace, sk.toks
220 } 219 }
221 220
222 n := 0 221 n := 0
223 for i := k; i != nil; i = i.Parent() { 222 for i := k; i != nil; i = i.Parent() {
224 n++ 223 n++
225 } 224 }
226 » toks = make([]gae.DSKeyTok, n) 225 » toks = make([]KeyTok, n)
227 for i := k; i != nil; i = i.Parent() { 226 for i := k; i != nil; i = i.Parent() {
228 n-- 227 n--
229 toks[n].IntID = i.IntID() 228 toks[n].IntID = i.IntID()
230 toks[n].StringID = i.StringID() 229 toks[n].StringID = i.StringID()
231 toks[n].Kind = i.Kind() 230 toks[n].Kind = i.Kind()
232 } 231 }
233 appID = k.AppID() 232 appID = k.AppID()
234 namespace = k.Namespace() 233 namespace = k.Namespace()
235 return 234 return
236 } 235 }
OLDNEW
« no previous file with comments | « service/rawdatastore/datastore_impl.go ('k') | service/rawdatastore/datastore_key_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698