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