Chromium Code Reviews| Index: service/datastore/properties.go |
| diff --git a/service/datastore/properties.go b/service/datastore/properties.go |
| index dfa91515cca6432f38b102d2a119ca230e3655b5..6b4d1ba1a64236066dc9ff3ff3c731112ac6106e 100644 |
| --- a/service/datastore/properties.go |
| +++ b/service/datastore/properties.go |
| @@ -225,6 +225,10 @@ func PropertyTypeOf(v interface{}, checkValid bool) (PropertyType, error) { |
| // its native datastore-compatible type. e.g. int16 will convert to int64, and |
| // `type Foo string` will convert to `string`. |
| func UpconvertUnderlyingType(o interface{}, t reflect.Type) (interface{}, reflect.Type) { |
|
dnj
2015/08/05 00:38:41
Is this used elsewhere? What's the point of taking
iannucci
2015/08/05 00:58:14
Yes, it's used in Property.SetValue. That said, th
|
| + if o == nil { |
| + return o, t |
| + } |
| + |
| v := reflect.ValueOf(o) |
| switch t.Kind() { |
| case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: |
| @@ -314,22 +318,9 @@ func (p *Property) SetValue(value interface{}, is IndexSetting) (err error) { |
| return |
| } |
| -// PropertyLoadSaver may be implemented by a user type, and Interface will |
| -// use this interface to serialize the type instead of trying to automatically |
| -// create a serialization codec for it with helper.GetPLS. |
| -type PropertyLoadSaver interface { |
| - // Load takes the values from the given map and attempts to save them into |
| - // the underlying object (usually a struct or a PropertyMap). If a fatal |
| - // error occurs, it's returned via error. If non-fatal conversion errors |
| - // occur, error will be a MultiError containing one or more ErrFieldMismatch |
| - // objects. |
| - Load(PropertyMap) error |
| - |
| - // Save returns the current property as a PropertyMap. if withMeta is true, |
| - // then the PropertyMap contains all the metadata (e.g. '$meta' fields) |
| - // which was held by this PropertyLoadSaver. |
| - Save(withMeta bool) (PropertyMap, error) |
| - |
| +// MetaGetter is a subinterface of PropertyLoadSaver, but is also used to |
| +// abstract the meta argument for RawInterface.GetMulti. |
| +type MetaGetter interface { |
| // GetMeta will get information about the field which has the struct tag in |
| // the form of `gae:"$<key>[,<default>]?"`. |
| // |
| @@ -362,6 +353,38 @@ type PropertyLoadSaver interface { |
| // } |
| GetMeta(key string) (interface{}, error) |
| + // GetMetaDefault is GetMeta, but with a default. |
| + // |
| + // If the metadata key is not available, or its type doesn't equal the |
| + // homogenized type of dflt, then dflt will be returned. |
| + // |
| + // Type homogenization: |
| + // signed integer types -> int64 |
| + // bool -> Toggle fields (bool) |
| + // |
| + // Example: |
| + // pls.GetMetaDefault("foo", 100).(int64) |
| + GetMetaDefault(key string, dflt interface{}) interface{} |
| +} |
| + |
| +// PropertyLoadSaver may be implemented by a user type, and Interface will |
| +// use this interface to serialize the type instead of trying to automatically |
| +// create a serialization codec for it with helper.GetPLS. |
| +type PropertyLoadSaver interface { |
| + // Load takes the values from the given map and attempts to save them into |
| + // the underlying object (usually a struct or a PropertyMap). If a fatal |
| + // error occurs, it's returned via error. If non-fatal conversion errors |
| + // occur, error will be a MultiError containing one or more ErrFieldMismatch |
| + // objects. |
| + Load(PropertyMap) error |
| + |
| + // Save returns the current property as a PropertyMap. if withMeta is true, |
| + // then the PropertyMap contains all the metadata (e.g. '$meta' fields) |
| + // which was held by this PropertyLoadSaver. |
| + Save(withMeta bool) (PropertyMap, error) |
| + |
| + MetaGetter |
| + |
| // SetMeta allows you to set the current value of the meta-keyed field. |
| SetMeta(key string, val interface{}) error |
| @@ -435,6 +458,10 @@ func (pm PropertyMap) GetMeta(key string) (interface{}, error) { |
| return v[0].Value(), nil |
| } |
| +func (pm PropertyMap) GetMetaDefault(key string, dflt interface{}) interface{} { |
| + return GetMetaDefaultImpl(pm.GetMeta, key, dflt) |
| +} |
| + |
| // SetMeta implements PropertyLoadSaver.SetMeta. It will only return an error |
| // if `val` has an invalid type (e.g. not one supported by Property). |
| func (pm PropertyMap) SetMeta(key string, val interface{}) error { |
| @@ -450,3 +477,19 @@ func (pm PropertyMap) SetMeta(key string, val interface{}) error { |
| func (pm PropertyMap) Problem() error { |
| return nil |
| } |
| + |
| +// GetMetaDefaultImpl is the implementation of PropertyLoadSaver.GetMetaDefault. |
| +// |
| +// It takes the normal GetMeta function, the key and the default, and returns |
| +// the value according to PropertyLoadSaver.GetMetaDefault. |
| +func GetMetaDefaultImpl(gm func(string) (interface{}, error), key string, dflt interface{}) interface{} { |
| + cur, err := gm(key) |
| + dflt, typ := UpconvertUnderlyingType(dflt, reflect.TypeOf(dflt)) |
|
dnj
2015/08/05 00:38:41
Since you're always calling this anyway, do it abo
iannucci
2015/08/05 00:58:14
Done.
|
| + if err != nil { |
| + return dflt |
| + } |
| + if dflt != nil && reflect.TypeOf(cur) != typ { |
| + return dflt |
| + } |
| + return cur |
| +} |