// ReadIndexDefinition reads an IndexDefinition from the buffer. func ReadIndexDefinition(buf Buffer) (i ds.IndexDefinition, err error) { defer recoverTo(&err) i.Kind, _, err = cmpbin.ReadString(buf) panicIf(err) anc, err := buf.ReadByte() panicIf(err) i.Ancestor = anc == 1 for { ctrl := byte(0) ctrl, err = buf.ReadByte() panicIf(err) if ctrl == 0 { break } if len(i.SortBy) > MaxIndexColumns { err = fmt.Errorf("datastore: Got over %d sort orders", MaxIndexColumns) return } sb, err := ReadIndexColumn(buf) panicIf(err) i.SortBy = append(i.SortBy, sb) } return }
// ReadPropertyMap reads a PropertyMap from the buffer. `context` and // friends behave the same way that they do for ReadKey. func ReadPropertyMap(buf Buffer, context KeyContext, appid, namespace string) (pm ds.PropertyMap, err error) { defer recoverTo(&err) numRows := uint64(0) numRows, _, e := cmpbin.ReadUint(buf) panicIf(e) if numRows > ReadPropertyMapReasonableLimit { err = fmt.Errorf("helper: tried to decode map with huge number of rows %d", numRows) return } pm = make(ds.PropertyMap, numRows) name, prop := "", ds.Property{} for i := uint64(0); i < numRows; i++ { name, _, e = cmpbin.ReadString(buf) panicIf(e) numProps, _, e := cmpbin.ReadUint(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++ { prop, err = ReadProperty(buf, context, appid, namespace) panicIf(err) props = append(props, prop) } pm[name] = props } return }
// ReadKey deserializes a key from the buffer. The value of context must match // the value of context that was passed to WriteKey when the key was encoded. // If context == WithoutContext, then the appid and namespace parameters are // used in the decoded Key. Otherwise they're ignored. func ReadKey(buf Buffer, context KeyContext, appid, namespace string) (ret *ds.Key, err error) { defer recoverTo(&err) actualCtx, e := buf.ReadByte() panicIf(e) actualAid, actualNS := "", "" if actualCtx == 1 { actualAid, _, e = cmpbin.ReadString(buf) panicIf(e) actualNS, _, e = cmpbin.ReadString(buf) panicIf(e) } else if actualCtx != 0 { err = fmt.Errorf("helper: expected actualCtx to be 0 or 1, got %d", actualCtx) return } if context == WithoutContext { // overrwrite with the supplied ones actualAid = appid actualNS = namespace } toks := []ds.KeyTok{} for { ctrlByte, e := buf.ReadByte() panicIf(e) if ctrlByte == 0 { break } if len(toks)+1 > ReadKeyNumToksReasonableLimit { err = fmt.Errorf( "helper: tried to decode huge key with > %d tokens", ReadKeyNumToksReasonableLimit) return } tok, e := ReadKeyTok(buf) panicIf(e) toks = append(toks, tok) } return ds.NewKeyToks(actualAid, actualNS, toks), nil }
// ReadIndexColumn reads an IndexColumn from the buffer. func ReadIndexColumn(buf Buffer) (c ds.IndexColumn, err error) { defer recoverTo(&err) dir, err := buf.ReadByte() panicIf(err) c.Descending = dir != 0 c.Property, _, err = cmpbin.ReadString(buf) return }
// ReadProperty reads a Property from the buffer. `context`, `appid`, and // `namespace` behave the same way they do for ReadKey, but only have an // effect if the decoded property has a Key value. func ReadProperty(buf Buffer, context KeyContext, appid, namespace string) (p ds.Property, err error) { val := interface{}(nil) b, err := buf.ReadByte() if err != nil { return } is := ds.ShouldIndex if (b & 0x80) == 0 { is = ds.NoIndex } switch ds.PropertyType(b & 0x7f) { case ds.PTNull: case ds.PTBool: b, err = buf.ReadByte() val = (b != 0) case ds.PTInt: val, _, err = cmpbin.ReadInt(buf) case ds.PTFloat: val, _, err = cmpbin.ReadFloat64(buf) case ds.PTString: val, _, err = cmpbin.ReadString(buf) case ds.PTBytes: val, _, err = cmpbin.ReadBytes(buf) case ds.PTTime: val, err = ReadTime(buf) case ds.PTGeoPoint: val, err = ReadGeoPoint(buf) case ds.PTKey: val, err = ReadKey(buf, context, appid, namespace) case ds.PTBlobKey: s := "" if s, _, err = cmpbin.ReadString(buf); err != nil { break } val = blobstore.Key(s) default: err = fmt.Errorf("read: unknown type! %v", b) } if err == nil { err = p.SetValue(val, is) } return }
// ReadKeyTok reads a KeyTok from the buffer. You usually want ReadKey // instead of this. func ReadKeyTok(buf Buffer) (ret ds.KeyTok, err error) { defer recoverTo(&err) e := error(nil) ret.Kind, _, e = cmpbin.ReadString(buf) panicIf(e) typ, e := buf.ReadByte() panicIf(e) switch ds.PropertyType(typ) { case ds.PTString: ret.StringID, _, err = cmpbin.ReadString(buf) case ds.PTInt: ret.IntID, _, err = cmpbin.ReadInt(buf) if err == nil && ret.IntID <= 0 { err = errors.New("helper: decoded key with empty stringID and zero/negative intID") } default: err = fmt.Errorf("helper: invalid type %s", ds.PropertyType(typ)) } return }
// ReadIndexColumn reads an IndexColumn from the buffer. func ReadIndexColumn(buf Buffer) (c ds.IndexColumn, err error) { defer recoverTo(&err) dir, err := buf.ReadByte() panicIf(err) switch dir { case 0: c.Direction = ds.ASCENDING default: c.Direction = ds.DESCENDING } c.Property, _, err = cmpbin.ReadString(buf) return }