Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(191)

Unified Diff: service/rawdatastore/properties.go

Issue 1243323002: Refactor a bit. (Closed) Base URL: https://github.com/luci/gae.git@master
Patch Set: fix golint Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « service/rawdatastore/invertible_test.go ('k') | service/rawdatastore/properties_test.go » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: service/rawdatastore/properties.go
diff --git a/properties.go b/service/rawdatastore/properties.go
similarity index 57%
rename from properties.go
rename to service/rawdatastore/properties.go
index c7a7fb8c9f77dbad8cb3a3cc934ac35c3359540a..d6793df63fd62e9d289710d0ab26c54931b67b98 100644
--- a/properties.go
+++ b/service/rawdatastore/properties.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-package gae
+package rawdatastore
import (
"errors"
@@ -10,26 +10,8 @@ import (
"math"
"reflect"
"time"
-)
-
-var (
- // ErrDSMetaFieldUnset is returned from DSPropertyLoadSaver.{Get,Set}Meta
- // implementations when the specified meta key isn't set on the struct at
- // all.
- ErrDSMetaFieldUnset = fmt.Errorf("gae: meta field unset")
-)
-var (
- typeOfBSKey = reflect.TypeOf(BSKey(""))
- typeOfBool = reflect.TypeOf(false)
- typeOfByteSlice = reflect.TypeOf([]byte(nil))
- typeOfDSByteString = reflect.TypeOf(DSByteString(nil))
- typeOfDSGeoPoint = reflect.TypeOf(DSGeoPoint{})
- typeOfDSKey = reflect.TypeOf((*DSKey)(nil)).Elem()
- typeOfFloat64 = reflect.TypeOf(float64(0))
- typeOfInt64 = reflect.TypeOf(int64(0))
- typeOfString = reflect.TypeOf("")
- typeOfTime = reflect.TypeOf(time.Time{})
+ "github.com/luci/gae/service/blobstore"
)
var (
@@ -37,11 +19,13 @@ var (
maxTime = time.Unix(int64(math.MaxInt64)/1e6, (int64(math.MaxInt64)%1e6)*1e3)
)
+// IndexSetting indicates whether or not a Property should be indexed by the
+// datastore.
type IndexSetting bool
+// ShouldIndex is the default, which is why it must assume the zero value,
+// even though it's werid :(.
const (
- // ShouldIndex is the default, which is why it must assume the zero value,
- // even though it's werid :(.
ShouldIndex IndexSetting = false
NoIndex IndexSetting = true
)
@@ -53,74 +37,74 @@ func (i IndexSetting) String() string {
return "ShouldIndex"
}
-// DSProperty is a value plus an indicator of whether the value should be
-// indexed. Name and Multiple are stored in the DSPropertyMap object.
-type DSProperty struct {
+// Property is a value plus an indicator of whether the value should be
+// indexed. Name and Multiple are stored in the PropertyMap object.
+type Property struct {
value interface{}
indexSetting IndexSetting
- propType DSPropertyType
+ propType PropertyType
}
-// MkDSProperty makes a new indexed* DSProperty and returns it. If val is an
+// MkProperty makes a new indexed* Property and returns it. If val is an
// invalid value, this panics (so don't do it). If you want to handle the error
// normally, use SetValue(..., ShouldIndex) instead.
//
// *indexed if val is not an unindexable type like []byte.
-func MkDSProperty(val interface{}) DSProperty {
- ret := DSProperty{}
+func MkProperty(val interface{}) Property {
+ ret := Property{}
if err := ret.SetValue(val, ShouldIndex); err != nil {
panic(err)
}
return ret
}
-// MkDSPropertyNI makes a new DSProperty (with noindex set to true), and returns
+// MkPropertyNI makes a new Property (with noindex set to true), and returns
// it. If val is an invalid value, this panics (so don't do it). If you want to
// handle the error normally, use SetValue(..., NoIndex) instead.
-func MkDSPropertyNI(val interface{}) DSProperty {
- ret := DSProperty{}
+func MkPropertyNI(val interface{}) Property {
+ ret := Property{}
if err := ret.SetValue(val, NoIndex); err != nil {
panic(err)
}
return ret
}
-// DSPropertyConverter may be implemented by the pointer-to a struct field which
-// is serialized by RawDatastore. Its ToDSProperty will be called on save, and
-// it's FromDSProperty will be called on load (from datastore). The method may
+// PropertyConverter may be implemented by the pointer-to a struct field which
+// is serialized by RawDatastore. Its ToProperty will be called on save, and
+// it's FromProperty will be called on load (from datastore). The method may
// do arbitrary computation, and if it encounters an error, may return it. This
-// error will be a fatal error (as defined by DSPropertyLoadSaver) for the
+// error will be a fatal error (as defined by PropertyLoadSaver) for the
// struct conversion.
//
// Example:
// type Complex complex
-// func (c *Complex) ToDSProperty() (ret DSProperty, err error) {
+// func (c *Complex) ToProperty() (ret Property, err error) {
// // something like:
// err = ret.SetValue(fmt.Sprint(*c), true)
// return
// }
-// func (c *Complex) FromDSProperty(p DSProperty) (err error) {
+// func (c *Complex) FromProperty(p Property) (err error) {
// ... load *c from p ...
// }
//
// type MyStruct struct {
// Complexity []Complex // acts like []complex, but can be serialized to DS
// }
-type DSPropertyConverter interface {
+type PropertyConverter interface {
// TODO(riannucci): Allow a convertable to return multiple values. This is
// eminently doable (as long as the single-slice restriction is kept). It
// could also cut down on the amount of reflection necessary when resolving
// a path in a struct (in the struct loading routine in helper).
- ToDSProperty() (DSProperty, error)
- FromDSProperty(DSProperty) error
+ ToProperty() (Property, error)
+ FromProperty(Property) error
}
-// DSPropertyType is a single-byte representation of the type of data contained
-// in a DSProperty. The specific values of this type information are chosen so
+// PropertyType is a single-byte representation of the type of data contained
+// in a Property. The specific values of this type information are chosen so
// that the types sort according to the order of types as sorted by the
// datastore.
-type DSPropertyType byte
+type PropertyType byte
// These constants are in the order described by
// https://cloud.google.com/appengine/docs/go/datastore/entities#Go_Value_type_ordering
@@ -128,10 +112,10 @@ type DSPropertyType byte
// NOTE: this enum can only occupy 7 bits, because we use the high bit to encode
// indexed/non-indexed. See typData.WriteBinary.
const (
- DSPTNull DSPropertyType = iota
- DSPTInt
+ PTNull PropertyType = iota
+ PTInt
- // DSPTTime is a slight divergence from the way that datastore natively stores
+ // PTTime is a slight divergence from the way that datastore natively stores
// time. In datastore, times and integers actually sort together
// (apparently?). This is probably insane, and I don't want to add the
// complexity of field 'meaning' as a sparate concept from the field's 'type'
@@ -141,82 +125,82 @@ const (
// production. My advice is to NOT DO THAT. If you really want this (and you
// probably don't), you should take care of the time.Time <-> int64 conversion
// in your app and just use a property type of int64 (consider using
- // DSPropertyConverter).
- DSPTTime
+ // PropertyConverter).
+ PTTime
- // DSPTBoolFalse and True are also a slight divergence, but not a semantic
+ // PTBoolFalse and True are also a slight divergence, but not a semantic
// one. IIUC, in datastore 'bool' is actually the type and the value is either
// 0 or 1 (taking another byte to store). Since we have plenty of space in
// this type byte, I just merge the value into the type for booleans. If this
// becomes problematic, consider changing this to just pvBool, and then
// encoding a 0 or 1 as a byte in the relevant marshalling routines.
- DSPTBoolFalse
- DSPTBoolTrue
+ PTBoolFalse
+ PTBoolTrue
- DSPTBytes // []byte or datastore.ByteString
- DSPTString // string or string noindex
- DSPTFloat
- DSPTGeoPoint
- DSPTKey
- DSPTBlobKey
+ PTBytes // []byte or datastore.ByteString
+ PTString // string or string noindex
+ PTFloat
+ PTGeoPoint
+ PTKey
+ PTBlobKey
- DSPTUnknown
+ PTUnknown
)
-func (t DSPropertyType) String() string {
+func (t PropertyType) String() string {
switch t {
- case DSPTNull:
- return "DSPTNull"
- case DSPTInt:
- return "DSPTInt"
- case DSPTTime:
- return "DSPTTime"
- case DSPTBoolFalse:
- return "DSPTBoolFalse"
- case DSPTBoolTrue:
- return "DSPTBoolTrue"
- case DSPTBytes:
- return "DSPTBytes"
- case DSPTString:
- return "DSPTString"
- case DSPTFloat:
- return "DSPTFloat"
- case DSPTGeoPoint:
- return "DSPTGeoPoint"
- case DSPTKey:
- return "DSPTKey"
- case DSPTBlobKey:
- return "DSPTBlobKey"
+ case PTNull:
+ return "PTNull"
+ case PTInt:
+ return "PTInt"
+ case PTTime:
+ return "PTTime"
+ case PTBoolFalse:
+ return "PTBoolFalse"
+ case PTBoolTrue:
+ return "PTBoolTrue"
+ case PTBytes:
+ return "PTBytes"
+ case PTString:
+ return "PTString"
+ case PTFloat:
+ return "PTFloat"
+ case PTGeoPoint:
+ return "PTGeoPoint"
+ case PTKey:
+ return "PTKey"
+ case PTBlobKey:
+ return "PTBlobKey"
default:
- return fmt.Sprintf("DSPTUnknown(%02x)", byte(t))
+ return fmt.Sprintf("PTUnknown(%02x)", byte(t))
}
}
-// DSPropertyTypeOf returns the DSPT* type of the given DSProperty-compatible
+// PropertyTypeOf returns the PT* type of the given Property-compatible
// value v. If checkValid is true, this method will also ensure that time.Time
-// and DSGeoPoint have valid values.
-func DSPropertyTypeOf(v interface{}, checkValid bool) (DSPropertyType, error) {
+// and GeoPoint have valid values.
+func PropertyTypeOf(v interface{}, checkValid bool) (PropertyType, error) {
switch x := v.(type) {
case nil:
- return DSPTNull, nil
+ return PTNull, nil
case int64:
- return DSPTInt, nil
+ return PTInt, nil
case float64:
- return DSPTFloat, nil
+ return PTFloat, nil
case bool:
if x {
- return DSPTBoolTrue, nil
+ return PTBoolTrue, nil
}
- return DSPTBoolFalse, nil
- case []byte, DSByteString:
- return DSPTBytes, nil
- case BSKey:
- return DSPTBlobKey, nil
+ return PTBoolFalse, nil
+ case []byte, ByteString:
+ return PTBytes, nil
+ case blobstore.Key:
+ return PTBlobKey, nil
case string:
- return DSPTString, nil
- case DSKey:
+ return PTString, nil
+ case Key:
// TODO(riannucci): Check key for validity in its own namespace?
- return DSPTKey, nil
+ return PTKey, nil
case time.Time:
err := error(nil)
if checkValid && (x.Before(minTime) || x.After(maxTime)) {
@@ -225,22 +209,22 @@ func DSPropertyTypeOf(v interface{}, checkValid bool) (DSPropertyType, error) {
if checkValid && x.Location() != time.UTC {
err = fmt.Errorf("time value has wrong Location: %s", x.Location())
}
- return DSPTTime, err
- case DSGeoPoint:
+ return PTTime, err
+ case GeoPoint:
err := error(nil)
if checkValid && !x.Valid() {
err = errors.New("invalid GeoPoint value")
}
- return DSPTGeoPoint, err
+ return PTGeoPoint, err
default:
- return DSPTUnknown, fmt.Errorf("gae: DSProperty has bad type %T", v)
+ return PTUnknown, fmt.Errorf("gae: Property has bad type %T", v)
}
}
-// DSUpconvertUnderlyingType takes an object o, and attempts to convert it to
+// UpconvertUnderlyingType takes an object o, and attempts to convert it to
// its native datastore-compatible type. e.g. int16 will convert to int64, and
// `type Foo string` will convert to `string`.
-func DSUpconvertUnderlyingType(o interface{}, t reflect.Type) (interface{}, reflect.Type) {
+func UpconvertUnderlyingType(o interface{}, t reflect.Type) (interface{}, reflect.Type) {
v := reflect.ValueOf(o)
switch t.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
@@ -258,13 +242,13 @@ func DSUpconvertUnderlyingType(o interface{}, t reflect.Type) (interface{}, refl
o = v.Float()
t = typeOfFloat64
case reflect.Slice:
- if t != typeOfDSByteString && t.Elem().Kind() == reflect.Uint8 {
+ if t != typeOfByteString && t.Elem().Kind() == reflect.Uint8 {
o = v.Bytes()
t = typeOfByteSlice
}
case reflect.Struct:
if t == typeOfTime {
- // time in a DSProperty can only hold microseconds
+ // time in a Property can only hold microseconds
o = v.Interface().(time.Time).Round(time.Microsecond)
}
}
@@ -274,29 +258,29 @@ func DSUpconvertUnderlyingType(o interface{}, t reflect.Type) (interface{}, refl
// Value returns the current value held by this property. It's guaranteed to
// be a valid value type (i.e. `p.SetValue(p.Value(), true)` will never return
// an error).
-func (p DSProperty) Value() interface{} { return p.value }
+func (p Property) Value() interface{} { return p.value }
// IndexSetting says weather or not the datastore should create indicies for
// this value.
-func (p DSProperty) IndexSetting() IndexSetting { return p.indexSetting }
+func (p Property) IndexSetting() IndexSetting { return p.indexSetting }
-// Type is the DSPT* type of the data contained in Value().
-func (p DSProperty) Type() DSPropertyType { return p.propType }
+// Type is the PT* type of the data contained in Value().
+func (p Property) Type() PropertyType { return p.propType }
-// SetValue sets the Value field of a DSProperty, and ensures that its value
+// SetValue sets the Value field of a Property, and ensures that its value
// conforms to the permissible types. That way, you're guaranteed that if you
-// have a DSProperty, its value is valid.
+// have a Property, its value is valid.
//
// value is the property value. The valid types are:
// - int64
// - bool
// - string
// - float64
-// - DSByteString
-// - DSKey
+// - ByteString
+// - Key
// - time.Time
-// - BSKey
-// - DSGeoPoint
+// - blobstore.Key
+// - GeoPoint
// - []byte (up to 1 megabyte in length)
// This set is smaller than the set of valid struct field types that the
// datastore can load and save. A Property Value cannot be a slice (apart
@@ -311,13 +295,13 @@ func (p DSProperty) Type() DSPropertyType { return p.propType }
// Python's None but not directly representable by a Go struct. Loading
// a nil-valued property into a struct will set that field to the zero
// value.
-func (p *DSProperty) SetValue(value interface{}, is IndexSetting) (err error) {
+func (p *Property) SetValue(value interface{}, is IndexSetting) (err error) {
t := reflect.Type(nil)
- pt := DSPTNull
+ pt := PTNull
if value != nil {
t = reflect.TypeOf(value)
- value, t = DSUpconvertUnderlyingType(value, t)
- if pt, err = DSPropertyTypeOf(value, true); err != nil {
+ value, t = UpconvertUnderlyingType(value, t)
+ if pt, err = PropertyTypeOf(value, true); err != nil {
return
}
}
@@ -330,21 +314,21 @@ func (p *DSProperty) SetValue(value interface{}, is IndexSetting) (err error) {
return
}
-// DSPropertyLoadSaver may be implemented by a user type, and RawDatastore will
+// PropertyLoadSaver may be implemented by a user type, and RawDatastore will
// use this interface to serialize the type instead of trying to automatically
// create a serialization codec for it with helper.GetPLS.
-type DSPropertyLoadSaver interface {
+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 DSPropertyMap). If a fatal
+ // 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 ErrDSFieldMismatch
+ // occur, error will be a MultiError containing one or more ErrFieldMismatch
// objects.
- Load(DSPropertyMap) error
+ Load(PropertyMap) error
- // Save returns the current property as a DSPropertyMap. if withMeta is true,
- // then the DSPropertyMap contains all the metadata (e.g. '$meta' fields)
- // which was held by this DSPropertyLoadSaver.
- Save(withMeta bool) (DSPropertyMap, 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)
// GetMeta will get information about the field which has the struct tag in
// the form of `gae:"$<key>[,<value>]?"`.
@@ -374,48 +358,48 @@ type DSPropertyLoadSaver interface {
Problem() error
}
-// DSPropertyMap represents the contents of a datastore entity in a generic way.
+// PropertyMap represents the contents of a datastore entity in a generic way.
// It maps from property name to a list of property values which correspond to
// that property name. It is the spiritual successor to PropertyList from the
// original SDK.
//
-// DSPropertyMap may contain "meta" values, which are keyed with a '$' prefix.
+// PropertyMap may contain "meta" values, which are keyed with a '$' prefix.
// Technically the datastore allows arbitrary property names, but all of the
// SDKs go out of their way to try to make all property names valid programming
-// language tokens. Special values must correspond to a single DSProperty...
+// language tokens. Special values must correspond to a single Property...
// corresponding to 0 is equivalent to unset, and corresponding to >1 is an
// error. So:
//
// {
-// "$id": {MkDSProperty(1)}, // GetProperty("id") -> 1, nil
-// "$foo": {}, // GetProperty("foo") -> nil, ErrDSMetaFieldUnset
-// // GetProperty("bar") -> nil, ErrDSMetaFieldUnset
+// "$id": {MkProperty(1)}, // GetProperty("id") -> 1, nil
+// "$foo": {}, // GetProperty("foo") -> nil, ErrMetaFieldUnset
+// // GetProperty("bar") -> nil, ErrMetaFieldUnset
// "$meep": {
-// MkDSProperty("hi"),
-// MkDSProperty("there")}, // GetProperty("meep") -> nil, error!
+// MkProperty("hi"),
+// MkProperty("there")}, // GetProperty("meep") -> nil, error!
// }
//
// Additionally, Save returns a copy of the map with the meta keys omitted (e.g.
// these keys are not going to be serialized to the datastore).
-type DSPropertyMap map[string][]DSProperty
+type PropertyMap map[string][]Property
-var _ DSPropertyLoadSaver = DSPropertyMap(nil)
+var _ PropertyLoadSaver = PropertyMap(nil)
-// Load implements DSPropertyLoadSaver.Load
-func (pm DSPropertyMap) Load(props DSPropertyMap) error {
+// Load implements PropertyLoadSaver.Load
+func (pm PropertyMap) Load(props PropertyMap) error {
for k, v := range props {
pm[k] = append(pm[k], v...)
}
return nil
}
-// Save implements DSPropertyLoadSaver.Save by returning a copy of the
+// Save implements PropertyLoadSaver.Save by returning a copy of the
// current map data.
-func (pm DSPropertyMap) Save(withMeta bool) (DSPropertyMap, error) {
+func (pm PropertyMap) Save(withMeta bool) (PropertyMap, error) {
if len(pm) == 0 {
- return DSPropertyMap{}, nil
+ return PropertyMap{}, nil
}
- ret := make(DSPropertyMap, len(pm))
+ ret := make(PropertyMap, len(pm))
for k, v := range pm {
if withMeta || len(k) == 0 || k[0] != '$' {
ret[k] = append(ret[k], v...)
@@ -424,10 +408,13 @@ func (pm DSPropertyMap) Save(withMeta bool) (DSPropertyMap, error) {
return ret, nil
}
-func (pm DSPropertyMap) GetMeta(key string) (interface{}, error) {
+// GetMeta implements PropertyLoadSaver.GetMeta, and returns the current value
+// associated with the metadata key. It may return ErrMetaFieldUnset if the
+// key doesn't exist.
+func (pm PropertyMap) GetMeta(key string) (interface{}, error) {
v, ok := pm["$"+key]
if !ok || len(v) == 0 {
- return nil, ErrDSMetaFieldUnset
+ return nil, ErrMetaFieldUnset
}
if len(v) > 1 {
return nil, errors.New("gae: too many values for Meta key")
@@ -435,15 +422,18 @@ func (pm DSPropertyMap) GetMeta(key string) (interface{}, error) {
return v[0].Value(), nil
}
-func (pm DSPropertyMap) SetMeta(key string, val interface{}) error {
- prop := DSProperty{}
+// 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 {
+ prop := Property{}
if err := prop.SetValue(val, NoIndex); err != nil {
return err
}
- pm["$"+key] = []DSProperty{prop}
+ pm["$"+key] = []Property{prop}
return nil
}
-func (pm DSPropertyMap) Problem() error {
+// Problem implements PropertyLoadSaver.Problem. It ALWAYS returns nil.
+func (pm PropertyMap) Problem() error {
return nil
}
« no previous file with comments | « service/rawdatastore/invertible_test.go ('k') | service/rawdatastore/properties_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698