OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // 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 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
46 var _ PropertyLoadSaver = (*structPLS)(nil) | 46 var _ PropertyLoadSaver = (*structPLS)(nil) |
47 | 47 |
48 // typeMismatchReason returns a string explaining why the property p could not | 48 // typeMismatchReason returns a string explaining why the property p could not |
49 // be stored in an entity field of type v.Type(). | 49 // be stored in an entity field of type v.Type(). |
50 func typeMismatchReason(val interface{}, v reflect.Value) string { | 50 func typeMismatchReason(val interface{}, v reflect.Value) string { |
51 entityType := reflect.TypeOf(val) | 51 entityType := reflect.TypeOf(val) |
52 return fmt.Sprintf("type mismatch: %s versus %v", entityType, v.Type()) | 52 return fmt.Sprintf("type mismatch: %s versus %v", entityType, v.Type()) |
53 } | 53 } |
54 | 54 |
55 func (p *structPLS) Load(propMap PropertyMap) error { | 55 func (p *structPLS) Load(propMap PropertyMap) error { |
56 if err := p.Problem(); err != nil { | |
57 return err | |
58 } | |
59 | |
60 convFailures := errors.MultiError(nil) | 56 convFailures := errors.MultiError(nil) |
61 | 57 |
62 t := reflect.Type(nil) | 58 t := reflect.Type(nil) |
63 for name, props := range propMap { | 59 for name, props := range propMap { |
64 multiple := len(props) > 1 | 60 multiple := len(props) > 1 |
65 for i, prop := range props { | 61 for i, prop := range props { |
66 if reason := loadInner(p.c, p.o, i, name, prop, multiple
); reason != "" { | 62 if reason := loadInner(p.c, p.o, i, name, prop, multiple
); reason != "" { |
67 if t == nil { | 63 if t == nil { |
68 t = p.o.Type() | 64 t = p.o.Type() |
69 } | 65 } |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
198 } | 194 } |
199 set(pVal) | 195 set(pVal) |
200 } | 196 } |
201 if slice.IsValid() { | 197 if slice.IsValid() { |
202 slice.Set(reflect.Append(slice, v)) | 198 slice.Set(reflect.Append(slice, v)) |
203 } | 199 } |
204 return "" | 200 return "" |
205 } | 201 } |
206 | 202 |
207 func (p *structPLS) Save(withMeta bool) (PropertyMap, error) { | 203 func (p *structPLS) Save(withMeta bool) (PropertyMap, error) { |
208 if err := p.Problem(); err != nil { | |
209 return nil, err | |
210 } | |
211 | |
212 ret := PropertyMap(nil) | 204 ret := PropertyMap(nil) |
213 if withMeta { | 205 if withMeta { |
214 ret = getMGS(p.o.Addr().Interface()).GetAllMeta() | 206 ret = getMGS(p.o.Addr().Interface()).GetAllMeta() |
215 } else { | 207 } else { |
216 ret = make(PropertyMap, len(p.c.byName)) | 208 ret = make(PropertyMap, len(p.c.byName)) |
217 } | 209 } |
218 if _, err := p.save(ret, "", ShouldIndex); err != nil { | 210 if _, err := p.save(ret, "", ShouldIndex); err != nil { |
219 return nil, err | 211 return nil, err |
220 } | 212 } |
221 return ret, nil | 213 return ret, nil |
222 } | 214 } |
223 | 215 |
224 func (p *structPLS) getDefaultKind() string { | 216 func (p *structPLS) getDefaultKind() string { |
225 if !p.o.IsValid() { | 217 if !p.o.IsValid() { |
226 return "" | 218 return "" |
227 } | 219 } |
228 return p.o.Type().Name() | 220 return p.o.Type().Name() |
229 } | 221 } |
230 | 222 |
231 func (p *structPLS) save(propMap PropertyMap, prefix string, is IndexSetting) (i
dxCount int, err error) { | 223 func (p *structPLS) save(propMap PropertyMap, prefix string, is IndexSetting) (i
dxCount int, err error) { |
232 if err = p.Problem(); err != nil { | |
233 return | |
234 } | |
235 | |
236 saveProp := func(name string, si IndexSetting, v reflect.Value, st *stru
ctTag) (err error) { | 224 saveProp := func(name string, si IndexSetting, v reflect.Value, st *stru
ctTag) (err error) { |
237 if st.substructCodec != nil { | 225 if st.substructCodec != nil { |
238 count, err := (&structPLS{v, st.substructCodec}).save(pr
opMap, name, si) | 226 count, err := (&structPLS{v, st.substructCodec}).save(pr
opMap, name, si) |
239 if err == nil { | 227 if err == nil { |
240 idxCount += count | 228 idxCount += count |
241 if idxCount > maxIndexedProperties { | 229 if idxCount > maxIndexedProperties { |
242 err = errors.New("gae: too many indexed
properties") | 230 err = errors.New("gae: too many indexed
properties") |
243 } | 231 } |
244 } | 232 } |
245 return err | 233 return err |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
285 } | 273 } |
286 } else { | 274 } else { |
287 if err = saveProp(name, is1, v, &st); err != nil { | 275 if err = saveProp(name, is1, v, &st); err != nil { |
288 return | 276 return |
289 } | 277 } |
290 } | 278 } |
291 } | 279 } |
292 return | 280 return |
293 } | 281 } |
294 | 282 |
295 func (p *structPLS) GetMeta(key string) (interface{}, error) { | 283 func (p *structPLS) GetMeta(key string) (interface{}, bool) { |
296 » if err := p.Problem(); err != nil { | |
297 » » return nil, err | |
298 » } | |
299 | |
300 if idx, ok := p.c.byMeta[key]; ok { | 284 if idx, ok := p.c.byMeta[key]; ok { |
301 if val, ok := p.getMetaFor(idx); ok { | 285 if val, ok := p.getMetaFor(idx); ok { |
302 » » » return val, nil | 286 » » » return val, true |
303 } | 287 } |
304 } else if key == "kind" { | 288 } else if key == "kind" { |
305 » » return p.getDefaultKind(), nil | 289 » » return p.getDefaultKind(), true |
306 } | 290 } |
307 » return nil, ErrMetaFieldUnset | 291 » return nil, false |
308 } | 292 } |
309 | 293 |
310 func (p *structPLS) getMetaFor(idx int) (interface{}, bool) { | 294 func (p *structPLS) getMetaFor(idx int) (interface{}, bool) { |
311 st := p.c.byIndex[idx] | 295 st := p.c.byIndex[idx] |
312 val := st.metaVal | 296 val := st.metaVal |
313 if st.canSet { | 297 if st.canSet { |
314 f := p.o.Field(idx) | 298 f := p.o.Field(idx) |
315 if st.convert { | 299 if st.convert { |
316 prop, err := f.Addr().Interface().(PropertyConverter).To
Property() | 300 prop, err := f.Addr().Interface().(PropertyConverter).To
Property() |
317 if err != nil { | 301 if err != nil { |
(...skipping 27 matching lines...) Expand all Loading... |
345 } | 329 } |
346 } | 330 } |
347 if needKind { | 331 if needKind { |
348 if _, ok := p.c.byMeta["kind"]; !ok { | 332 if _, ok := p.c.byMeta["kind"]; !ok { |
349 ret["$kind"] = []Property{MkPropertyNI(p.getDefaultKind(
))} | 333 ret["$kind"] = []Property{MkPropertyNI(p.getDefaultKind(
))} |
350 } | 334 } |
351 } | 335 } |
352 return ret | 336 return ret |
353 } | 337 } |
354 | 338 |
355 func (p *structPLS) GetMetaDefault(key string, def interface{}) interface{} { | 339 func (p *structPLS) SetMeta(key string, val interface{}) bool { |
356 » return GetMetaDefaultImpl(p.GetMeta, key, def) | |
357 } | |
358 | |
359 func (p *structPLS) SetMeta(key string, val interface{}) (err error) { | |
360 » if err = p.Problem(); err != nil { | |
361 » » return | |
362 » } | |
363 idx, ok := p.c.byMeta[key] | 340 idx, ok := p.c.byMeta[key] |
364 if !ok { | 341 if !ok { |
365 » » return ErrMetaFieldUnset | 342 » » return false |
366 } | 343 } |
367 st := p.c.byIndex[idx] | 344 st := p.c.byIndex[idx] |
368 if !st.canSet { | 345 if !st.canSet { |
369 » » return fmt.Errorf("gae/helper: cannot set meta %q: unexported fi
eld", key) | 346 » » return false |
370 } | 347 } |
371 if st.convert { | 348 if st.convert { |
372 » » return p.o.Field(idx).Addr().Interface().(PropertyConverter).Fro
mProperty( | 349 » » err := p.o.Field(idx).Addr().Interface().(PropertyConverter).Fro
mProperty( |
373 MkPropertyNI(val)) | 350 MkPropertyNI(val)) |
| 351 return err == nil |
374 } | 352 } |
375 | 353 |
376 // setting a BoolField | 354 // setting a BoolField |
377 if b, ok := val.(bool); ok { | 355 if b, ok := val.(bool); ok { |
378 if b { | 356 if b { |
379 val = On | 357 val = On |
380 } else { | 358 } else { |
381 val = Off | 359 val = Off |
382 } | 360 } |
383 } | 361 } |
384 f := p.o.Field(idx) | 362 f := p.o.Field(idx) |
385 if val == nil { | 363 if val == nil { |
386 f.Set(reflect.Zero(f.Type())) | 364 f.Set(reflect.Zero(f.Type())) |
387 } else { | 365 } else { |
388 value := reflect.ValueOf(val) | 366 value := reflect.ValueOf(val) |
389 f.Set(value.Convert(f.Type())) | 367 f.Set(value.Convert(f.Type())) |
390 } | 368 } |
391 » return nil | 369 » return true |
392 } | 370 } |
393 | 371 |
394 func (p *structPLS) Problem() error { return p.c.problem } | |
395 | |
396 var ( | 372 var ( |
397 // The RWMutex is chosen intentionally, as the majority of access to the | 373 // The RWMutex is chosen intentionally, as the majority of access to the |
398 // structCodecs map will be in parallel and will be to read an existing
codec. | 374 // structCodecs map will be in parallel and will be to read an existing
codec. |
399 // There's no reason to serialize goroutines on every | 375 // There's no reason to serialize goroutines on every |
400 // gae.Interface.{Get,Put}{,Multi} call. | 376 // gae.Interface.{Get,Put}{,Multi} call. |
401 structCodecsMutex sync.RWMutex | 377 structCodecsMutex sync.RWMutex |
402 structCodecs = map[reflect.Type]*structCodec{} | 378 structCodecs = map[reflect.Type]*structCodec{} |
403 ) | 379 ) |
404 | 380 |
405 // validPropertyName returns whether name consists of one or more valid Go | 381 // validPropertyName returns whether name consists of one or more valid Go |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
439 } | 415 } |
440 | 416 |
441 me := func(fmtStr string, args ...interface{}) error { | 417 me := func(fmtStr string, args ...interface{}) error { |
442 return fmt.Errorf(fmtStr, args...) | 418 return fmt.Errorf(fmtStr, args...) |
443 } | 419 } |
444 | 420 |
445 c = &structCodec{ | 421 c = &structCodec{ |
446 byIndex: make([]structTag, t.NumField()), | 422 byIndex: make([]structTag, t.NumField()), |
447 byName: make(map[string]int, t.NumField()), | 423 byName: make(map[string]int, t.NumField()), |
448 byMeta: make(map[string]int, t.NumField()), | 424 byMeta: make(map[string]int, t.NumField()), |
| 425 |
449 problem: errRecursiveStruct, // we'll clear this later if it's n
ot recursive | 426 problem: errRecursiveStruct, // we'll clear this later if it's n
ot recursive |
450 } | 427 } |
451 defer func() { | 428 defer func() { |
452 // If the codec has a problem, free up the indexes | 429 // If the codec has a problem, free up the indexes |
453 if c.problem != nil { | 430 if c.problem != nil { |
454 c.byIndex = nil | 431 c.byIndex = nil |
455 c.byName = nil | 432 c.byName = nil |
456 c.byMeta = nil | 433 c.byMeta = nil |
457 } | 434 } |
458 }() | 435 }() |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
606 switch val { | 583 switch val { |
607 case "on", "On", "true": | 584 case "on", "On", "true": |
608 return true, nil | 585 return true, nil |
609 case "off", "Off", "false": | 586 case "off", "Off", "false": |
610 return false, nil | 587 return false, nil |
611 } | 588 } |
612 return nil, fmt.Errorf("Toggle field has bad/missing default, go
t %q", val) | 589 return nil, fmt.Errorf("Toggle field has bad/missing default, go
t %q", val) |
613 } | 590 } |
614 return nil, fmt.Errorf("helper: meta field with bad type/value %s/%q", t
, val) | 591 return nil, fmt.Errorf("helper: meta field with bad type/value %s/%q", t
, val) |
615 } | 592 } |
OLD | NEW |