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 // HEAVILY adapted from github.com/golang/appengine/datastore | 5 // HEAVILY adapted from github.com/golang/appengine/datastore |
6 | 6 |
7 package datastore | 7 package datastore |
8 | 8 |
9 import ( | 9 import ( |
10 "fmt" | 10 "fmt" |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
62 useExtra := false | 62 useExtra := false |
63 extra := (*PropertyMap)(nil) | 63 extra := (*PropertyMap)(nil) |
64 if i, ok := p.c.bySpecial["extra"]; ok { | 64 if i, ok := p.c.bySpecial["extra"]; ok { |
65 useExtra = true | 65 useExtra = true |
66 f := p.c.byIndex[i] | 66 f := p.c.byIndex[i] |
67 if f.canSet { | 67 if f.canSet { |
68 extra = p.o.Field(i).Addr().Interface().(*PropertyMap) | 68 extra = p.o.Field(i).Addr().Interface().(*PropertyMap) |
69 } | 69 } |
70 } | 70 } |
71 t := reflect.Type(nil) | 71 t := reflect.Type(nil) |
72 » for name, props := range propMap { | 72 » for name, pdata := range propMap { |
73 » » multiple := len(props) > 1 | 73 » » pslice := pdata.Slice() |
74 » » for i, prop := range props { | 74 » » requireSlice := len(pslice) > 1 |
75 » » » if reason := loadInner(p.c, p.o, i, name, prop, multiple
); reason != "" { | 75 » » for i, prop := range pslice { |
| 76 » » » if reason := loadInner(p.c, p.o, i, name, prop, requireS
lice); reason != "" { |
76 if useExtra { | 77 if useExtra { |
77 if extra != nil { | 78 if extra != nil { |
78 if *extra == nil { | 79 if *extra == nil { |
79 *extra = make(PropertyMa
p, 1) | 80 *extra = make(PropertyMa
p, 1) |
80 } | 81 } |
81 » » » » » » (*extra)[name] = props | 82 » » » » » » (*extra)[name] = pslice |
82 } | 83 } |
83 break // go to the next property in prop
Map | 84 break // go to the next property in prop
Map |
84 } else { | 85 } else { |
85 if t == nil { | 86 if t == nil { |
86 t = p.o.Type() | 87 t = p.o.Type() |
87 } | 88 } |
88 convFailures = append(convFailures, &Err
FieldMismatch{ | 89 convFailures = append(convFailures, &Err
FieldMismatch{ |
89 StructType: t, | 90 StructType: t, |
90 FieldName: name, | 91 FieldName: name, |
91 Reason: reason, | 92 Reason: reason, |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
234 ret := PropertyMap(nil) | 235 ret := PropertyMap(nil) |
235 if withMeta { | 236 if withMeta { |
236 if p.mgs != nil { | 237 if p.mgs != nil { |
237 ret = p.mgs.GetAllMeta() | 238 ret = p.mgs.GetAllMeta() |
238 } else { | 239 } else { |
239 ret = p.GetAllMeta() | 240 ret = p.GetAllMeta() |
240 } | 241 } |
241 } else { | 242 } else { |
242 ret = make(PropertyMap, len(p.c.byName)) | 243 ret = make(PropertyMap, len(p.c.byName)) |
243 } | 244 } |
244 » if _, err := p.save(ret, "", ShouldIndex); err != nil { | 245 » if _, err := p.save(ret, "", nil, ShouldIndex); err != nil { |
245 return nil, err | 246 return nil, err |
246 } | 247 } |
247 return ret, nil | 248 return ret, nil |
248 } | 249 } |
249 | 250 |
250 func (p *structPLS) getDefaultKind() string { | 251 func (p *structPLS) getDefaultKind() string { |
251 if !p.o.IsValid() { | 252 if !p.o.IsValid() { |
252 return "" | 253 return "" |
253 } | 254 } |
254 return p.o.Type().Name() | 255 return p.o.Type().Name() |
255 } | 256 } |
256 | 257 |
257 func (p *structPLS) save(propMap PropertyMap, prefix string, is IndexSetting) (i
dxCount int, err error) { | 258 func (p *structPLS) save(propMap PropertyMap, prefix string, parentST *structTag
, is IndexSetting) (idxCount int, err error) { |
258 saveProp := func(name string, si IndexSetting, v reflect.Value, st *stru
ctTag) (err error) { | 259 saveProp := func(name string, si IndexSetting, v reflect.Value, st *stru
ctTag) (err error) { |
259 if st.substructCodec != nil { | 260 if st.substructCodec != nil { |
260 » » » count, err := (&structPLS{v, st.substructCodec, nil}).sa
ve(propMap, name, si) | 261 » » » count, err := (&structPLS{v, st.substructCodec, nil}).sa
ve(propMap, name, st, si) |
261 if err == nil { | 262 if err == nil { |
262 idxCount += count | 263 idxCount += count |
263 if idxCount > maxIndexedProperties { | 264 if idxCount > maxIndexedProperties { |
264 err = errors.New("gae: too many indexed
properties") | 265 err = errors.New("gae: too many indexed
properties") |
265 } | 266 } |
266 } | 267 } |
267 return err | 268 return err |
268 } | 269 } |
269 | 270 |
270 prop := Property{} | 271 prop := Property{} |
271 if st.convert { | 272 if st.convert { |
272 prop, err = v.Addr().Interface().(PropertyConverter).ToP
roperty() | 273 prop, err = v.Addr().Interface().(PropertyConverter).ToP
roperty() |
273 } else { | 274 } else { |
274 err = prop.SetValue(v.Interface(), si) | 275 err = prop.SetValue(v.Interface(), si) |
275 } | 276 } |
276 if err != nil { | 277 if err != nil { |
277 return err | 278 return err |
278 } | 279 } |
279 » » propMap[name] = append(propMap[name], prop) | 280 |
| 281 » » // If we're a slice, or we are members in a slice, then use a Pr
opertySlice. |
| 282 » » if st.isSlice || (parentST != nil && parentST.isSlice) { |
| 283 » » » var pslice PropertySlice |
| 284 » » » if pdata := propMap[name]; pdata != nil { |
| 285 » » » » pslice = pdata.(PropertySlice) |
| 286 » » » } |
| 287 » » » propMap[name] = append(pslice, prop) |
| 288 » » } else { |
| 289 » » » if _, ok := propMap[name]; ok { |
| 290 » » » » return errors.New("non-slice property adding mul
tiple PropertyMap entries") |
| 291 » » » } |
| 292 » » » propMap[name] = prop |
| 293 » » } |
| 294 |
280 if prop.IndexSetting() == ShouldIndex { | 295 if prop.IndexSetting() == ShouldIndex { |
281 idxCount++ | 296 idxCount++ |
282 if idxCount > maxIndexedProperties { | 297 if idxCount > maxIndexedProperties { |
283 return errors.New("gae: too many indexed propert
ies") | 298 return errors.New("gae: too many indexed propert
ies") |
284 } | 299 } |
285 } | 300 } |
286 return nil | 301 return nil |
287 } | 302 } |
288 | 303 |
289 for i, st := range p.c.byIndex { | 304 for i, st := range p.c.byIndex { |
290 if st.name == "-" || st.isExtra { | 305 if st.name == "-" || st.isExtra { |
291 continue | 306 continue |
292 } | 307 } |
293 name := st.name | 308 name := st.name |
294 if prefix != "" { | 309 if prefix != "" { |
295 name = prefix + name | 310 name = prefix + name |
296 } | 311 } |
297 v := p.o.Field(i) | 312 v := p.o.Field(i) |
298 is1 := is | 313 is1 := is |
299 if st.idxSetting == NoIndex { | 314 if st.idxSetting == NoIndex { |
300 is1 = NoIndex | 315 is1 = NoIndex |
301 } | 316 } |
302 if st.isSlice { | 317 if st.isSlice { |
303 for j := 0; j < v.Len(); j++ { | 318 for j := 0; j < v.Len(); j++ { |
304 if err = saveProp(name, is1, v.Index(j), &st); e
rr != nil { | 319 if err = saveProp(name, is1, v.Index(j), &st); e
rr != nil { |
| 320 err = fmt.Errorf("gae: failed to save sl
ice field %q: %v", name, err) |
305 return | 321 return |
306 } | 322 } |
307 } | 323 } |
308 } else { | 324 } else { |
309 if err = saveProp(name, is1, v, &st); err != nil { | 325 if err = saveProp(name, is1, v, &st); err != nil { |
| 326 err = fmt.Errorf("gae: failed to save single fie
ld %q: %v", name, err) |
310 return | 327 return |
311 } | 328 } |
312 } | 329 } |
313 } | 330 } |
314 | 331 |
315 if i, ok := p.c.bySpecial["extra"]; ok { | 332 if i, ok := p.c.bySpecial["extra"]; ok { |
316 if p.c.byIndex[i].name != "-" { | 333 if p.c.byIndex[i].name != "-" { |
317 for fullName, vals := range p.o.Field(i).Interface().(Pr
opertyMap) { | 334 for fullName, vals := range p.o.Field(i).Interface().(Pr
opertyMap) { |
318 if _, ok := propMap[fullName]; !ok { | 335 if _, ok := propMap[fullName]; !ok { |
319 propMap[fullName] = vals | 336 propMap[fullName] = vals |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
363 | 380 |
364 func (p *structPLS) GetAllMeta() PropertyMap { | 381 func (p *structPLS) GetAllMeta() PropertyMap { |
365 needKind := true | 382 needKind := true |
366 ret := make(PropertyMap, len(p.c.byMeta)+1) | 383 ret := make(PropertyMap, len(p.c.byMeta)+1) |
367 for k, idx := range p.c.byMeta { | 384 for k, idx := range p.c.byMeta { |
368 if val, ok := p.getMetaFor(idx); ok { | 385 if val, ok := p.getMetaFor(idx); ok { |
369 p := Property{} | 386 p := Property{} |
370 if err := p.SetValue(val, NoIndex); err != nil { | 387 if err := p.SetValue(val, NoIndex); err != nil { |
371 continue | 388 continue |
372 } | 389 } |
373 » » » ret["$"+k] = []Property{p} | 390 » » » ret["$"+k] = p |
374 } | 391 } |
375 } | 392 } |
376 if needKind { | 393 if needKind { |
377 if _, ok := p.c.byMeta["kind"]; !ok { | 394 if _, ok := p.c.byMeta["kind"]; !ok { |
378 » » » ret["$kind"] = []Property{MkPropertyNI(p.getDefaultKind(
))} | 395 » » » ret["$kind"] = MkPropertyNI(p.getDefaultKind()) |
379 } | 396 } |
380 } | 397 } |
381 return ret | 398 return ret |
382 } | 399 } |
383 | 400 |
384 func (p *structPLS) SetMeta(key string, val interface{}) bool { | 401 func (p *structPLS) SetMeta(key string, val interface{}) bool { |
385 idx, ok := p.c.byMeta[key] | 402 idx, ok := p.c.byMeta[key] |
386 if !ok { | 403 if !ok { |
387 return false | 404 return false |
388 } | 405 } |
(...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
677 switch val { | 694 switch val { |
678 case "on", "On", "true": | 695 case "on", "On", "true": |
679 return true, nil | 696 return true, nil |
680 case "off", "Off", "false": | 697 case "off", "Off", "false": |
681 return false, nil | 698 return false, nil |
682 } | 699 } |
683 return nil, fmt.Errorf("Toggle field has bad/missing default, go
t %q", val) | 700 return nil, fmt.Errorf("Toggle field has bad/missing default, go
t %q", val) |
684 } | 701 } |
685 return nil, fmt.Errorf("helper: meta field with bad type/value %s/%q", t
, val) | 702 return nil, fmt.Errorf("helper: meta field with bad type/value %s/%q", t
, val) |
686 } | 703 } |
OLD | NEW |