1// Copyright 2019 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package datastore
16
17import (
18	"encoding/base64"
19	"strings"
20
21	"cloud.google.com/go/datastore/internal/gaepb"
22	"github.com/golang/protobuf/proto"
23)
24
25// decodeGAEKey attempts to decode the given encoded key generated by the
26// GAE Datastore package (google.golang.org/appengine/datastore), returning nil
27// if the key couldn't be decoded.
28func decodeGAEKey(encoded string) *Key {
29	// Re-add padding.
30	if m := len(encoded) % 4; m != 0 {
31		encoded += strings.Repeat("=", 4-m)
32	}
33
34	b, err := base64.URLEncoding.DecodeString(encoded)
35	if err != nil {
36		return nil
37	}
38	ref := new(gaepb.Reference)
39	if err := proto.Unmarshal(b, ref); err != nil {
40		return nil
41	}
42	return gaeProtoToKey(ref)
43}
44
45// gaeProtoToKey accepts a GAE Datastore key and converts it to a Cloud Datastore key.
46// This is adapted from the "protoToKey" function in the appengine/datastore package.
47//
48// NOTE(cbro): this is a lossy operation, as GAE Datastore keys include the project/app ID,
49// but Cloud Datastore keys do not.
50func gaeProtoToKey(r *gaepb.Reference) *Key {
51	namespace := r.GetNameSpace()
52	var k *Key
53	for _, e := range r.Path.Element {
54		k = &Key{
55			Kind:      e.GetType(),
56			Name:      e.GetName(),
57			ID:        e.GetId(),
58			Parent:    k,
59			Namespace: namespace,
60		}
61	}
62	if !k.valid() {
63		return nil
64	}
65	return k
66}
67