| Index: service/datastore/serialize/serialize.go
|
| diff --git a/service/datastore/serialize/serialize.go b/service/datastore/serialize/serialize.go
|
| index 66a6db7289d35d36b1991d6c70423dc4673bc2e9..2c7a7dfce6e8a91d7fe49fa00d32d738eda6e494 100644
|
| --- a/service/datastore/serialize/serialize.go
|
| +++ b/service/datastore/serialize/serialize.go
|
| @@ -337,14 +337,26 @@ func WritePropertyMap(buf Buffer, context KeyContext, pm ds.PropertyMap) (err er
|
| rows := make(sort.StringSlice, 0, len(pm))
|
| tmpBuf := &bytes.Buffer{}
|
| pm, _ = pm.Save(false)
|
| - for name, vals := range pm {
|
| + for name, pdata := range pm {
|
| tmpBuf.Reset()
|
| _, e := cmpbin.WriteString(tmpBuf, name)
|
| panicIf(e)
|
| - _, e = cmpbin.WriteUint(tmpBuf, uint64(len(vals)))
|
| - panicIf(e)
|
| - for _, p := range vals {
|
| - panicIf(WriteProperty(tmpBuf, context, p))
|
| +
|
| + switch t := pdata.(type) {
|
| + case ds.Property:
|
| + _, e = cmpbin.WriteInt(tmpBuf, -1)
|
| + panicIf(e)
|
| + panicIf(WriteProperty(tmpBuf, context, t))
|
| +
|
| + case ds.PropertySlice:
|
| + _, e = cmpbin.WriteInt(tmpBuf, int64(len(t)))
|
| + panicIf(e)
|
| + for _, p := range t {
|
| + panicIf(WriteProperty(tmpBuf, context, p))
|
| + }
|
| +
|
| + default:
|
| + return fmt.Errorf("unknown PropertyData type %T", t)
|
| }
|
| rows = append(rows, tmpBuf.String())
|
| }
|
| @@ -382,19 +394,28 @@ func ReadPropertyMap(buf Buffer, context KeyContext, appid, namespace string) (p
|
| name, _, e = cmpbin.ReadString(buf)
|
| panicIf(e)
|
|
|
| - numProps, _, e := cmpbin.ReadUint(buf)
|
| + numProps, _, e := cmpbin.ReadInt(buf)
|
| panicIf(e)
|
| - if numProps > ReadPropertyMapReasonableLimit {
|
| - err = fmt.Errorf("helper: tried to decode map with huge number of properties %d", numProps)
|
| - return
|
| - }
|
| - props := make([]ds.Property, 0, numProps)
|
| - for j := uint64(0); j < numProps; j++ {
|
| + switch {
|
| + case numProps < 0:
|
| + // Single property.
|
| prop, err = ReadProperty(buf, context, appid, namespace)
|
| panicIf(err)
|
| - props = append(props, prop)
|
| + pm[name] = prop
|
| +
|
| + case uint64(numProps) > ReadPropertyMapReasonableLimit:
|
| + err = fmt.Errorf("helper: tried to decode map with huge number of properties %d", numProps)
|
| + return
|
| +
|
| + default:
|
| + props := make(ds.PropertySlice, 0, numProps)
|
| + for j := int64(0); j < numProps; j++ {
|
| + prop, err = ReadProperty(buf, context, appid, namespace)
|
| + panicIf(err)
|
| + props = append(props, prop)
|
| + }
|
| + pm[name] = props
|
| }
|
| - pm[name] = props
|
| }
|
| return
|
| }
|
| @@ -475,7 +496,7 @@ func ReadIndexDefinition(buf Buffer) (i ds.IndexDefinition, err error) {
|
| return
|
| }
|
|
|
| -// SerializedPslice is all of the serialized DSProperty values in qASC order.
|
| +// SerializedPslice is all of the serialized DSProperty values in ASC order.
|
| type SerializedPslice [][]byte
|
|
|
| func (s SerializedPslice) Len() int { return len(s) }
|
| @@ -483,6 +504,8 @@ func (s SerializedPslice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
| func (s SerializedPslice) Less(i, j int) bool { return bytes.Compare(s[i], s[j]) < 0 }
|
|
|
| // PropertySlice serializes a single row of a DSProperty map.
|
| +//
|
| +// It does not differentiate between single- and multi- properties.
|
| func PropertySlice(vals ds.PropertySlice) SerializedPslice {
|
| dups := stringset.New(0)
|
| ret := make(SerializedPslice, 0, len(vals))
|
| @@ -519,8 +542,8 @@ func PropertyMapPartially(k *ds.Key, pm ds.PropertyMap) (ret SerializedPmap) {
|
| k = k.Parent()
|
| }
|
| }
|
| - for k, vals := range pm {
|
| - newVals := PropertySlice(vals)
|
| + for k := range pm {
|
| + newVals := PropertySlice(pm.Slice(k))
|
| if len(newVals) > 0 {
|
| ret[k] = newVals
|
| }
|
|
|