// Copyright 2019 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package datastore import ( "encoding/base64" "strings" "cloud.google.com/go/datastore/internal/gaepb" "github.com/golang/protobuf/proto" ) // decodeGAEKey attempts to decode the given encoded key generated by the // GAE Datastore package (google.golang.org/appengine/datastore), returning nil // if the key couldn't be decoded. func decodeGAEKey(encoded string) *Key { // Re-add padding. if m := len(encoded) % 4; m != 0 { encoded += strings.Repeat("=", 4-m) } b, err := base64.URLEncoding.DecodeString(encoded) if err != nil { return nil } ref := new(gaepb.Reference) if err := proto.Unmarshal(b, ref); err != nil { return nil } return gaeProtoToKey(ref) } // gaeProtoToKey accepts a GAE Datastore key and converts it to a Cloud Datastore key. // This is adapted from the "protoToKey" function in the appengine/datastore package. // // NOTE(cbro): this is a lossy operation, as GAE Datastore keys include the project/app ID, // but Cloud Datastore keys do not. func gaeProtoToKey(r *gaepb.Reference) *Key { namespace := r.GetNameSpace() var k *Key for _, e := range r.Path.Element { k = &Key{ Kind: e.GetType(), Name: e.GetName(), ID: e.GetId(), Parent: k, Namespace: namespace, } } if !k.valid() { return nil } return k }