Index: service/datastore/serialize/serialize.go |
diff --git a/service/datastore/serialize/serialize.go b/service/datastore/serialize/serialize.go |
index 736010820f222499212728ca30154029a905cc4f..baa6e3280fdfd456cf8ebb8212dbd1faa052734f 100644 |
--- a/service/datastore/serialize/serialize.go |
+++ b/service/datastore/serialize/serialize.go |
@@ -189,16 +189,17 @@ func ReadGeoPoint(buf Buffer) (gp ds.GeoPoint, err error) { |
return |
} |
-// WriteTime writes a time.Time in a byte-sortable way. |
+// WriteTime writes a time.Time to the buffer. |
// |
-// This method truncates the time to microseconds and drops the timezone, |
-// because that's the (undocumented) way that the appengine SDK does it. |
+// The supplied time is rounded via datastore.RoundTime and written as a |
+// microseconds-since-epoch integer to comform to datastore storage standards. |
func WriteTime(buf Buffer, t time.Time) error { |
name, off := t.Zone() |
if name != "UTC" || off != 0 { |
panic(fmt.Errorf("helper: UTC OR DEATH: %s", t)) |
} |
- _, err := cmpbin.WriteInt(buf, t.Unix()*1e6+int64(t.Nanosecond()/1e3)) |
+ |
+ _, err := cmpbin.WriteInt(buf, ds.TimeToInt(t)) |
return err |
} |
@@ -208,48 +209,70 @@ func ReadTime(buf Buffer) (time.Time, error) { |
if err != nil { |
return time.Time{}, err |
} |
- t := time.Unix(v/1e6, (v%1e6)*1e3) |
- if t.IsZero() { |
- return time.Time{}, nil |
- } |
- return t.UTC(), nil |
+ return ds.IntToTime(v), nil |
} |
// WriteProperty writes a Property to the buffer. `context` behaves the same |
// way that it does for WriteKey, but only has an effect if `p` contains a |
-// Key as its Value. |
-func WriteProperty(buf Buffer, context KeyContext, p ds.Property) (err error) { |
+// Key as its IndexValue. |
+func WriteProperty(buf Buffer, context KeyContext, p ds.Property) error { |
+ return writePropertyImpl(buf, context, &p, false) |
+} |
+ |
+// WriteIndexProperty writes a Property to the buffer as its native index type. |
+// `context` behaves the same way that it does for WriteKey, but only has an |
+// effect if `p` contains a Key as its IndexValue. |
+func WriteIndexProperty(buf Buffer, context KeyContext, p ds.Property) error { |
+ return writePropertyImpl(buf, context, &p, true) |
+} |
+ |
+// writePropertyImpl is an implementation of WriteProperty and |
+// WriteIndexProperty. |
+func writePropertyImpl(buf Buffer, context KeyContext, p *ds.Property, index bool) (err error) { |
defer recoverTo(&err) |
- typb := byte(p.Type()) |
+ |
+ it, v := p.IndexTypeAndValue() |
+ if !index { |
+ it = p.Type() |
+ } |
+ typb := byte(it) |
if p.IndexSetting() != ds.NoIndex { |
typb |= 0x80 |
} |
panicIf(buf.WriteByte(typb)) |
- switch p.Type() { |
- case ds.PTNull: |
- case ds.PTBool: |
- b := p.Value().(bool) |
- if b { |
- err = buf.WriteByte(1) |
- } else { |
- err = buf.WriteByte(0) |
+ |
+ err = writeIndexValue(buf, context, v) |
+ return |
+} |
+ |
+// writeIndexValue writes the index value of v to buf. |
+// |
+// v may be one of the return types from ds.Property's GetIndexTypeAndValue |
+// method. |
+func writeIndexValue(buf Buffer, context KeyContext, v interface{}) (err error) { |
+ switch t := v.(type) { |
+ case nil: |
+ case bool: |
+ b := byte(0) |
+ if t { |
+ b = 1 |
} |
- case ds.PTInt: |
- _, err = cmpbin.WriteInt(buf, p.Value().(int64)) |
- case ds.PTFloat: |
- _, err = cmpbin.WriteFloat64(buf, p.Value().(float64)) |
- case ds.PTString: |
- _, err = cmpbin.WriteString(buf, p.Value().(string)) |
- case ds.PTBytes: |
- _, err = cmpbin.WriteBytes(buf, p.Value().([]byte)) |
- case ds.PTTime: |
- err = WriteTime(buf, p.Value().(time.Time)) |
- case ds.PTGeoPoint: |
- err = WriteGeoPoint(buf, p.Value().(ds.GeoPoint)) |
- case ds.PTKey: |
- err = WriteKey(buf, context, p.Value().(*ds.Key)) |
- case ds.PTBlobKey: |
- _, err = cmpbin.WriteString(buf, string(p.Value().(blobstore.Key))) |
+ err = buf.WriteByte(b) |
+ case int64: |
+ _, err = cmpbin.WriteInt(buf, t) |
+ case float64: |
+ _, err = cmpbin.WriteFloat64(buf, t) |
+ case string: |
+ _, err = cmpbin.WriteString(buf, t) |
+ case []byte: |
+ _, err = cmpbin.WriteBytes(buf, t) |
+ case ds.GeoPoint: |
+ err = WriteGeoPoint(buf, t) |
+ case *ds.Key: |
+ err = WriteKey(buf, context, t) |
+ |
+ default: |
+ err = fmt.Errorf("unsupported type: %T", t) |
} |
return |
} |
@@ -301,11 +324,12 @@ func ReadProperty(buf Buffer, context KeyContext, appid, namespace string) (p ds |
return |
} |
-// WritePropertyMap writes an entire PropertyMap to the buffer. `context` behaves the same |
-// way that it does for WriteKey. If WritePropertyMapDeterministic is true, then |
-// the rows will be sorted by property name before they're serialized to buf |
-// (mostly useful for testing, but also potentially useful if you need to make |
-// a hash of the property data). |
+// WritePropertyMap writes an entire PropertyMap to the buffer. `context` |
+// behaves the same way that it does for WriteKey. |
+// |
+// If WritePropertyMapDeterministic is true, then the rows will be sorted by |
+// property name before they're serialized to buf (mostly useful for testing, |
+// but also potentially useful if you need to make a hash of the property data). |
// |
// Write skips metadata keys. |
func WritePropertyMap(buf Buffer, context KeyContext, pm ds.PropertyMap) (err error) { |
@@ -466,7 +490,8 @@ func PropertySlice(vals ds.PropertySlice) SerializedPslice { |
if v.IndexSetting() == ds.NoIndex { |
continue |
} |
- data := ToBytes(v.ForIndex()) |
+ |
+ data := ToBytes(v) |
dataS := string(data) |
if !dups.Add(dataS) { |
continue |
@@ -504,35 +529,29 @@ func PropertyMapPartially(k *ds.Key, pm ds.PropertyMap) (ret SerializedPmap) { |
} |
func toBytesErr(i interface{}, ctx KeyContext) (ret []byte, err error) { |
- buf := &bytes.Buffer{} |
- switch x := i.(type) { |
- case ds.GeoPoint: |
- err = WriteGeoPoint(buf, x) |
+ buf := bytes.Buffer{} |
+ switch t := i.(type) { |
case ds.IndexColumn: |
- err = WriteIndexColumn(buf, x) |
+ err = WriteIndexColumn(&buf, t) |
case ds.IndexDefinition: |
- err = WriteIndexDefinition(buf, x) |
- |
- case *ds.Key: |
- err = WriteKey(buf, ctx, x) |
+ err = WriteIndexDefinition(&buf, t) |
case ds.KeyTok: |
- err = WriteKeyTok(buf, x) |
+ err = WriteKeyTok(&buf, t) |
case ds.Property: |
- err = WriteProperty(buf, ctx, x) |
+ err = WriteIndexProperty(&buf, ctx, t) |
case ds.PropertyMap: |
- err = WritePropertyMap(buf, ctx, x) |
- |
- case time.Time: |
- err = WriteTime(buf, x) |
+ err = WritePropertyMap(&buf, ctx, t) |
default: |
- err = fmt.Errorf("unknown type for ToBytes: %T", i) |
+ _, v := ds.MkProperty(i).IndexTypeAndValue() |
+ err = writeIndexValue(&buf, ctx, v) |
} |
+ |
if err == nil { |
ret = buf.Bytes() |
} |