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 { | 56 » if p.c.problem != nil { |
57 » » return err | 57 » » panic(p.c.problem) |
58 } | 58 } |
59 | 59 |
60 convFailures := errors.MultiError(nil) | 60 convFailures := errors.MultiError(nil) |
61 | 61 |
62 t := reflect.Type(nil) | 62 t := reflect.Type(nil) |
63 for name, props := range propMap { | 63 for name, props := range propMap { |
64 multiple := len(props) > 1 | 64 multiple := len(props) > 1 |
65 for i, prop := range props { | 65 for i, prop := range props { |
66 if reason := loadInner(p.c, p.o, i, name, prop, multiple ); reason != "" { | 66 if reason := loadInner(p.c, p.o, i, name, prop, multiple ); reason != "" { |
67 if t == nil { | 67 if t == nil { |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
198 } | 198 } |
199 set(pVal) | 199 set(pVal) |
200 } | 200 } |
201 if slice.IsValid() { | 201 if slice.IsValid() { |
202 slice.Set(reflect.Append(slice, v)) | 202 slice.Set(reflect.Append(slice, v)) |
203 } | 203 } |
204 return "" | 204 return "" |
205 } | 205 } |
206 | 206 |
207 func (p *structPLS) Save(withMeta bool) (PropertyMap, error) { | 207 func (p *structPLS) Save(withMeta bool) (PropertyMap, error) { |
208 » if err := p.Problem(); err != nil { | 208 » if p.c.problem != nil { |
209 » » return nil, err | 209 » » panic(p.c.problem) |
210 } | 210 } |
211 | 211 |
212 ret := PropertyMap(nil) | 212 ret := PropertyMap(nil) |
213 if withMeta { | 213 if withMeta { |
214 ret = getMGS(p.o.Addr().Interface()).GetAllMeta() | 214 ret = getMGS(p.o.Addr().Interface()).GetAllMeta() |
215 } else { | 215 } else { |
216 ret = make(PropertyMap, len(p.c.byName)) | 216 ret = make(PropertyMap, len(p.c.byName)) |
217 } | 217 } |
218 if _, err := p.save(ret, "", ShouldIndex); err != nil { | 218 if _, err := p.save(ret, "", ShouldIndex); err != nil { |
219 return nil, err | 219 return nil, err |
220 } | 220 } |
221 return ret, nil | 221 return ret, nil |
222 } | 222 } |
223 | 223 |
224 func (p *structPLS) getDefaultKind() string { | 224 func (p *structPLS) getDefaultKind() string { |
225 if !p.o.IsValid() { | 225 if !p.o.IsValid() { |
226 return "" | 226 return "" |
227 } | 227 } |
228 return p.o.Type().Name() | 228 return p.o.Type().Name() |
229 } | 229 } |
230 | 230 |
231 func (p *structPLS) save(propMap PropertyMap, prefix string, is IndexSetting) (i dxCount int, err error) { | 231 func (p *structPLS) save(propMap PropertyMap, prefix string, is IndexSetting) (i dxCount int, err error) { |
232 » if err = p.Problem(); err != nil { | 232 » if p.c.problem != nil { |
233 » » return | 233 » » panic(p.c.problem) |
234 } | 234 } |
235 | 235 |
236 saveProp := func(name string, si IndexSetting, v reflect.Value, st *stru ctTag) (err error) { | 236 saveProp := func(name string, si IndexSetting, v reflect.Value, st *stru ctTag) (err error) { |
237 if st.substructCodec != nil { | 237 if st.substructCodec != nil { |
238 count, err := (&structPLS{v, st.substructCodec}).save(pr opMap, name, si) | 238 count, err := (&structPLS{v, st.substructCodec}).save(pr opMap, name, si) |
239 if err == nil { | 239 if err == nil { |
240 idxCount += count | 240 idxCount += count |
241 if idxCount > maxIndexedProperties { | 241 if idxCount > maxIndexedProperties { |
242 err = errors.New("gae: too many indexed properties") | 242 err = errors.New("gae: too many indexed properties") |
243 } | 243 } |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
285 } | 285 } |
286 } else { | 286 } else { |
287 if err = saveProp(name, is1, v, &st); err != nil { | 287 if err = saveProp(name, is1, v, &st); err != nil { |
288 return | 288 return |
289 } | 289 } |
290 } | 290 } |
291 } | 291 } |
292 return | 292 return |
293 } | 293 } |
294 | 294 |
295 func (p *structPLS) GetMeta(key string) (interface{}, error) { | 295 func (p *structPLS) GetMeta(key string) (interface{}, bool) { |
296 » if err := p.Problem(); err != nil { | 296 » if p.c.problem != nil { |
297 » » return nil, err | 297 » » panic(p.c.problem) |
298 } | 298 } |
299 | 299 |
300 if idx, ok := p.c.byMeta[key]; ok { | 300 if idx, ok := p.c.byMeta[key]; ok { |
301 if val, ok := p.getMetaFor(idx); ok { | 301 if val, ok := p.getMetaFor(idx); ok { |
302 » » » return val, nil | 302 » » » return val, true |
303 } | 303 } |
304 } else if key == "kind" { | 304 } else if key == "kind" { |
305 » » return p.getDefaultKind(), nil | 305 » » return p.getDefaultKind(), true |
306 } | 306 } |
307 » return nil, ErrMetaFieldUnset | 307 » return nil, false |
308 } | 308 } |
309 | 309 |
310 func (p *structPLS) getMetaFor(idx int) (interface{}, bool) { | 310 func (p *structPLS) getMetaFor(idx int) (interface{}, bool) { |
311 st := p.c.byIndex[idx] | 311 st := p.c.byIndex[idx] |
312 val := st.metaVal | 312 val := st.metaVal |
313 if st.canSet { | 313 if st.canSet { |
314 f := p.o.Field(idx) | 314 f := p.o.Field(idx) |
315 if st.convert { | 315 if st.convert { |
316 prop, err := f.Addr().Interface().(PropertyConverter).To Property() | 316 prop, err := f.Addr().Interface().(PropertyConverter).To Property() |
317 if err != nil { | 317 if err != nil { |
(...skipping 27 matching lines...) Expand all Loading... | |
345 } | 345 } |
346 } | 346 } |
347 if needKind { | 347 if needKind { |
348 if _, ok := p.c.byMeta["kind"]; !ok { | 348 if _, ok := p.c.byMeta["kind"]; !ok { |
349 ret["$kind"] = []Property{MkPropertyNI(p.getDefaultKind( ))} | 349 ret["$kind"] = []Property{MkPropertyNI(p.getDefaultKind( ))} |
350 } | 350 } |
351 } | 351 } |
352 return ret | 352 return ret |
353 } | 353 } |
354 | 354 |
355 func (p *structPLS) GetMetaDefault(key string, def interface{}) interface{} { | 355 func (p *structPLS) SetMeta(key string, val interface{}) bool { |
356 » return GetMetaDefaultImpl(p.GetMeta, key, def) | 356 » if p.c.problem != nil { |
357 } | 357 » » panic(p.c.problem) |
358 » } | |
358 | 359 |
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] | 360 idx, ok := p.c.byMeta[key] |
364 if !ok { | 361 if !ok { |
365 » » return ErrMetaFieldUnset | 362 » » return false |
366 } | 363 } |
367 st := p.c.byIndex[idx] | 364 st := p.c.byIndex[idx] |
368 if !st.canSet { | 365 if !st.canSet { |
369 » » return fmt.Errorf("gae/helper: cannot set meta %q: unexported fi eld", key) | 366 » » return false |
370 } | 367 } |
371 if st.convert { | 368 if st.convert { |
372 » » return p.o.Field(idx).Addr().Interface().(PropertyConverter).Fro mProperty( | 369 » » err := p.o.Field(idx).Addr().Interface().(PropertyConverter).Fro mProperty( |
373 MkPropertyNI(val)) | 370 MkPropertyNI(val)) |
371 return err == nil | |
374 } | 372 } |
375 | 373 |
376 // setting a BoolField | 374 // setting a BoolField |
377 if b, ok := val.(bool); ok { | 375 if b, ok := val.(bool); ok { |
378 if b { | 376 if b { |
379 val = On | 377 val = On |
380 } else { | 378 } else { |
381 val = Off | 379 val = Off |
382 } | 380 } |
383 } | 381 } |
384 f := p.o.Field(idx) | 382 f := p.o.Field(idx) |
385 if val == nil { | 383 if val == nil { |
386 f.Set(reflect.Zero(f.Type())) | 384 f.Set(reflect.Zero(f.Type())) |
387 } else { | 385 } else { |
388 value := reflect.ValueOf(val) | 386 value := reflect.ValueOf(val) |
389 f.Set(value.Convert(f.Type())) | 387 f.Set(value.Convert(f.Type())) |
390 } | 388 } |
391 » return nil | 389 » return true |
392 } | 390 } |
393 | 391 |
394 func (p *structPLS) Problem() error { return p.c.problem } | |
395 | |
396 var ( | 392 var ( |
397 // The RWMutex is chosen intentionally, as the majority of access to the | 393 // 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. | 394 // structCodecs map will be in parallel and will be to read an existing codec. |
399 // There's no reason to serialize goroutines on every | 395 // There's no reason to serialize goroutines on every |
400 // gae.Interface.{Get,Put}{,Multi} call. | 396 // gae.Interface.{Get,Put}{,Multi} call. |
401 structCodecsMutex sync.RWMutex | 397 structCodecsMutex sync.RWMutex |
402 structCodecs = map[reflect.Type]*structCodec{} | 398 structCodecs = map[reflect.Type]*structCodec{} |
403 ) | 399 ) |
404 | 400 |
405 // validPropertyName returns whether name consists of one or more valid Go | 401 // validPropertyName returns whether name consists of one or more valid Go |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
472 st.convert = reflect.PtrTo(ft).Implements(typeOfPropertyConverte r) | 468 st.convert = reflect.PtrTo(ft).Implements(typeOfPropertyConverte r) |
473 switch { | 469 switch { |
474 case name == "": | 470 case name == "": |
475 if !f.Anonymous { | 471 if !f.Anonymous { |
476 name = f.Name | 472 name = f.Name |
477 } | 473 } |
478 case name[0] == '$': | 474 case name[0] == '$': |
479 name = name[1:] | 475 name = name[1:] |
480 if _, ok := c.byMeta[name]; ok { | 476 if _, ok := c.byMeta[name]; ok { |
481 c.problem = me("meta field %q set multiple times ", "$"+name) | 477 c.problem = me("meta field %q set multiple times ", "$"+name) |
482 return | 478 return |
dnj
2015/12/12 02:47:50
I think you should panic when the problem is ident
iannucci
2015/12/12 03:52:22
Ok, now we panic harder (in getCodec).
| |
483 } | 479 } |
484 c.byMeta[name] = i | 480 c.byMeta[name] = i |
485 if !st.convert { | 481 if !st.convert { |
486 mv, err := convertMeta(opts, ft) | 482 mv, err := convertMeta(opts, ft) |
487 if err != nil { | 483 if err != nil { |
488 c.problem = me("meta field %q has bad ty pe: %s", "$"+name, err) | 484 c.problem = me("meta field %q has bad ty pe: %s", "$"+name, err) |
489 return | 485 return |
490 } | 486 } |
491 st.metaVal = mv | 487 st.metaVal = mv |
492 } | 488 } |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
606 switch val { | 602 switch val { |
607 case "on", "On", "true": | 603 case "on", "On", "true": |
608 return true, nil | 604 return true, nil |
609 case "off", "Off", "false": | 605 case "off", "Off", "false": |
610 return false, nil | 606 return false, nil |
611 } | 607 } |
612 return nil, fmt.Errorf("Toggle field has bad/missing default, go t %q", val) | 608 return nil, fmt.Errorf("Toggle field has bad/missing default, go t %q", val) |
613 } | 609 } |
614 return nil, fmt.Errorf("helper: meta field with bad type/value %s/%q", t , val) | 610 return nil, fmt.Errorf("helper: meta field with bad type/value %s/%q", t , val) |
615 } | 611 } |
OLD | NEW |