key.go 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. // Copyright 2014 Google Inc. All Rights Reserved.
  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. package datastore
  15. import (
  16. "bytes"
  17. "encoding/base64"
  18. "encoding/gob"
  19. "errors"
  20. "strconv"
  21. "strings"
  22. "github.com/golang/protobuf/proto"
  23. "golang.org/x/net/context"
  24. pb "google.golang.org/cloud/internal/datastore"
  25. )
  26. // Key represents the datastore key for a stored entity, and is immutable.
  27. type Key struct {
  28. kind string
  29. id int64
  30. name string
  31. parent *Key
  32. namespace string
  33. }
  34. func (k *Key) Kind() string {
  35. return k.kind
  36. }
  37. func (k *Key) ID() int64 {
  38. return k.id
  39. }
  40. func (k *Key) Name() string {
  41. return k.name
  42. }
  43. func (k *Key) Parent() *Key {
  44. return k.parent
  45. }
  46. func (k *Key) SetParent(v *Key) {
  47. if v.Incomplete() {
  48. panic("can't set an incomplete key as parent")
  49. }
  50. k.parent = v
  51. }
  52. func (k *Key) Namespace() string {
  53. return k.namespace
  54. }
  55. // Complete returns whether the key does not refer to a stored entity.
  56. func (k *Key) Incomplete() bool {
  57. return k.name == "" && k.id == 0
  58. }
  59. // valid returns whether the key is valid.
  60. func (k *Key) valid() bool {
  61. if k == nil {
  62. return false
  63. }
  64. for ; k != nil; k = k.parent {
  65. if k.kind == "" {
  66. return false
  67. }
  68. if k.name != "" && k.id != 0 {
  69. return false
  70. }
  71. if k.parent != nil {
  72. if k.parent.Incomplete() {
  73. return false
  74. }
  75. if k.parent.namespace != k.namespace {
  76. return false
  77. }
  78. }
  79. }
  80. return true
  81. }
  82. func (k *Key) Equal(o *Key) bool {
  83. for {
  84. if k == nil || o == nil {
  85. return k == o // if either is nil, both must be nil
  86. }
  87. if k.namespace != o.namespace || k.name != o.name || k.id != o.id || k.kind != o.kind {
  88. return false
  89. }
  90. if k.parent == nil && o.parent == nil {
  91. return true
  92. }
  93. k = k.parent
  94. o = o.parent
  95. }
  96. }
  97. // marshal marshals the key's string representation to the buffer.
  98. func (k *Key) marshal(b *bytes.Buffer) {
  99. if k.parent != nil {
  100. k.parent.marshal(b)
  101. }
  102. b.WriteByte('/')
  103. b.WriteString(k.kind)
  104. b.WriteByte(',')
  105. if k.name != "" {
  106. b.WriteString(k.name)
  107. } else {
  108. b.WriteString(strconv.FormatInt(k.id, 10))
  109. }
  110. }
  111. // String returns a string representation of the key.
  112. func (k *Key) String() string {
  113. if k == nil {
  114. return ""
  115. }
  116. b := bytes.NewBuffer(make([]byte, 0, 512))
  117. k.marshal(b)
  118. return b.String()
  119. }
  120. // Note: Fields not renamed compared to appengine gobKey struct
  121. // This ensures gobs created by appengine can be read here, and vice/versa
  122. type gobKey struct {
  123. Kind string
  124. StringID string
  125. IntID int64
  126. Parent *gobKey
  127. AppID string
  128. Namespace string
  129. }
  130. func keyToGobKey(k *Key) *gobKey {
  131. if k == nil {
  132. return nil
  133. }
  134. return &gobKey{
  135. Kind: k.kind,
  136. StringID: k.name,
  137. IntID: k.id,
  138. Parent: keyToGobKey(k.parent),
  139. Namespace: k.namespace,
  140. }
  141. }
  142. func gobKeyToKey(gk *gobKey) *Key {
  143. if gk == nil {
  144. return nil
  145. }
  146. return &Key{
  147. kind: gk.Kind,
  148. name: gk.StringID,
  149. id: gk.IntID,
  150. parent: gobKeyToKey(gk.Parent),
  151. namespace: gk.Namespace,
  152. }
  153. }
  154. func (k *Key) GobEncode() ([]byte, error) {
  155. buf := new(bytes.Buffer)
  156. if err := gob.NewEncoder(buf).Encode(keyToGobKey(k)); err != nil {
  157. return nil, err
  158. }
  159. return buf.Bytes(), nil
  160. }
  161. func (k *Key) GobDecode(buf []byte) error {
  162. gk := new(gobKey)
  163. if err := gob.NewDecoder(bytes.NewBuffer(buf)).Decode(gk); err != nil {
  164. return err
  165. }
  166. *k = *gobKeyToKey(gk)
  167. return nil
  168. }
  169. func (k *Key) MarshalJSON() ([]byte, error) {
  170. return []byte(`"` + k.Encode() + `"`), nil
  171. }
  172. func (k *Key) UnmarshalJSON(buf []byte) error {
  173. if len(buf) < 2 || buf[0] != '"' || buf[len(buf)-1] != '"' {
  174. return errors.New("datastore: bad JSON key")
  175. }
  176. k2, err := DecodeKey(string(buf[1 : len(buf)-1]))
  177. if err != nil {
  178. return err
  179. }
  180. *k = *k2
  181. return nil
  182. }
  183. // Encode returns an opaque representation of the key
  184. // suitable for use in HTML and URLs.
  185. // This is compatible with the Python and Java runtimes.
  186. func (k *Key) Encode() string {
  187. pKey := keyToProto(k)
  188. b, err := proto.Marshal(pKey)
  189. if err != nil {
  190. panic(err)
  191. }
  192. // Trailing padding is stripped.
  193. return strings.TrimRight(base64.URLEncoding.EncodeToString(b), "=")
  194. }
  195. // DecodeKey decodes a key from the opaque representation returned by Encode.
  196. func DecodeKey(encoded string) (*Key, error) {
  197. // Re-add padding.
  198. if m := len(encoded) % 4; m != 0 {
  199. encoded += strings.Repeat("=", 4-m)
  200. }
  201. b, err := base64.URLEncoding.DecodeString(encoded)
  202. if err != nil {
  203. return nil, err
  204. }
  205. pKey := new(pb.Key)
  206. if err := proto.Unmarshal(b, pKey); err != nil {
  207. return nil, err
  208. }
  209. return protoToKey(pKey)
  210. }
  211. // NewIncompleteKey creates a new incomplete key.
  212. // kind cannot be empty.
  213. func NewIncompleteKey(ctx context.Context, kind string, parent *Key) *Key {
  214. return NewKey(ctx, kind, "", 0, parent)
  215. }
  216. // NewKey creates a new key.
  217. // kind cannot be empty.
  218. // Either one or both of name and id must be zero. If both are zero,
  219. // the key returned is incomplete.
  220. // parent must either be a complete key or nil.
  221. func NewKey(ctx context.Context, kind, name string, id int64, parent *Key) *Key {
  222. return &Key{
  223. kind: kind,
  224. name: name,
  225. id: id,
  226. parent: parent,
  227. namespace: ctxNamespace(ctx),
  228. }
  229. }
  230. // AllocateIDs accepts a slice of incomplete keys and returns a
  231. // slice of complete keys that are guaranteed to be valid in the datastore
  232. func (c *Client) AllocateIDs(ctx context.Context, keys []*Key) ([]*Key, error) {
  233. if keys == nil {
  234. return nil, nil
  235. }
  236. req := &pb.AllocateIdsRequest{Key: multiKeyToProto(keys)}
  237. res := &pb.AllocateIdsResponse{}
  238. if err := c.call(ctx, "allocateIds", req, res); err != nil {
  239. return nil, err
  240. }
  241. return multiProtoToKey(res.Key)
  242. }