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 |
} |