datastore.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  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 contains a Google Cloud Datastore client.
  15. //
  16. // This package is experimental and may make backwards-incompatible changes.
  17. package datastore // import "google.golang.org/cloud/datastore"
  18. import (
  19. "errors"
  20. "fmt"
  21. "reflect"
  22. "github.com/golang/protobuf/proto"
  23. "golang.org/x/net/context"
  24. "google.golang.org/cloud"
  25. pb "google.golang.org/cloud/internal/datastore"
  26. "google.golang.org/cloud/internal/transport"
  27. )
  28. const prodAddr = "https://www.googleapis.com/datastore/v1beta2/datasets/"
  29. const userAgent = "gcloud-golang-datastore/20150727"
  30. const (
  31. // ScopeDatastore grants permissions to view and/or manage datastore entities
  32. ScopeDatastore = "https://www.googleapis.com/auth/datastore"
  33. // ScopeUserEmail grants permission to view the user's email address.
  34. // It is required to access the datastore.
  35. ScopeUserEmail = "https://www.googleapis.com/auth/userinfo.email"
  36. )
  37. // protoClient is an interface for *transport.ProtoClient to support injecting
  38. // fake clients in tests.
  39. type protoClient interface {
  40. Call(context.Context, string, proto.Message, proto.Message) error
  41. }
  42. // Client is a client for reading and writing data in a datastore dataset.
  43. type Client struct {
  44. client protoClient
  45. endpoint string
  46. dataset string // Called dataset by the datastore API, synonym for project ID.
  47. }
  48. // NewClient creates a new Client for a given dataset.
  49. func NewClient(ctx context.Context, projectID string, opts ...cloud.ClientOption) (*Client, error) {
  50. o := []cloud.ClientOption{
  51. cloud.WithEndpoint(prodAddr),
  52. cloud.WithScopes(ScopeDatastore, ScopeUserEmail),
  53. cloud.WithUserAgent(userAgent),
  54. }
  55. o = append(o, opts...)
  56. client, err := transport.NewProtoClient(ctx, o...)
  57. if err != nil {
  58. return nil, fmt.Errorf("dialing: %v", err)
  59. }
  60. return &Client{
  61. client: client,
  62. dataset: projectID,
  63. }, nil
  64. }
  65. var (
  66. // ErrInvalidEntityType is returned when functions like Get or Next are
  67. // passed a dst or src argument of invalid type.
  68. ErrInvalidEntityType = errors.New("datastore: invalid entity type")
  69. // ErrInvalidKey is returned when an invalid key is presented.
  70. ErrInvalidKey = errors.New("datastore: invalid key")
  71. // ErrNoSuchEntity is returned when no entity was found for a given key.
  72. ErrNoSuchEntity = errors.New("datastore: no such entity")
  73. )
  74. type multiArgType int
  75. const (
  76. multiArgTypeInvalid multiArgType = iota
  77. multiArgTypePropertyLoadSaver
  78. multiArgTypeStruct
  79. multiArgTypeStructPtr
  80. multiArgTypeInterface
  81. )
  82. // nsKey is the type of the context.Context key to store the datastore
  83. // namespace.
  84. type nsKey struct{}
  85. // WithNamespace returns a new context that limits the scope its parent
  86. // context with a Datastore namespace.
  87. func WithNamespace(parent context.Context, namespace string) context.Context {
  88. return context.WithValue(parent, nsKey{}, namespace)
  89. }
  90. // ctxNamespace returns the active namespace for a context.
  91. // It defaults to "" if no namespace was specified.
  92. func ctxNamespace(ctx context.Context) string {
  93. v, _ := ctx.Value(nsKey{}).(string)
  94. return v
  95. }
  96. // ErrFieldMismatch is returned when a field is to be loaded into a different
  97. // type than the one it was stored from, or when a field is missing or
  98. // unexported in the destination struct.
  99. // StructType is the type of the struct pointed to by the destination argument
  100. // passed to Get or to Iterator.Next.
  101. type ErrFieldMismatch struct {
  102. StructType reflect.Type
  103. FieldName string
  104. Reason string
  105. }
  106. func (e *ErrFieldMismatch) Error() string {
  107. return fmt.Sprintf("datastore: cannot load field %q into a %q: %s",
  108. e.FieldName, e.StructType, e.Reason)
  109. }
  110. func (c *Client) call(ctx context.Context, method string, req, resp proto.Message) error {
  111. return c.client.Call(ctx, c.dataset+"/"+method, req, resp)
  112. }
  113. func keyToProto(k *Key) *pb.Key {
  114. if k == nil {
  115. return nil
  116. }
  117. // TODO(jbd): Eliminate unrequired allocations.
  118. path := []*pb.Key_PathElement(nil)
  119. for {
  120. el := &pb.Key_PathElement{
  121. Kind: proto.String(k.kind),
  122. }
  123. if k.id != 0 {
  124. el.Id = proto.Int64(k.id)
  125. }
  126. if k.name != "" {
  127. el.Name = proto.String(k.name)
  128. }
  129. path = append([]*pb.Key_PathElement{el}, path...)
  130. if k.parent == nil {
  131. break
  132. }
  133. k = k.parent
  134. }
  135. key := &pb.Key{
  136. PathElement: path,
  137. }
  138. if k.namespace != "" {
  139. key.PartitionId = &pb.PartitionId{
  140. Namespace: proto.String(k.namespace),
  141. }
  142. }
  143. return key
  144. }
  145. // protoToKey decodes a protocol buffer representation of a key into an
  146. // equivalent *Key object.
  147. func protoToKey(p *pb.Key) (*Key, error) {
  148. var key *Key
  149. for _, el := range p.GetPathElement() {
  150. key = &Key{
  151. namespace: p.GetPartitionId().GetNamespace(),
  152. kind: el.GetKind(),
  153. id: el.GetId(),
  154. name: el.GetName(),
  155. parent: key,
  156. }
  157. }
  158. if !key.valid() { // Also detects key == nil.
  159. return nil, ErrInvalidKey
  160. }
  161. return key, nil
  162. }
  163. // multiKeyToProto is a batch version of keyToProto.
  164. func multiKeyToProto(keys []*Key) []*pb.Key {
  165. ret := make([]*pb.Key, len(keys))
  166. for i, k := range keys {
  167. ret[i] = keyToProto(k)
  168. }
  169. return ret
  170. }
  171. // multiKeyToProto is a batch version of keyToProto.
  172. func multiProtoToKey(keys []*pb.Key) ([]*Key, error) {
  173. hasErr := false
  174. ret := make([]*Key, len(keys))
  175. err := make(MultiError, len(keys))
  176. for i, k := range keys {
  177. ret[i], err[i] = protoToKey(k)
  178. if err[i] != nil {
  179. hasErr = true
  180. }
  181. }
  182. if hasErr {
  183. return nil, err
  184. }
  185. return ret, nil
  186. }
  187. // multiValid is a batch version of Key.valid. It returns an error, not a
  188. // []bool.
  189. func multiValid(key []*Key) error {
  190. invalid := false
  191. for _, k := range key {
  192. if !k.valid() {
  193. invalid = true
  194. break
  195. }
  196. }
  197. if !invalid {
  198. return nil
  199. }
  200. err := make(MultiError, len(key))
  201. for i, k := range key {
  202. if !k.valid() {
  203. err[i] = ErrInvalidKey
  204. }
  205. }
  206. return err
  207. }
  208. // checkMultiArg checks that v has type []S, []*S, []I, or []P, for some struct
  209. // type S, for some interface type I, or some non-interface non-pointer type P
  210. // such that P or *P implements PropertyLoadSaver.
  211. //
  212. // It returns what category the slice's elements are, and the reflect.Type
  213. // that represents S, I or P.
  214. //
  215. // As a special case, PropertyList is an invalid type for v.
  216. func checkMultiArg(v reflect.Value) (m multiArgType, elemType reflect.Type) {
  217. if v.Kind() != reflect.Slice {
  218. return multiArgTypeInvalid, nil
  219. }
  220. if v.Type() == typeOfPropertyList {
  221. return multiArgTypeInvalid, nil
  222. }
  223. elemType = v.Type().Elem()
  224. if reflect.PtrTo(elemType).Implements(typeOfPropertyLoadSaver) {
  225. return multiArgTypePropertyLoadSaver, elemType
  226. }
  227. switch elemType.Kind() {
  228. case reflect.Struct:
  229. return multiArgTypeStruct, elemType
  230. case reflect.Interface:
  231. return multiArgTypeInterface, elemType
  232. case reflect.Ptr:
  233. elemType = elemType.Elem()
  234. if elemType.Kind() == reflect.Struct {
  235. return multiArgTypeStructPtr, elemType
  236. }
  237. }
  238. return multiArgTypeInvalid, nil
  239. }
  240. // Get loads the entity stored for key into dst, which must be a struct pointer
  241. // or implement PropertyLoadSaver. If there is no such entity for the key, Get
  242. // returns ErrNoSuchEntity.
  243. //
  244. // The values of dst's unmatched struct fields are not modified, and matching
  245. // slice-typed fields are not reset before appending to them. In particular, it
  246. // is recommended to pass a pointer to a zero valued struct on each Get call.
  247. //
  248. // ErrFieldMismatch is returned when a field is to be loaded into a different
  249. // type than the one it was stored from, or when a field is missing or
  250. // unexported in the destination struct. ErrFieldMismatch is only returned if
  251. // dst is a struct pointer.
  252. func (c *Client) Get(ctx context.Context, key *Key, dst interface{}) error {
  253. if dst == nil { // get catches nil interfaces; we need to catch nil ptr here
  254. return ErrInvalidEntityType
  255. }
  256. err := c.get(ctx, []*Key{key}, []interface{}{dst}, nil)
  257. if me, ok := err.(MultiError); ok {
  258. return me[0]
  259. }
  260. return err
  261. }
  262. // GetMulti is a batch version of Get.
  263. //
  264. // dst must be a []S, []*S, []I or []P, for some struct type S, some interface
  265. // type I, or some non-interface non-pointer type P such that P or *P
  266. // implements PropertyLoadSaver. If an []I, each element must be a valid dst
  267. // for Get: it must be a struct pointer or implement PropertyLoadSaver.
  268. //
  269. // As a special case, PropertyList is an invalid type for dst, even though a
  270. // PropertyList is a slice of structs. It is treated as invalid to avoid being
  271. // mistakenly passed when []PropertyList was intended.
  272. func (c *Client) GetMulti(ctx context.Context, keys []*Key, dst interface{}) error {
  273. return c.get(ctx, keys, dst, nil)
  274. }
  275. func (c *Client) get(ctx context.Context, keys []*Key, dst interface{}, opts *pb.ReadOptions) error {
  276. v := reflect.ValueOf(dst)
  277. multiArgType, _ := checkMultiArg(v)
  278. // Sanity checks
  279. if multiArgType == multiArgTypeInvalid {
  280. return errors.New("datastore: dst has invalid type")
  281. }
  282. if len(keys) != v.Len() {
  283. return errors.New("datastore: keys and dst slices have different length")
  284. }
  285. if len(keys) == 0 {
  286. return nil
  287. }
  288. // Go through keys, validate them, serialize then, and create a dict mapping them to their index
  289. multiErr, any := make(MultiError, len(keys)), false
  290. keyMap := make(map[string]int)
  291. pbKeys := make([]*pb.Key, len(keys))
  292. for i, k := range keys {
  293. if !k.valid() {
  294. multiErr[i] = ErrInvalidKey
  295. any = true
  296. } else {
  297. keyMap[k.String()] = i
  298. pbKeys[i] = keyToProto(k)
  299. }
  300. }
  301. if any {
  302. return multiErr
  303. }
  304. req := &pb.LookupRequest{
  305. Key: pbKeys,
  306. ReadOptions: opts,
  307. }
  308. resp := &pb.LookupResponse{}
  309. if err := c.call(ctx, "lookup", req, resp); err != nil {
  310. return err
  311. }
  312. if len(resp.Deferred) > 0 {
  313. // TODO(jbd): Assess whether we should retry the deferred keys.
  314. return errors.New("datastore: some entities temporarily unavailable")
  315. }
  316. if len(keys) != len(resp.Found)+len(resp.Missing) {
  317. return errors.New("datastore: internal error: server returned the wrong number of entities")
  318. }
  319. for _, e := range resp.Found {
  320. k, err := protoToKey(e.Entity.Key)
  321. if err != nil {
  322. return errors.New("datastore: internal error: server returned an invalid key")
  323. }
  324. index := keyMap[k.String()]
  325. elem := v.Index(index)
  326. if multiArgType == multiArgTypePropertyLoadSaver || multiArgType == multiArgTypeStruct {
  327. elem = elem.Addr()
  328. }
  329. if multiArgType == multiArgTypeStructPtr && elem.IsNil() {
  330. elem.Set(reflect.New(elem.Type().Elem()))
  331. }
  332. if err := loadEntity(elem.Interface(), e.Entity); err != nil {
  333. multiErr[index] = err
  334. any = true
  335. }
  336. }
  337. for _, e := range resp.Missing {
  338. k, err := protoToKey(e.Entity.Key)
  339. if err != nil {
  340. return errors.New("datastore: internal error: server returned an invalid key")
  341. }
  342. multiErr[keyMap[k.String()]] = ErrNoSuchEntity
  343. any = true
  344. }
  345. if any {
  346. return multiErr
  347. }
  348. return nil
  349. }
  350. // Put saves the entity src into the datastore with key k. src must be a struct
  351. // pointer or implement PropertyLoadSaver; if a struct pointer then any
  352. // unexported fields of that struct will be skipped. If k is an incomplete key,
  353. // the returned key will be a unique key generated by the datastore.
  354. func (c *Client) Put(ctx context.Context, key *Key, src interface{}) (*Key, error) {
  355. k, err := c.PutMulti(ctx, []*Key{key}, []interface{}{src})
  356. if err != nil {
  357. if me, ok := err.(MultiError); ok {
  358. return nil, me[0]
  359. }
  360. return nil, err
  361. }
  362. return k[0], nil
  363. }
  364. // PutMulti is a batch version of Put.
  365. //
  366. // src must satisfy the same conditions as the dst argument to GetMulti.
  367. func (c *Client) PutMulti(ctx context.Context, keys []*Key, src interface{}) ([]*Key, error) {
  368. mutation, err := putMutation(keys, src)
  369. if err != nil {
  370. return nil, err
  371. }
  372. // Make the request.
  373. req := &pb.CommitRequest{
  374. Mutation: mutation,
  375. Mode: pb.CommitRequest_NON_TRANSACTIONAL.Enum(),
  376. }
  377. resp := &pb.CommitResponse{}
  378. if err := c.call(ctx, "commit", req, resp); err != nil {
  379. return nil, err
  380. }
  381. // Copy any newly minted keys into the returned keys.
  382. newKeys := make(map[int]int) // Map of index in returned slice to index in response.
  383. ret := make([]*Key, len(keys))
  384. var idx int
  385. for i, key := range keys {
  386. if key.Incomplete() {
  387. // This key will be in the mutation result.
  388. newKeys[i] = idx
  389. idx++
  390. } else {
  391. ret[i] = key
  392. }
  393. }
  394. if len(newKeys) != len(resp.MutationResult.InsertAutoIdKey) {
  395. return nil, errors.New("datastore: internal error: server returned the wrong number of keys")
  396. }
  397. for retI, respI := range newKeys {
  398. ret[retI], err = protoToKey(resp.MutationResult.InsertAutoIdKey[respI])
  399. if err != nil {
  400. return nil, errors.New("datastore: internal error: server returned an invalid key")
  401. }
  402. }
  403. return ret, nil
  404. }
  405. func putMutation(keys []*Key, src interface{}) (*pb.Mutation, error) {
  406. v := reflect.ValueOf(src)
  407. multiArgType, _ := checkMultiArg(v)
  408. if multiArgType == multiArgTypeInvalid {
  409. return nil, errors.New("datastore: src has invalid type")
  410. }
  411. if len(keys) != v.Len() {
  412. return nil, errors.New("datastore: key and src slices have different length")
  413. }
  414. if len(keys) == 0 {
  415. return nil, nil
  416. }
  417. if err := multiValid(keys); err != nil {
  418. return nil, err
  419. }
  420. var upsert, insert []*pb.Entity
  421. for i, k := range keys {
  422. val := reflect.ValueOf(src).Index(i)
  423. // If src is an interface slice []interface{}{ent1, ent2}
  424. if val.Kind() == reflect.Interface && val.Elem().Kind() == reflect.Slice {
  425. val = val.Elem()
  426. }
  427. // If src is a slice of ptrs []*T{ent1, ent2}
  428. if val.Kind() == reflect.Ptr && val.Elem().Kind() == reflect.Slice {
  429. val = val.Elem()
  430. }
  431. p, err := saveEntity(k, val.Interface())
  432. if err != nil {
  433. return nil, fmt.Errorf("datastore: Error while saving %v: %v", k.String(), err)
  434. }
  435. if k.Incomplete() {
  436. insert = append(insert, p)
  437. } else {
  438. upsert = append(upsert, p)
  439. }
  440. }
  441. return &pb.Mutation{
  442. InsertAutoId: insert,
  443. Upsert: upsert,
  444. }, nil
  445. }
  446. // Delete deletes the entity for the given key.
  447. func (c *Client) Delete(ctx context.Context, key *Key) error {
  448. err := c.DeleteMulti(ctx, []*Key{key})
  449. if me, ok := err.(MultiError); ok {
  450. return me[0]
  451. }
  452. return err
  453. }
  454. // DeleteMulti is a batch version of Delete.
  455. func (c *Client) DeleteMulti(ctx context.Context, keys []*Key) error {
  456. mutation, err := deleteMutation(keys)
  457. if err != nil {
  458. return err
  459. }
  460. req := &pb.CommitRequest{
  461. Mutation: mutation,
  462. Mode: pb.CommitRequest_NON_TRANSACTIONAL.Enum(),
  463. }
  464. resp := &pb.CommitResponse{}
  465. return c.call(ctx, "commit", req, resp)
  466. }
  467. func deleteMutation(keys []*Key) (*pb.Mutation, error) {
  468. protoKeys := make([]*pb.Key, len(keys))
  469. for i, k := range keys {
  470. if k.Incomplete() {
  471. return nil, fmt.Errorf("datastore: can't delete the incomplete key: %v", k)
  472. }
  473. protoKeys[i] = keyToProto(k)
  474. }
  475. return &pb.Mutation{
  476. Delete: protoKeys,
  477. }, nil
  478. }