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 |