diff options
Diffstat (limited to 'vendor/google.golang.org/appengine/datastore/datastore.go')
-rw-r--r-- | vendor/google.golang.org/appengine/datastore/datastore.go | 407 |
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 | |||
5 | package datastore | ||
6 | |||
7 | import ( | ||
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 | |||
20 | var ( | ||
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. | ||
35 | type ErrFieldMismatch struct { | ||
36 | StructType reflect.Type | ||
37 | FieldName string | ||
38 | Reason string | ||
39 | } | ||
40 | |||
41 | func (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. | ||
48 | func 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. | ||
68 | func 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. | ||
105 | func 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. | ||
115 | func 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. | ||
141 | func 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. | ||
162 | func 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 | |||
179 | type multiArgType int | ||
180 | |||
181 | const ( | ||
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. | ||
197 | func 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. | ||
234 | func 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. | ||
255 | func 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. | ||
308 | func 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. | ||
322 | func 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. | ||
369 | func 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. | ||
378 | func 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 | |||
392 | func 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 | |||
403 | func 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 | } | ||