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

Side by Side Diff: service/datastore/multiarg.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/key_test.go ('k') | service/datastore/raw_interface.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 "fmt" 8 "fmt"
9 "reflect" 9 "reflect"
10 10
11 "github.com/luci/luci-go/common/errors" 11 "github.com/luci/luci-go/common/errors"
12 ) 12 )
13 13
14 type metaMultiArgConstraints int
15
16 const (
17 // mmaReadWrite allows a metaMultiArg to operate on any type that can be
18 // both read and written to.
19 mmaReadWrite metaMultiArgConstraints = iota
20 // mmaKeysOnly implies mmaReadWrite, with the further statement that the only
21 // operation that will be performed against the arguments will be key
22 // extraction.
23 mmaKeysOnly = iota
24 // mmaWriteKeys indicates that the caller is only going to write key
25 // values. This enables the same inputs as mmaReadWrite, but also allows
26 // []*Key.
27 mmaWriteKeys = iota
28 )
29
30 func (c metaMultiArgConstraints) allowSingleKey() bool {
31 return c == mmaKeysOnly
32 }
33
34 func (c metaMultiArgConstraints) keyOperationsOnly() bool {
35 return c >= mmaKeysOnly
36 }
37
14 type multiArgType struct { 38 type multiArgType struct {
15 getMGS func(slot reflect.Value) MetaGetterSetter 39 getMGS func(slot reflect.Value) MetaGetterSetter
16 getPLS func(slot reflect.Value) PropertyLoadSaver 40 getPLS func(slot reflect.Value) PropertyLoadSaver
17 newElem func() reflect.Value 41 newElem func() reflect.Value
18 } 42 }
19 43
20 func (mat *multiArgType) getKey(aid, ns string, slot reflect.Value) (*Key, error ) { 44 func (mat *multiArgType) getKey(aid, ns string, slot reflect.Value) (*Key, error ) {
21 return newKeyObjErr(aid, ns, mat.getMGS(slot)) 45 return newKeyObjErr(aid, ns, mat.getMGS(slot))
22 } 46 }
23 47
24 func (mat *multiArgType) getPM(slot reflect.Value) (PropertyMap, error) { 48 func (mat *multiArgType) getPM(slot reflect.Value) (PropertyMap, error) {
25 return mat.getPLS(slot).Save(true) 49 return mat.getPLS(slot).Save(true)
26 } 50 }
27 51
28 func (mat *multiArgType) getMetaPM(slot reflect.Value) PropertyMap { 52 func (mat *multiArgType) getMetaPM(slot reflect.Value) PropertyMap {
29 return mat.getMGS(slot).GetAllMeta() 53 return mat.getMGS(slot).GetAllMeta()
30 } 54 }
31 55
32 func (mat *multiArgType) setPM(slot reflect.Value, pm PropertyMap) error { 56 func (mat *multiArgType) setPM(slot reflect.Value, pm PropertyMap) error {
33 return mat.getPLS(slot).Load(pm) 57 return mat.getPLS(slot).Load(pm)
34 } 58 }
35 59
36 func (mat *multiArgType) setKey(slot reflect.Value, k *Key) { 60 func (mat *multiArgType) setKey(slot reflect.Value, k *Key) bool {
37 » PopulateKey(mat.getMGS(slot), k) 61 » return populateKeyMGS(mat.getMGS(slot), k)
38 } 62 }
39 63
40 // parseArg checks that et is of type S, *S, I, P or *P, for some 64 // parseArg checks that et is of type S, *S, I, P or *P, for some
41 // struct type S, for some interface type I, or some non-interface non-pointer 65 // struct type S, for some interface type I, or some non-interface non-pointer
42 // type P such that P or *P implements PropertyLoadSaver. 66 // type P such that P or *P implements PropertyLoadSaver.
43 // 67 //
44 // If et is a chan type that implements PropertyLoadSaver, new elements will be 68 // If et is a chan type that implements PropertyLoadSaver, new elements will be
45 // allocated with a buffer of 0. 69 // allocated with a buffer of 0.
46 // 70 //
47 // If keysOnly is true, a read-only key extraction multiArgType will be 71 // If allowKey is true, et may additional be type *Key. Only MetaGetterSetter
48 // returned if et is a *Key. 72 // fields will be populated in the result (see keyMGS).
49 func parseArg(et reflect.Type, keysOnly bool) *multiArgType { 73 func parseArg(et reflect.Type, allowKeys bool) *multiArgType {
50 var mat multiArgType 74 var mat multiArgType
51 75
52 » if keysOnly && et == typeOfKey { 76 » if et == typeOfKey {
53 » » mat.getMGS = func(slot reflect.Value) MetaGetterSetter { return &keyExtractionMGS{key: slot.Interface().(*Key)} } 77 » » if !allowKeys {
78 » » » return nil
79 » » }
80
81 » » mat.getMGS = func(slot reflect.Value) MetaGetterSetter { return &keyMGS{slot: slot} }
54 return &mat 82 return &mat
55 } 83 }
56 84
57 // If we do identify a structCodec for this type, retain it so we don't 85 // If we do identify a structCodec for this type, retain it so we don't
58 // resolve it multiple times. 86 // resolve it multiple times.
59 var codec *structCodec 87 var codec *structCodec
60 initCodec := func(t reflect.Type) *structCodec { 88 initCodec := func(t reflect.Type) *structCodec {
61 if codec == nil { 89 if codec == nil {
62 codec = getCodec(t) 90 codec = getCodec(t)
63 } 91 }
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
192 return &mat 220 return &mat
193 } 221 }
194 222
195 // mustParseMultiArg checks that v has type []S, []*S, []I, []P or []*P, for 223 // mustParseMultiArg checks that v has type []S, []*S, []I, []P or []*P, for
196 // some struct type S, for some interface type I, or some non-interface 224 // some struct type S, for some interface type I, or some non-interface
197 // non-pointer type P such that P or *P implements PropertyLoadSaver. 225 // non-pointer type P such that P or *P implements PropertyLoadSaver.
198 func mustParseMultiArg(et reflect.Type) *multiArgType { 226 func mustParseMultiArg(et reflect.Type) *multiArgType {
199 if et.Kind() != reflect.Slice { 227 if et.Kind() != reflect.Slice {
200 panic(fmt.Errorf("invalid argument type: expected slice, got %s" , et)) 228 panic(fmt.Errorf("invalid argument type: expected slice, got %s" , et))
201 } 229 }
202 » return mustParseArg(et.Elem()) 230 » return mustParseArg(et.Elem(), true)
203 } 231 }
204 232
205 func mustParseArg(et reflect.Type) *multiArgType { 233 func mustParseArg(et reflect.Type, sliceArg bool) *multiArgType {
206 if mat := parseArg(et, false); mat != nil { 234 if mat := parseArg(et, false); mat != nil {
207 return mat 235 return mat
208 } 236 }
209 panic(fmt.Errorf("invalid argument type: %s is not a PLS or pointer-to-s truct", et)) 237 panic(fmt.Errorf("invalid argument type: %s is not a PLS or pointer-to-s truct", et))
210 } 238 }
211 239
212 func newKeyObjErr(aid, ns string, mgs MetaGetterSetter) (*Key, error) { 240 func newKeyObjErr(aid, ns string, mgs MetaGetterSetter) (*Key, error) {
213 if key, _ := GetMetaDefault(mgs, "key", nil).(*Key); key != nil { 241 if key, _ := GetMetaDefault(mgs, "key", nil).(*Key); key != nil {
214 return key, nil 242 return key, nil
215 } 243 }
216 244
217 // get kind 245 // get kind
218 kind := GetMetaDefault(mgs, "kind", "").(string) 246 kind := GetMetaDefault(mgs, "kind", "").(string)
219 if kind == "" { 247 if kind == "" {
220 return nil, errors.New("unable to extract $kind") 248 return nil, errors.New("unable to extract $kind")
221 } 249 }
222 250
223 // get id - allow both to be default for default keys 251 // get id - allow both to be default for default keys
224 sid := GetMetaDefault(mgs, "id", "").(string) 252 sid := GetMetaDefault(mgs, "id", "").(string)
225 iid := GetMetaDefault(mgs, "id", 0).(int64) 253 iid := GetMetaDefault(mgs, "id", 0).(int64)
226 254
227 // get parent 255 // get parent
228 par, _ := GetMetaDefault(mgs, "parent", nil).(*Key) 256 par, _ := GetMetaDefault(mgs, "parent", nil).(*Key)
229 257
230 return NewKey(aid, ns, kind, sid, iid, par), nil 258 return NewKey(aid, ns, kind, sid, iid, par), nil
231 } 259 }
232 260
233 func isOKSingleType(t reflect.Type, keysOnly bool) error { 261 func isOKSingleType(t reflect.Type, allowKey bool) error {
234 switch { 262 switch {
235 case t == nil: 263 case t == nil:
236 return errors.New("no type information") 264 return errors.New("no type information")
237 case t.Implements(typeOfPropertyLoadSaver): 265 case t.Implements(typeOfPropertyLoadSaver):
238 return nil 266 return nil
239 » case !keysOnly && t == typeOfKey: 267 » case !allowKey && t == typeOfKey:
240 return errors.New("not user datatype") 268 return errors.New("not user datatype")
241 269
242 case t.Kind() != reflect.Ptr: 270 case t.Kind() != reflect.Ptr:
243 return errors.New("not a pointer") 271 return errors.New("not a pointer")
244 case t.Elem().Kind() != reflect.Struct: 272 case t.Elem().Kind() != reflect.Struct:
245 return errors.New("does not point to a struct") 273 return errors.New("does not point to a struct")
246 274
247 default: 275 default:
248 return nil 276 return nil
249 } 277 }
250 } 278 }
251 279
252 // keyExtractionMGS is a MetaGetterSetter that wraps a key and only implements 280 // keyMGS is a MetaGetterSetter that wraps a single key value/slot. It only
253 // GetMeta, and even then only retrieves the wrapped key meta value, "key". 281 // implements operations on the "key" key.
254 type keyExtractionMGS struct { 282 //
255 » MetaGetterSetter 283 // GetMeta will be implemented, returning the *Key for the "key" meta.
256 284 //
257 » key *Key 285 // If slot is addressable, SetMeta will allow it to be set to the supplied
286 // Value.
287 type keyMGS struct {
288 » slot reflect.Value
258 } 289 }
259 290
260 func (mgs *keyExtractionMGS) GetMeta(key string) (interface{}, bool) { 291 func (mgs *keyMGS) GetAllMeta() PropertyMap {
261 » if key == "key" { 292 » return PropertyMap{"$key": []Property{MkPropertyNI(mgs.slot.Interface()) }}
262 » » return mgs.key, true 293 }
294
295 func (mgs *keyMGS) GetMeta(key string) (interface{}, bool) {
296 » if key != "key" {
297 » » return nil, false
263 } 298 }
264 » return nil, false 299 » return mgs.slot.Interface(), true
300 }
301
302 func (mgs *keyMGS) SetMeta(key string, value interface{}) bool {
303 » if !(key == "key" && mgs.slot.CanAddr()) {
304 » » return false
305 » }
306 » mgs.slot.Set(reflect.ValueOf(value))
307 » return true
265 } 308 }
266 309
267 type metaMultiArgElement struct { 310 type metaMultiArgElement struct {
268 arg reflect.Value 311 arg reflect.Value
269 mat *multiArgType 312 mat *multiArgType
270 size int // size is -1 if this element is not a slice. 313 size int // size is -1 if this element is not a slice.
271 } 314 }
272 315
273 type metaMultiArg struct { 316 type metaMultiArg struct {
274 elems []metaMultiArgElement 317 elems []metaMultiArgElement
275 keysOnly bool 318 keysOnly bool
276 319
277 count int // total number of elements, flattening slices 320 count int // total number of elements, flattening slices
278 } 321 }
279 322
280 func makeMetaMultiArg(args []interface{}, keysOnly bool) (*metaMultiArg, error) { 323 // makeMetaMultiArg returns a metaMultiArg for the supplied args.
324 //
325 // If an arg is a slice, a slice metaMultiArg will be returned, and errors for
326 // that slice will be written into a positional MultiError if they occur.
327 //
328 // If keysOnly is true, the caller is instructing metaMultiArg to only extract
329 // the datastore *Key from args. *Key entries will be permitted, but the caller
330 // may not write to them (since keys are read-only structs).
331 func makeMetaMultiArg(args []interface{}, c metaMultiArgConstraints) (*metaMulti Arg, error) {
281 mma := metaMultiArg{ 332 mma := metaMultiArg{
282 elems: make([]metaMultiArgElement, len(args)), 333 elems: make([]metaMultiArgElement, len(args)),
283 » » keysOnly: keysOnly, 334 » » keysOnly: c.keyOperationsOnly(),
284 } 335 }
285 336
286 lme := errors.NewLazyMultiError(len(args)) 337 lme := errors.NewLazyMultiError(len(args))
287 for i, arg := range args { 338 for i, arg := range args {
288 if arg == nil { 339 if arg == nil {
289 lme.Assign(i, errors.New("cannot use nil as single argum ent")) 340 lme.Assign(i, errors.New("cannot use nil as single argum ent"))
290 continue 341 continue
291 } 342 }
292 343
293 v := reflect.ValueOf(arg) 344 v := reflect.ValueOf(arg)
294 vt := v.Type() 345 vt := v.Type()
295 mma.elems[i].arg = v 346 mma.elems[i].arg = v
296 347
297 // Try and treat the argument as a single-value first. This allo ws slices 348 // Try and treat the argument as a single-value first. This allo ws slices
298 // that implement PropertyLoadSaver to be properly treated as a single 349 // that implement PropertyLoadSaver to be properly treated as a single
299 // element. 350 // element.
300 » » var err error 351 » » var (
301 » » isSlice := false 352 » » » mat *multiArgType
302 » » mat := parseArg(vt, keysOnly) 353 » » » err error
303 » » if mat == nil { 354 » » » isSlice = false
355 » » )
356 » » if mat = parseArg(vt, c.allowSingleKey()); mat == nil {
304 // If this is a slice, treat it as a slice of arg candid ates. 357 // If this is a slice, treat it as a slice of arg candid ates.
358 //
359 // If only keys are being read/written, we allow a []*Ke y to be accepted
360 // here, since slices are addressable (write).
305 if v.Kind() == reflect.Slice { 361 if v.Kind() == reflect.Slice {
306 isSlice = true 362 isSlice = true
307 » » » » mat = parseArg(vt.Elem(), keysOnly) 363 » » » » mat = parseArg(vt.Elem(), c.keyOperationsOnly())
308 } 364 }
309 } else { 365 } else {
310 // Single types need to be able to be assigned to. 366 // Single types need to be able to be assigned to.
311 » » » err = isOKSingleType(vt, keysOnly) 367 » » » //
368 » » » // We only allow *Key here when the keys cannot be writt en to, since *Key
369 » » » // should not be modified in-place, as they are immutabl e.
370 » » » err = isOKSingleType(vt, c.allowSingleKey())
312 } 371 }
313 » » if mat == nil { 372 » » if mat == nil && err == nil {
314 » » » err = errors.New("not a PLS or pointer-to-struct") 373 » » » err = errors.New("not a PLS, pointer-to-struct, or slice thereof")
315 } 374 }
316 if err != nil { 375 if err != nil {
317 lme.Assign(i, fmt.Errorf("invalid input type (%T): %s", arg, err)) 376 lme.Assign(i, fmt.Errorf("invalid input type (%T): %s", arg, err))
318 continue 377 continue
319 } 378 }
320 379
321 mma.elems[i].mat = mat 380 mma.elems[i].mat = mat
322 if isSlice { 381 if isSlice {
323 l := v.Len() 382 l := v.Len()
324 mma.count += l 383 mma.count += l
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after
506 default: 565 default:
507 // Pass through to track as MultiError. 566 // Pass through to track as MultiError.
508 bt.errorTracker.trackError(it, err) 567 bt.errorTracker.trackError(it, err)
509 } 568 }
510 } 569 }
511 570
512 func (bt *boolTracker) result() *ExistsResult { 571 func (bt *boolTracker) result() *ExistsResult {
513 bt.res.updateSlices() 572 bt.res.updateSlices()
514 return &bt.res 573 return &bt.res
515 } 574 }
OLDNEW
« no previous file with comments | « service/datastore/key_test.go ('k') | service/datastore/raw_interface.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698