datastore.go 12 KB

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