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