datastore.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. // Copyright 2011 Google Inc. All rights reserved.
  2. // Use of this source code is governed by the Apache 2.0
  3. // license that can be found in the LICENSE file.
  4. package datastore
  5. import (
  6. "context"
  7. "errors"
  8. "fmt"
  9. "reflect"
  10. "github.com/golang/protobuf/proto"
  11. "google.golang.org/appengine"
  12. "google.golang.org/appengine/internal"
  13. pb "google.golang.org/appengine/internal/datastore"
  14. )
  15. var (
  16. // ErrInvalidEntityType is returned when functions like Get or Next are
  17. // passed a dst or src argument of invalid type.
  18. ErrInvalidEntityType = errors.New("datastore: invalid entity type")
  19. // ErrInvalidKey is returned when an invalid key is presented.
  20. ErrInvalidKey = errors.New("datastore: invalid key")
  21. // ErrNoSuchEntity is returned when no entity was found for a given key.
  22. ErrNoSuchEntity = errors.New("datastore: no such entity")
  23. )
  24. // ErrFieldMismatch is returned when a field is to be loaded into a different
  25. // type than the one it was stored from, or when a field is missing or
  26. // unexported in the destination struct.
  27. // StructType is the type of the struct pointed to by the destination argument
  28. // passed to Get or to Iterator.Next.
  29. type ErrFieldMismatch struct {
  30. StructType reflect.Type
  31. FieldName string
  32. Reason string
  33. }
  34. func (e *ErrFieldMismatch) Error() string {
  35. return fmt.Sprintf("datastore: cannot load field %q into a %q: %s",
  36. e.FieldName, e.StructType, e.Reason)
  37. }
  38. // protoToKey converts a Reference proto to a *Key. If the key is invalid,
  39. // protoToKey will return the invalid key along with ErrInvalidKey.
  40. func protoToKey(r *pb.Reference) (k *Key, err error) {
  41. appID := r.GetApp()
  42. namespace := r.GetNameSpace()
  43. for _, e := range r.Path.Element {
  44. k = &Key{
  45. kind: e.GetType(),
  46. stringID: e.GetName(),
  47. intID: e.GetId(),
  48. parent: k,
  49. appID: appID,
  50. namespace: namespace,
  51. }
  52. if !k.valid() {
  53. return k, ErrInvalidKey
  54. }
  55. }
  56. return
  57. }
  58. // keyToProto converts a *Key to a Reference proto.
  59. func keyToProto(defaultAppID string, k *Key) *pb.Reference {
  60. appID := k.appID
  61. if appID == "" {
  62. appID = defaultAppID
  63. }
  64. n := 0
  65. for i := k; i != nil; i = i.parent {
  66. n++
  67. }
  68. e := make([]*pb.Path_Element, n)
  69. for i := k; i != nil; i = i.parent {
  70. n--
  71. e[n] = &pb.Path_Element{
  72. Type: &i.kind,
  73. }
  74. // At most one of {Name,Id} should be set.
  75. // Neither will be set for incomplete keys.
  76. if i.stringID != "" {
  77. e[n].Name = &i.stringID
  78. } else if i.intID != 0 {
  79. e[n].Id = &i.intID
  80. }
  81. }
  82. var namespace *string
  83. if k.namespace != "" {
  84. namespace = proto.String(k.namespace)
  85. }
  86. return &pb.Reference{
  87. App: proto.String(appID),
  88. NameSpace: namespace,
  89. Path: &pb.Path{
  90. Element: e,
  91. },
  92. }
  93. }
  94. // multiKeyToProto is a batch version of keyToProto.
  95. func multiKeyToProto(appID string, key []*Key) []*pb.Reference {
  96. ret := make([]*pb.Reference, len(key))
  97. for i, k := range key {
  98. ret[i] = keyToProto(appID, k)
  99. }
  100. return ret
  101. }
  102. // multiValid is a batch version of Key.valid. It returns an error, not a
  103. // []bool.
  104. func multiValid(key []*Key) error {
  105. invalid := false
  106. for _, k := range key {
  107. if !k.valid() {
  108. invalid = true
  109. break
  110. }
  111. }
  112. if !invalid {
  113. return nil
  114. }
  115. err := make(appengine.MultiError, len(key))
  116. for i, k := range key {
  117. if !k.valid() {
  118. err[i] = ErrInvalidKey
  119. }
  120. }
  121. return err
  122. }
  123. // It's unfortunate that the two semantically equivalent concepts pb.Reference
  124. // and pb.PropertyValue_ReferenceValue aren't the same type. For example, the
  125. // two have different protobuf field numbers.
  126. // referenceValueToKey is the same as protoToKey except the input is a
  127. // PropertyValue_ReferenceValue instead of a Reference.
  128. func referenceValueToKey(r *pb.PropertyValue_ReferenceValue) (k *Key, err error) {
  129. appID := r.GetApp()
  130. namespace := r.GetNameSpace()
  131. for _, e := range r.Pathelement {
  132. k = &Key{
  133. kind: e.GetType(),
  134. stringID: e.GetName(),
  135. intID: e.GetId(),
  136. parent: k,
  137. appID: appID,
  138. namespace: namespace,
  139. }
  140. if !k.valid() {
  141. return nil, ErrInvalidKey
  142. }
  143. }
  144. return
  145. }
  146. // keyToReferenceValue is the same as keyToProto except the output is a
  147. // PropertyValue_ReferenceValue instead of a Reference.
  148. func keyToReferenceValue(defaultAppID string, k *Key) *pb.PropertyValue_ReferenceValue {
  149. ref := keyToProto(defaultAppID, k)
  150. pe := make([]*pb.PropertyValue_ReferenceValue_PathElement, len(ref.Path.Element))
  151. for i, e := range ref.Path.Element {
  152. pe[i] = &pb.PropertyValue_ReferenceValue_PathElement{
  153. Type: e.Type,
  154. Id: e.Id,
  155. Name: e.Name,
  156. }
  157. }
  158. return &pb.PropertyValue_ReferenceValue{
  159. App: ref.App,
  160. NameSpace: ref.NameSpace,
  161. Pathelement: pe,
  162. }
  163. }
  164. type multiArgType int
  165. const (
  166. multiArgTypeInvalid multiArgType = iota
  167. multiArgTypePropertyLoadSaver
  168. multiArgTypeStruct
  169. multiArgTypeStructPtr
  170. multiArgTypeInterface
  171. )
  172. // checkMultiArg checks that v has type []S, []*S, []I, or []P, for some struct
  173. // type S, for some interface type I, or some non-interface non-pointer type P
  174. // such that P or *P implements PropertyLoadSaver.
  175. //
  176. // It returns what category the slice's elements are, and the reflect.Type
  177. // that represents S, I or P.
  178. //
  179. // As a special case, PropertyList is an invalid type for v.
  180. func checkMultiArg(v reflect.Value) (m multiArgType, elemType reflect.Type) {
  181. if v.Kind() != reflect.Slice {
  182. return multiArgTypeInvalid, nil
  183. }
  184. if v.Type() == typeOfPropertyList {
  185. return multiArgTypeInvalid, nil
  186. }
  187. elemType = v.Type().Elem()
  188. if reflect.PtrTo(elemType).Implements(typeOfPropertyLoadSaver) {
  189. return multiArgTypePropertyLoadSaver, elemType
  190. }
  191. switch elemType.Kind() {
  192. case reflect.Struct:
  193. return multiArgTypeStruct, elemType
  194. case reflect.Interface:
  195. return multiArgTypeInterface, elemType
  196. case reflect.Ptr:
  197. elemType = elemType.Elem()
  198. if elemType.Kind() == reflect.Struct {
  199. return multiArgTypeStructPtr, elemType
  200. }
  201. }
  202. return multiArgTypeInvalid, nil
  203. }
  204. // Get loads the entity stored for k into dst, which must be a struct pointer
  205. // or implement PropertyLoadSaver. If there is no such entity for the key, Get
  206. // returns ErrNoSuchEntity.
  207. //
  208. // The values of dst's unmatched struct fields are not modified, and matching
  209. // slice-typed fields are not reset before appending to them. In particular, it
  210. // is recommended to pass a pointer to a zero valued struct on each Get call.
  211. //
  212. // ErrFieldMismatch is returned when a field is to be loaded into a different
  213. // type than the one it was stored from, or when a field is missing or
  214. // unexported in the destination struct. ErrFieldMismatch is only returned if
  215. // dst is a struct pointer.
  216. func Get(c context.Context, key *Key, dst interface{}) error {
  217. if dst == nil { // GetMulti catches nil interface; we need to catch nil ptr here
  218. return ErrInvalidEntityType
  219. }
  220. err := GetMulti(c, []*Key{key}, []interface{}{dst})
  221. if me, ok := err.(appengine.MultiError); ok {
  222. return me[0]
  223. }
  224. return err
  225. }
  226. // GetMulti is a batch version of Get.
  227. //
  228. // dst must be a []S, []*S, []I or []P, for some struct type S, some interface
  229. // type I, or some non-interface non-pointer type P such that P or *P
  230. // implements PropertyLoadSaver. If an []I, each element must be a valid dst
  231. // for Get: it must be a struct pointer or implement PropertyLoadSaver.
  232. //
  233. // As a special case, PropertyList is an invalid type for dst, even though a
  234. // PropertyList is a slice of structs. It is treated as invalid to avoid being
  235. // mistakenly passed when []PropertyList was intended.
  236. func GetMulti(c context.Context, key []*Key, dst interface{}) error {
  237. v := reflect.ValueOf(dst)
  238. multiArgType, _ := checkMultiArg(v)
  239. if multiArgType == multiArgTypeInvalid {
  240. return errors.New("datastore: dst has invalid type")
  241. }
  242. if len(key) != v.Len() {
  243. return errors.New("datastore: key and dst slices have different length")
  244. }
  245. if len(key) == 0 {
  246. return nil
  247. }
  248. if err := multiValid(key); err != nil {
  249. return err
  250. }
  251. req := &pb.GetRequest{
  252. Key: multiKeyToProto(internal.FullyQualifiedAppID(c), key),
  253. }
  254. res := &pb.GetResponse{}
  255. if err := internal.Call(c, "datastore_v3", "Get", req, res); err != nil {
  256. return err
  257. }
  258. if len(key) != len(res.Entity) {
  259. return errors.New("datastore: internal error: server returned the wrong number of entities")
  260. }
  261. multiErr, any := make(appengine.MultiError, len(key)), false
  262. for i, e := range res.Entity {
  263. if e.Entity == nil {
  264. multiErr[i] = ErrNoSuchEntity
  265. } else {
  266. elem := v.Index(i)
  267. if multiArgType == multiArgTypePropertyLoadSaver || multiArgType == multiArgTypeStruct {
  268. elem = elem.Addr()
  269. }
  270. if multiArgType == multiArgTypeStructPtr && elem.IsNil() {
  271. elem.Set(reflect.New(elem.Type().Elem()))
  272. }
  273. multiErr[i] = loadEntity(elem.Interface(), e.Entity)
  274. }
  275. if multiErr[i] != nil {
  276. any = true
  277. }
  278. }
  279. if any {
  280. return multiErr
  281. }
  282. return nil
  283. }
  284. // Put saves the entity src into the datastore with key k. src must be a struct
  285. // pointer or implement PropertyLoadSaver; if a struct pointer then any
  286. // unexported fields of that struct will be skipped. If k is an incomplete key,
  287. // the returned key will be a unique key generated by the datastore.
  288. func Put(c context.Context, key *Key, src interface{}) (*Key, error) {
  289. k, err := PutMulti(c, []*Key{key}, []interface{}{src})
  290. if err != nil {
  291. if me, ok := err.(appengine.MultiError); ok {
  292. return nil, me[0]
  293. }
  294. return nil, err
  295. }
  296. return k[0], nil
  297. }
  298. // PutMulti is a batch version of Put.
  299. //
  300. // src must satisfy the same conditions as the dst argument to GetMulti.
  301. func PutMulti(c context.Context, key []*Key, src interface{}) ([]*Key, error) {
  302. v := reflect.ValueOf(src)
  303. multiArgType, _ := checkMultiArg(v)
  304. if multiArgType == multiArgTypeInvalid {
  305. return nil, errors.New("datastore: src has invalid type")
  306. }
  307. if len(key) != v.Len() {
  308. return nil, errors.New("datastore: key and src slices have different length")
  309. }
  310. if len(key) == 0 {
  311. return nil, nil
  312. }
  313. appID := internal.FullyQualifiedAppID(c)
  314. if err := multiValid(key); err != nil {
  315. return nil, err
  316. }
  317. req := &pb.PutRequest{}
  318. for i := range key {
  319. elem := v.Index(i)
  320. if multiArgType == multiArgTypePropertyLoadSaver || multiArgType == multiArgTypeStruct {
  321. elem = elem.Addr()
  322. }
  323. sProto, err := saveEntity(appID, key[i], elem.Interface())
  324. if err != nil {
  325. return nil, err
  326. }
  327. req.Entity = append(req.Entity, sProto)
  328. }
  329. res := &pb.PutResponse{}
  330. if err := internal.Call(c, "datastore_v3", "Put", req, res); err != nil {
  331. return nil, err
  332. }
  333. if len(key) != len(res.Key) {
  334. return nil, errors.New("datastore: internal error: server returned the wrong number of keys")
  335. }
  336. ret := make([]*Key, len(key))
  337. for i := range ret {
  338. var err error
  339. ret[i], err = protoToKey(res.Key[i])
  340. if err != nil || ret[i].Incomplete() {
  341. return nil, errors.New("datastore: internal error: server returned an invalid key")
  342. }
  343. }
  344. return ret, nil
  345. }
  346. // Delete deletes the entity for the given key.
  347. func Delete(c context.Context, key *Key) error {
  348. err := DeleteMulti(c, []*Key{key})
  349. if me, ok := err.(appengine.MultiError); ok {
  350. return me[0]
  351. }
  352. return err
  353. }
  354. // DeleteMulti is a batch version of Delete.
  355. func DeleteMulti(c context.Context, key []*Key) error {
  356. if len(key) == 0 {
  357. return nil
  358. }
  359. if err := multiValid(key); err != nil {
  360. return err
  361. }
  362. req := &pb.DeleteRequest{
  363. Key: multiKeyToProto(internal.FullyQualifiedAppID(c), key),
  364. }
  365. res := &pb.DeleteResponse{}
  366. return internal.Call(c, "datastore_v3", "Delete", req, res)
  367. }
  368. func namespaceMod(m proto.Message, namespace string) {
  369. // pb.Query is the only type that has a name_space field.
  370. // All other namespace support in datastore is in the keys.
  371. switch m := m.(type) {
  372. case *pb.Query:
  373. if m.NameSpace == nil {
  374. m.NameSpace = &namespace
  375. }
  376. }
  377. }
  378. func init() {
  379. internal.NamespaceMods["datastore_v3"] = namespaceMod
  380. internal.RegisterErrorCodeMap("datastore_v3", pb.Error_ErrorCode_name)
  381. internal.RegisterTimeoutErrorCode("datastore_v3", int32(pb.Error_TIMEOUT))
  382. }