PageRenderTime 26ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/appengine/datastore/datastore.go

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