| 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 |