func (t *txnBufState) fixKeys(keys []*datastore.Key) ([]*datastore.Key, error) { lme := errors.NewLazyMultiError(len(keys)) realKeys := []*datastore.Key(nil) for i, key := range keys { if key.Incomplete() { // intentionally call AllocateIDs without lock. start, err := t.parentDS.AllocateIDs(key, 1) if !lme.Assign(i, err) { if realKeys == nil { realKeys = make([]*datastore.Key, len(keys)) copy(realKeys, keys) } aid, ns, toks := key.Split() toks[len(toks)-1].IntID = start realKeys[i] = datastore.NewKeyToks(aid, ns, toks) } } } err := lme.Get() if realKeys != nil { return realKeys, err } return keys, err }
// 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 }
// dsR2F (DS real-to-fake) converts an SDK Key to a ds.Key func dsR2F(k *datastore.Key) *ds.Key { if k == nil { return nil } aid := k.AppID() ns := k.Namespace() count := 0 for nk := k; nk != nil; nk = nk.Parent() { count++ } toks := make([]ds.KeyTok, count) for ; k != nil; k = k.Parent() { count-- toks[count].Kind = k.Kind() toks[count].StringID = k.StringID() toks[count].IntID = k.IntID() } return ds.NewKeyToks(aid, ns, toks) }
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 ds.NewKeyToks(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 } }