You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

281 lines
6.6 KiB

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