// TODO(riannucci): dedup with datastore/key testing file. func mkKey(aid, ns string, elems ...interface{}) ds.Key { if len(elems)%2 != 0 { panic("odd number of tokens") } toks := make([]ds.KeyTok, len(elems)/2) for i := 0; i < len(elems); i += 2 { toks[i/2].Kind = elems[i].(string) switch x := elems[i+1].(type) { case string: toks[i/2].StringID = x case int: toks[i/2].IntID = int64(x) default: panic("bad token id") } } return dskey.NewToks(aid, ns, toks) }
// 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 dskey.NewToks(actualAid, actualNS, toks), nil }
func maybeIndexValue(val interface{}) interface{} { // It may be the SDK's datastore.indexValue structure (in datastore/load.go). // // Since this is a private type with no methods, we need to use reflection // to get the data out. Ick. rv := reflect.ValueOf(val) if rv.Kind() == reflect.Struct && rv.Type().String() == "datastore.indexValue" { rv = rv.FieldByName("value") if rv.IsValid() && rv.Kind() == reflect.Ptr { // TODO(riannucci): determine if this is how nil IndexValues are stored. // Maybe they're encoded as a PropertyValue with all-nil fields instead? if rv.IsNil() { return nil } rv = rv.Elem() // we're in protobuf land now. if rv.Type().Name() == "PropertyValue" { for i := 0; i < rv.NumField(); i++ { field := rv.Field(i) if field.Kind() == reflect.Ptr { if field.IsNil() { continue } field = field.Elem() switch field.Kind() { case reflect.Int64: return field.Int() case reflect.String: return field.String() case reflect.Bool: return field.Bool() case reflect.Float64: return field.Float() } switch field.Type().Name() { case "PropertyValue_PointValue": // Lat == X, Lng == Y b/c historical resons. return ds.GeoPoint{ Lat: field.FieldByName("X").Float(), Lng: field.FieldByName("Y").Float()} case "PropertyValue_ReferenceValue": aid := field.FieldByName("App").Elem().String() ns := "" if nsf := field.FieldByName("NameSpace"); !nsf.IsNil() { ns = nsf.Elem().String() } elems := field.FieldByName("Pathelement") toks := make([]ds.KeyTok, elems.Len()) for i := range toks { e := elems.Index(i).Elem() toks[i].Kind = e.FieldByName("Type").Elem().String() if iid := e.FieldByName("Id"); !iid.IsNil() { toks[i].IntID = iid.Elem().Int() } if sid := e.FieldByName("Name"); !sid.IsNil() { toks[i].StringID = sid.Elem().String() } } return dskey.NewToks(aid, ns, toks) } panic(fmt.Errorf( "UNKNOWN datastore.indexValue field type: %s", field.Type())) } // there's also the `XXX_unrecognized []byte` field, so don't panic // here. } panic(fmt.Errorf("cannot decode datastore.indexValue (no recognized field): %v", val)) } panic(fmt.Errorf("cannot decode datastore.indexValue (wrong inner type): %v", val)) } panic(fmt.Errorf("cannot decode datastore.indexValue: %v", val)) } else { return val } }