Chromium Code Reviews| 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 |