| OLD | NEW | 
|---|
| 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  Loading... | 
| 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  Loading... | 
| 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 } | 
| OLD | NEW | 
|---|