diff options
Diffstat (limited to 'vendor/google.golang.org/appengine/datastore')
-rw-r--r-- | vendor/google.golang.org/appengine/datastore/datastore.go | 407 | ||||
-rw-r--r-- | vendor/google.golang.org/appengine/datastore/doc.go | 361 | ||||
-rw-r--r-- | vendor/google.golang.org/appengine/datastore/key.go | 396 | ||||
-rw-r--r-- | vendor/google.golang.org/appengine/datastore/load.go | 429 | ||||
-rw-r--r-- | vendor/google.golang.org/appengine/datastore/metadata.go | 78 | ||||
-rw-r--r-- | vendor/google.golang.org/appengine/datastore/prop.go | 330 | ||||
-rw-r--r-- | vendor/google.golang.org/appengine/datastore/query.go | 757 | ||||
-rw-r--r-- | vendor/google.golang.org/appengine/datastore/save.go | 333 | ||||
-rw-r--r-- | vendor/google.golang.org/appengine/datastore/transaction.go | 96 |
9 files changed, 3187 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 | } | ||
diff --git a/vendor/google.golang.org/appengine/datastore/doc.go b/vendor/google.golang.org/appengine/datastore/doc.go new file mode 100644 index 0000000..85616cf --- /dev/null +++ b/vendor/google.golang.org/appengine/datastore/doc.go | |||
@@ -0,0 +1,361 @@ | |||
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 | /* | ||
6 | Package datastore provides a client for App Engine's datastore service. | ||
7 | |||
8 | |||
9 | Basic Operations | ||
10 | |||
11 | Entities are the unit of storage and are associated with a key. A key | ||
12 | consists of an optional parent key, a string application ID, a string kind | ||
13 | (also known as an entity type), and either a StringID or an IntID. A | ||
14 | StringID is also known as an entity name or key name. | ||
15 | |||
16 | It is valid to create a key with a zero StringID and a zero IntID; this is | ||
17 | called an incomplete key, and does not refer to any saved entity. Putting an | ||
18 | entity into the datastore under an incomplete key will cause a unique key | ||
19 | to be generated for that entity, with a non-zero IntID. | ||
20 | |||
21 | An entity's contents are a mapping from case-sensitive field names to values. | ||
22 | Valid value types are: | ||
23 | - signed integers (int, int8, int16, int32 and int64), | ||
24 | - bool, | ||
25 | - string, | ||
26 | - float32 and float64, | ||
27 | - []byte (up to 1 megabyte in length), | ||
28 | - any type whose underlying type is one of the above predeclared types, | ||
29 | - ByteString, | ||
30 | - *Key, | ||
31 | - time.Time (stored with microsecond precision), | ||
32 | - appengine.BlobKey, | ||
33 | - appengine.GeoPoint, | ||
34 | - structs whose fields are all valid value types, | ||
35 | - slices of any of the above. | ||
36 | |||
37 | Slices of structs are valid, as are structs that contain slices. However, if | ||
38 | one struct contains another, then at most one of those can be repeated. This | ||
39 | disqualifies recursively defined struct types: any struct T that (directly or | ||
40 | indirectly) contains a []T. | ||
41 | |||
42 | The Get and Put functions load and save an entity's contents. An entity's | ||
43 | contents are typically represented by a struct pointer. | ||
44 | |||
45 | Example code: | ||
46 | |||
47 | type Entity struct { | ||
48 | Value string | ||
49 | } | ||
50 | |||
51 | func handle(w http.ResponseWriter, r *http.Request) { | ||
52 | ctx := appengine.NewContext(r) | ||
53 | |||
54 | k := datastore.NewKey(ctx, "Entity", "stringID", 0, nil) | ||
55 | e := new(Entity) | ||
56 | if err := datastore.Get(ctx, k, e); err != nil { | ||
57 | http.Error(w, err.Error(), 500) | ||
58 | return | ||
59 | } | ||
60 | |||
61 | old := e.Value | ||
62 | e.Value = r.URL.Path | ||
63 | |||
64 | if _, err := datastore.Put(ctx, k, e); err != nil { | ||
65 | http.Error(w, err.Error(), 500) | ||
66 | return | ||
67 | } | ||
68 | |||
69 | w.Header().Set("Content-Type", "text/plain; charset=utf-8") | ||
70 | fmt.Fprintf(w, "old=%q\nnew=%q\n", old, e.Value) | ||
71 | } | ||
72 | |||
73 | GetMulti, PutMulti and DeleteMulti are batch versions of the Get, Put and | ||
74 | Delete functions. They take a []*Key instead of a *Key, and may return an | ||
75 | appengine.MultiError when encountering partial failure. | ||
76 | |||
77 | |||
78 | Properties | ||
79 | |||
80 | An entity's contents can be represented by a variety of types. These are | ||
81 | typically struct pointers, but can also be any type that implements the | ||
82 | PropertyLoadSaver interface. If using a struct pointer, you do not have to | ||
83 | explicitly implement the PropertyLoadSaver interface; the datastore will | ||
84 | automatically convert via reflection. If a struct pointer does implement that | ||
85 | interface then those methods will be used in preference to the default | ||
86 | behavior for struct pointers. Struct pointers are more strongly typed and are | ||
87 | easier to use; PropertyLoadSavers are more flexible. | ||
88 | |||
89 | The actual types passed do not have to match between Get and Put calls or even | ||
90 | across different calls to datastore. It is valid to put a *PropertyList and | ||
91 | get that same entity as a *myStruct, or put a *myStruct0 and get a *myStruct1. | ||
92 | Conceptually, any entity is saved as a sequence of properties, and is loaded | ||
93 | into the destination value on a property-by-property basis. When loading into | ||
94 | a struct pointer, an entity that cannot be completely represented (such as a | ||
95 | missing field) will result in an ErrFieldMismatch error but it is up to the | ||
96 | caller whether this error is fatal, recoverable or ignorable. | ||
97 | |||
98 | By default, for struct pointers, all properties are potentially indexed, and | ||
99 | the property name is the same as the field name (and hence must start with an | ||
100 | upper case letter). | ||
101 | |||
102 | Fields may have a `datastore:"name,options"` tag. The tag name is the | ||
103 | property name, which must be one or more valid Go identifiers joined by ".", | ||
104 | but may start with a lower case letter. An empty tag name means to just use the | ||
105 | field name. A "-" tag name means that the datastore will ignore that field. | ||
106 | |||
107 | The only valid options are "omitempty" and "noindex". | ||
108 | |||
109 | If the options include "omitempty" and the value of the field is empty, then the field will be omitted on Save. | ||
110 | The empty values are false, 0, any nil interface value, and any array, slice, map, or string of length zero. | ||
111 | Struct field values will never be empty. | ||
112 | |||
113 | If options include "noindex" then the field will not be indexed. All fields are indexed | ||
114 | by default. Strings or byte slices longer than 1500 bytes cannot be indexed; | ||
115 | fields used to store long strings and byte slices must be tagged with "noindex" | ||
116 | or they will cause Put operations to fail. | ||
117 | |||
118 | To use multiple options together, separate them by a comma. | ||
119 | The order does not matter. | ||
120 | |||
121 | If the options is "" then the comma may be omitted. | ||
122 | |||
123 | Example code: | ||
124 | |||
125 | // A and B are renamed to a and b. | ||
126 | // A, C and J are not indexed. | ||
127 | // D's tag is equivalent to having no tag at all (E). | ||
128 | // I is ignored entirely by the datastore. | ||
129 | // J has tag information for both the datastore and json packages. | ||
130 | type TaggedStruct struct { | ||
131 | A int `datastore:"a,noindex"` | ||
132 | B int `datastore:"b"` | ||
133 | C int `datastore:",noindex"` | ||
134 | D int `datastore:""` | ||
135 | E int | ||
136 | I int `datastore:"-"` | ||
137 | J int `datastore:",noindex" json:"j"` | ||
138 | } | ||
139 | |||
140 | |||
141 | Structured Properties | ||
142 | |||
143 | If the struct pointed to contains other structs, then the nested or embedded | ||
144 | structs are flattened. For example, given these definitions: | ||
145 | |||
146 | type Inner1 struct { | ||
147 | W int32 | ||
148 | X string | ||
149 | } | ||
150 | |||
151 | type Inner2 struct { | ||
152 | Y float64 | ||
153 | } | ||
154 | |||
155 | type Inner3 struct { | ||
156 | Z bool | ||
157 | } | ||
158 | |||
159 | type Outer struct { | ||
160 | A int16 | ||
161 | I []Inner1 | ||
162 | J Inner2 | ||
163 | Inner3 | ||
164 | } | ||
165 | |||
166 | then an Outer's properties would be equivalent to those of: | ||
167 | |||
168 | type OuterEquivalent struct { | ||
169 | A int16 | ||
170 | IDotW []int32 `datastore:"I.W"` | ||
171 | IDotX []string `datastore:"I.X"` | ||
172 | JDotY float64 `datastore:"J.Y"` | ||
173 | Z bool | ||
174 | } | ||
175 | |||
176 | If Outer's embedded Inner3 field was tagged as `datastore:"Foo"` then the | ||
177 | equivalent field would instead be: FooDotZ bool `datastore:"Foo.Z"`. | ||
178 | |||
179 | If an outer struct is tagged "noindex" then all of its implicit flattened | ||
180 | fields are effectively "noindex". | ||
181 | |||
182 | |||
183 | The PropertyLoadSaver Interface | ||
184 | |||
185 | An entity's contents can also be represented by any type that implements the | ||
186 | PropertyLoadSaver interface. This type may be a struct pointer, but it does | ||
187 | not have to be. The datastore package will call Load when getting the entity's | ||
188 | contents, and Save when putting the entity's contents. | ||
189 | Possible uses include deriving non-stored fields, verifying fields, or indexing | ||
190 | a field only if its value is positive. | ||
191 | |||
192 | Example code: | ||
193 | |||
194 | type CustomPropsExample struct { | ||
195 | I, J int | ||
196 | // Sum is not stored, but should always be equal to I + J. | ||
197 | Sum int `datastore:"-"` | ||
198 | } | ||
199 | |||
200 | func (x *CustomPropsExample) Load(ps []datastore.Property) error { | ||
201 | // Load I and J as usual. | ||
202 | if err := datastore.LoadStruct(x, ps); err != nil { | ||
203 | return err | ||
204 | } | ||
205 | // Derive the Sum field. | ||
206 | x.Sum = x.I + x.J | ||
207 | return nil | ||
208 | } | ||
209 | |||
210 | func (x *CustomPropsExample) Save() ([]datastore.Property, error) { | ||
211 | // Validate the Sum field. | ||
212 | if x.Sum != x.I + x.J { | ||
213 | return nil, errors.New("CustomPropsExample has inconsistent sum") | ||
214 | } | ||
215 | // Save I and J as usual. The code below is equivalent to calling | ||
216 | // "return datastore.SaveStruct(x)", but is done manually for | ||
217 | // demonstration purposes. | ||
218 | return []datastore.Property{ | ||
219 | { | ||
220 | Name: "I", | ||
221 | Value: int64(x.I), | ||
222 | }, | ||
223 | { | ||
224 | Name: "J", | ||
225 | Value: int64(x.J), | ||
226 | }, | ||
227 | }, nil | ||
228 | } | ||
229 | |||
230 | The *PropertyList type implements PropertyLoadSaver, and can therefore hold an | ||
231 | arbitrary entity's contents. | ||
232 | |||
233 | |||
234 | Queries | ||
235 | |||
236 | Queries retrieve entities based on their properties or key's ancestry. Running | ||
237 | a query yields an iterator of results: either keys or (key, entity) pairs. | ||
238 | Queries are re-usable and it is safe to call Query.Run from concurrent | ||
239 | goroutines. Iterators are not safe for concurrent use. | ||
240 | |||
241 | Queries are immutable, and are either created by calling NewQuery, or derived | ||
242 | from an existing query by calling a method like Filter or Order that returns a | ||
243 | new query value. A query is typically constructed by calling NewQuery followed | ||
244 | by a chain of zero or more such methods. These methods are: | ||
245 | - Ancestor and Filter constrain the entities returned by running a query. | ||
246 | - Order affects the order in which they are returned. | ||
247 | - Project constrains the fields returned. | ||
248 | - Distinct de-duplicates projected entities. | ||
249 | - KeysOnly makes the iterator return only keys, not (key, entity) pairs. | ||
250 | - Start, End, Offset and Limit define which sub-sequence of matching entities | ||
251 | to return. Start and End take cursors, Offset and Limit take integers. Start | ||
252 | and Offset affect the first result, End and Limit affect the last result. | ||
253 | If both Start and Offset are set, then the offset is relative to Start. | ||
254 | If both End and Limit are set, then the earliest constraint wins. Limit is | ||
255 | relative to Start+Offset, not relative to End. As a special case, a | ||
256 | negative limit means unlimited. | ||
257 | |||
258 | Example code: | ||
259 | |||
260 | type Widget struct { | ||
261 | Description string | ||
262 | Price int | ||
263 | } | ||
264 | |||
265 | func handle(w http.ResponseWriter, r *http.Request) { | ||
266 | ctx := appengine.NewContext(r) | ||
267 | q := datastore.NewQuery("Widget"). | ||
268 | Filter("Price <", 1000). | ||
269 | Order("-Price") | ||
270 | b := new(bytes.Buffer) | ||
271 | for t := q.Run(ctx); ; { | ||
272 | var x Widget | ||
273 | key, err := t.Next(&x) | ||
274 | if err == datastore.Done { | ||
275 | break | ||
276 | } | ||
277 | if err != nil { | ||
278 | serveError(ctx, w, err) | ||
279 | return | ||
280 | } | ||
281 | fmt.Fprintf(b, "Key=%v\nWidget=%#v\n\n", key, x) | ||
282 | } | ||
283 | w.Header().Set("Content-Type", "text/plain; charset=utf-8") | ||
284 | io.Copy(w, b) | ||
285 | } | ||
286 | |||
287 | |||
288 | Transactions | ||
289 | |||
290 | RunInTransaction runs a function in a transaction. | ||
291 | |||
292 | Example code: | ||
293 | |||
294 | type Counter struct { | ||
295 | Count int | ||
296 | } | ||
297 | |||
298 | func inc(ctx context.Context, key *datastore.Key) (int, error) { | ||
299 | var x Counter | ||
300 | if err := datastore.Get(ctx, key, &x); err != nil && err != datastore.ErrNoSuchEntity { | ||
301 | return 0, err | ||
302 | } | ||
303 | x.Count++ | ||
304 | if _, err := datastore.Put(ctx, key, &x); err != nil { | ||
305 | return 0, err | ||
306 | } | ||
307 | return x.Count, nil | ||
308 | } | ||
309 | |||
310 | func handle(w http.ResponseWriter, r *http.Request) { | ||
311 | ctx := appengine.NewContext(r) | ||
312 | var count int | ||
313 | err := datastore.RunInTransaction(ctx, func(ctx context.Context) error { | ||
314 | var err1 error | ||
315 | count, err1 = inc(ctx, datastore.NewKey(ctx, "Counter", "singleton", 0, nil)) | ||
316 | return err1 | ||
317 | }, nil) | ||
318 | if err != nil { | ||
319 | serveError(ctx, w, err) | ||
320 | return | ||
321 | } | ||
322 | w.Header().Set("Content-Type", "text/plain; charset=utf-8") | ||
323 | fmt.Fprintf(w, "Count=%d", count) | ||
324 | } | ||
325 | |||
326 | |||
327 | Metadata | ||
328 | |||
329 | The datastore package provides access to some of App Engine's datastore | ||
330 | metadata. This metadata includes information about the entity groups, | ||
331 | namespaces, entity kinds, and properties in the datastore, as well as the | ||
332 | property representations for each property. | ||
333 | |||
334 | Example code: | ||
335 | |||
336 | func handle(w http.ResponseWriter, r *http.Request) { | ||
337 | // Print all the kinds in the datastore, with all the indexed | ||
338 | // properties (and their representations) for each. | ||
339 | ctx := appengine.NewContext(r) | ||
340 | |||
341 | kinds, err := datastore.Kinds(ctx) | ||
342 | if err != nil { | ||
343 | serveError(ctx, w, err) | ||
344 | return | ||
345 | } | ||
346 | |||
347 | w.Header().Set("Content-Type", "text/plain; charset=utf-8") | ||
348 | for _, kind := range kinds { | ||
349 | fmt.Fprintf(w, "%s:\n", kind) | ||
350 | props, err := datastore.KindProperties(ctx, kind) | ||
351 | if err != nil { | ||
352 | fmt.Fprintln(w, "\t(unable to retrieve properties)") | ||
353 | continue | ||
354 | } | ||
355 | for p, rep := range props { | ||
356 | fmt.Fprintf(w, "\t-%s (%s)\n", p, strings.Join(rep, ", ")) | ||
357 | } | ||
358 | } | ||
359 | } | ||
360 | */ | ||
361 | package datastore // import "google.golang.org/appengine/datastore" | ||
diff --git a/vendor/google.golang.org/appengine/datastore/key.go b/vendor/google.golang.org/appengine/datastore/key.go new file mode 100644 index 0000000..6ab83ea --- /dev/null +++ b/vendor/google.golang.org/appengine/datastore/key.go | |||
@@ -0,0 +1,396 @@ | |||
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 | "bytes" | ||
9 | "encoding/base64" | ||
10 | "encoding/gob" | ||
11 | "errors" | ||
12 | "fmt" | ||
13 | "strconv" | ||
14 | "strings" | ||
15 | |||
16 | "github.com/golang/protobuf/proto" | ||
17 | "golang.org/x/net/context" | ||
18 | |||
19 | "google.golang.org/appengine/internal" | ||
20 | pb "google.golang.org/appengine/internal/datastore" | ||
21 | ) | ||
22 | |||
23 | type KeyRangeCollisionError struct { | ||
24 | start int64 | ||
25 | end int64 | ||
26 | } | ||
27 | |||
28 | func (e *KeyRangeCollisionError) Error() string { | ||
29 | return fmt.Sprintf("datastore: Collision when attempting to allocate range [%d, %d]", | ||
30 | e.start, e.end) | ||
31 | } | ||
32 | |||
33 | type KeyRangeContentionError struct { | ||
34 | start int64 | ||
35 | end int64 | ||
36 | } | ||
37 | |||
38 | func (e *KeyRangeContentionError) Error() string { | ||
39 | return fmt.Sprintf("datastore: Contention when attempting to allocate range [%d, %d]", | ||
40 | e.start, e.end) | ||
41 | } | ||
42 | |||
43 | // Key represents the datastore key for a stored entity, and is immutable. | ||
44 | type Key struct { | ||
45 | kind string | ||
46 | stringID string | ||
47 | intID int64 | ||
48 | parent *Key | ||
49 | appID string | ||
50 | namespace string | ||
51 | } | ||
52 | |||
53 | // Kind returns the key's kind (also known as entity type). | ||
54 | func (k *Key) Kind() string { | ||
55 | return k.kind | ||
56 | } | ||
57 | |||
58 | // StringID returns the key's string ID (also known as an entity name or key | ||
59 | // name), which may be "". | ||
60 | func (k *Key) StringID() string { | ||
61 | return k.stringID | ||
62 | } | ||
63 | |||
64 | // IntID returns the key's integer ID, which may be 0. | ||
65 | func (k *Key) IntID() int64 { | ||
66 | return k.intID | ||
67 | } | ||
68 | |||
69 | // Parent returns the key's parent key, which may be nil. | ||
70 | func (k *Key) Parent() *Key { | ||
71 | return k.parent | ||
72 | } | ||
73 | |||
74 | // AppID returns the key's application ID. | ||
75 | func (k *Key) AppID() string { | ||
76 | return k.appID | ||
77 | } | ||
78 | |||
79 | // Namespace returns the key's namespace. | ||
80 | func (k *Key) Namespace() string { | ||
81 | return k.namespace | ||
82 | } | ||
83 | |||
84 | // Incomplete returns whether the key does not refer to a stored entity. | ||
85 | // In particular, whether the key has a zero StringID and a zero IntID. | ||
86 | func (k *Key) Incomplete() bool { | ||
87 | return k.stringID == "" && k.intID == 0 | ||
88 | } | ||
89 | |||
90 | // valid returns whether the key is valid. | ||
91 | func (k *Key) valid() bool { | ||
92 | if k == nil { | ||
93 | return false | ||
94 | } | ||
95 | for ; k != nil; k = k.parent { | ||
96 | if k.kind == "" || k.appID == "" { | ||
97 | return false | ||
98 | } | ||
99 | if k.stringID != "" && k.intID != 0 { | ||
100 | return false | ||
101 | } | ||
102 | if k.parent != nil { | ||
103 | if k.parent.Incomplete() { | ||
104 | return false | ||
105 | } | ||
106 | if k.parent.appID != k.appID || k.parent.namespace != k.namespace { | ||
107 | return false | ||
108 | } | ||
109 | } | ||
110 | } | ||
111 | return true | ||
112 | } | ||
113 | |||
114 | // Equal returns whether two keys are equal. | ||
115 | func (k *Key) Equal(o *Key) bool { | ||
116 | for k != nil && o != nil { | ||
117 | if k.kind != o.kind || k.stringID != o.stringID || k.intID != o.intID || k.appID != o.appID || k.namespace != o.namespace { | ||
118 | return false | ||
119 | } | ||
120 | k, o = k.parent, o.parent | ||
121 | } | ||
122 | return k == o | ||
123 | } | ||
124 | |||
125 | // root returns the furthest ancestor of a key, which may be itself. | ||
126 | func (k *Key) root() *Key { | ||
127 | for k.parent != nil { | ||
128 | k = k.parent | ||
129 | } | ||
130 | return k | ||
131 | } | ||
132 | |||
133 | // marshal marshals the key's string representation to the buffer. | ||
134 | func (k *Key) marshal(b *bytes.Buffer) { | ||
135 | if k.parent != nil { | ||
136 | k.parent.marshal(b) | ||
137 | } | ||
138 | b.WriteByte('/') | ||
139 | b.WriteString(k.kind) | ||
140 | b.WriteByte(',') | ||
141 | if k.stringID != "" { | ||
142 | b.WriteString(k.stringID) | ||
143 | } else { | ||
144 | b.WriteString(strconv.FormatInt(k.intID, 10)) | ||
145 | } | ||
146 | } | ||
147 | |||
148 | // String returns a string representation of the key. | ||
149 | func (k *Key) String() string { | ||
150 | if k == nil { | ||
151 | return "" | ||
152 | } | ||
153 | b := bytes.NewBuffer(make([]byte, 0, 512)) | ||
154 | k.marshal(b) | ||
155 | return b.String() | ||
156 | } | ||
157 | |||
158 | type gobKey struct { | ||
159 | Kind string | ||
160 | StringID string | ||
161 | IntID int64 | ||
162 | Parent *gobKey | ||
163 | AppID string | ||
164 | Namespace string | ||
165 | } | ||
166 | |||
167 | func keyToGobKey(k *Key) *gobKey { | ||
168 | if k == nil { | ||
169 | return nil | ||
170 | } | ||
171 | return &gobKey{ | ||
172 | Kind: k.kind, | ||
173 | StringID: k.stringID, | ||
174 | IntID: k.intID, | ||
175 | Parent: keyToGobKey(k.parent), | ||
176 | AppID: k.appID, | ||
177 | Namespace: k.namespace, | ||
178 | } | ||
179 | } | ||
180 | |||
181 | func gobKeyToKey(gk *gobKey) *Key { | ||
182 | if gk == nil { | ||
183 | return nil | ||
184 | } | ||
185 | return &Key{ | ||
186 | kind: gk.Kind, | ||
187 | stringID: gk.StringID, | ||
188 | intID: gk.IntID, | ||
189 | parent: gobKeyToKey(gk.Parent), | ||
190 | appID: gk.AppID, | ||
191 | namespace: gk.Namespace, | ||
192 | } | ||
193 | } | ||
194 | |||
195 | func (k *Key) GobEncode() ([]byte, error) { | ||
196 | buf := new(bytes.Buffer) | ||
197 | if err := gob.NewEncoder(buf).Encode(keyToGobKey(k)); err != nil { | ||
198 | return nil, err | ||
199 | } | ||
200 | return buf.Bytes(), nil | ||
201 | } | ||
202 | |||
203 | func (k *Key) GobDecode(buf []byte) error { | ||
204 | gk := new(gobKey) | ||
205 | if err := gob.NewDecoder(bytes.NewBuffer(buf)).Decode(gk); err != nil { | ||
206 | return err | ||
207 | } | ||
208 | *k = *gobKeyToKey(gk) | ||
209 | return nil | ||
210 | } | ||
211 | |||
212 | func (k *Key) MarshalJSON() ([]byte, error) { | ||
213 | return []byte(`"` + k.Encode() + `"`), nil | ||
214 | } | ||
215 | |||
216 | func (k *Key) UnmarshalJSON(buf []byte) error { | ||
217 | if len(buf) < 2 || buf[0] != '"' || buf[len(buf)-1] != '"' { | ||
218 | return errors.New("datastore: bad JSON key") | ||
219 | } | ||
220 | k2, err := DecodeKey(string(buf[1 : len(buf)-1])) | ||
221 | if err != nil { | ||
222 | return err | ||
223 | } | ||
224 | *k = *k2 | ||
225 | return nil | ||
226 | } | ||
227 | |||
228 | // Encode returns an opaque representation of the key | ||
229 | // suitable for use in HTML and URLs. | ||
230 | // This is compatible with the Python and Java runtimes. | ||
231 | func (k *Key) Encode() string { | ||
232 | ref := keyToProto("", k) | ||
233 | |||
234 | b, err := proto.Marshal(ref) | ||
235 | if err != nil { | ||
236 | panic(err) | ||
237 | } | ||
238 | |||
239 | // Trailing padding is stripped. | ||
240 | return strings.TrimRight(base64.URLEncoding.EncodeToString(b), "=") | ||
241 | } | ||
242 | |||
243 | // DecodeKey decodes a key from the opaque representation returned by Encode. | ||
244 | func DecodeKey(encoded string) (*Key, error) { | ||
245 | // Re-add padding. | ||
246 | if m := len(encoded) % 4; m != 0 { | ||
247 | encoded += strings.Repeat("=", 4-m) | ||
248 | } | ||
249 | |||
250 | b, err := base64.URLEncoding.DecodeString(encoded) | ||
251 | if err != nil { | ||
252 | return nil, err | ||
253 | } | ||
254 | |||
255 | ref := new(pb.Reference) | ||
256 | if err := proto.Unmarshal(b, ref); err != nil { | ||
257 | return nil, err | ||
258 | } | ||
259 | |||
260 | return protoToKey(ref) | ||
261 | } | ||
262 | |||
263 | // NewIncompleteKey creates a new incomplete key. | ||
264 | // kind cannot be empty. | ||
265 | func NewIncompleteKey(c context.Context, kind string, parent *Key) *Key { | ||
266 | return NewKey(c, kind, "", 0, parent) | ||
267 | } | ||
268 | |||
269 | // NewKey creates a new key. | ||
270 | // kind cannot be empty. | ||
271 | // Either one or both of stringID and intID must be zero. If both are zero, | ||
272 | // the key returned is incomplete. | ||
273 | // parent must either be a complete key or nil. | ||
274 | func NewKey(c context.Context, kind, stringID string, intID int64, parent *Key) *Key { | ||
275 | // If there's a parent key, use its namespace. | ||
276 | // Otherwise, use any namespace attached to the context. | ||
277 | var namespace string | ||
278 | if parent != nil { | ||
279 | namespace = parent.namespace | ||
280 | } else { | ||
281 | namespace = internal.NamespaceFromContext(c) | ||
282 | } | ||
283 | |||
284 | return &Key{ | ||
285 | kind: kind, | ||
286 | stringID: stringID, | ||
287 | intID: intID, | ||
288 | parent: parent, | ||
289 | appID: internal.FullyQualifiedAppID(c), | ||
290 | namespace: namespace, | ||
291 | } | ||
292 | } | ||
293 | |||
294 | // AllocateIDs returns a range of n integer IDs with the given kind and parent | ||
295 | // combination. kind cannot be empty; parent may be nil. The IDs in the range | ||
296 | // returned will not be used by the datastore's automatic ID sequence generator | ||
297 | // and may be used with NewKey without conflict. | ||
298 | // | ||
299 | // The range is inclusive at the low end and exclusive at the high end. In | ||
300 | // other words, valid intIDs x satisfy low <= x && x < high. | ||
301 | // | ||
302 | // If no error is returned, low + n == high. | ||
303 | func AllocateIDs(c context.Context, kind string, parent *Key, n int) (low, high int64, err error) { | ||
304 | if kind == "" { | ||
305 | return 0, 0, errors.New("datastore: AllocateIDs given an empty kind") | ||
306 | } | ||
307 | if n < 0 { | ||
308 | return 0, 0, fmt.Errorf("datastore: AllocateIDs given a negative count: %d", n) | ||
309 | } | ||
310 | if n == 0 { | ||
311 | return 0, 0, nil | ||
312 | } | ||
313 | req := &pb.AllocateIdsRequest{ | ||
314 | ModelKey: keyToProto("", NewIncompleteKey(c, kind, parent)), | ||
315 | Size: proto.Int64(int64(n)), | ||
316 | } | ||
317 | res := &pb.AllocateIdsResponse{} | ||
318 | if err := internal.Call(c, "datastore_v3", "AllocateIds", req, res); err != nil { | ||
319 | return 0, 0, err | ||
320 | } | ||
321 | // The protobuf is inclusive at both ends. Idiomatic Go (e.g. slices, for loops) | ||
322 | // is inclusive at the low end and exclusive at the high end, so we add 1. | ||
323 | low = res.GetStart() | ||
324 | high = res.GetEnd() + 1 | ||
325 | if low+int64(n) != high { | ||
326 | return 0, 0, fmt.Errorf("datastore: internal error: could not allocate %d IDs", n) | ||
327 | } | ||
328 | return low, high, nil | ||
329 | } | ||
330 | |||
331 | // AllocateIDRange allocates a range of IDs with specific endpoints. | ||
332 | // The range is inclusive at both the low and high end. Once these IDs have been | ||
333 | // allocated, you can manually assign them to newly created entities. | ||
334 | // | ||
335 | // The Datastore's automatic ID allocator never assigns a key that has already | ||
336 | // been allocated (either through automatic ID allocation or through an explicit | ||
337 | // AllocateIDs call). As a result, entities written to the given key range will | ||
338 | // never be overwritten. However, writing entities with manually assigned keys in | ||
339 | // this range may overwrite existing entities (or new entities written by a separate | ||
340 | // request), depending on the error returned. | ||
341 | // | ||
342 | // Use this only if you have an existing numeric ID range that you want to reserve | ||
343 | // (for example, bulk loading entities that already have IDs). If you don't care | ||
344 | // about which IDs you receive, use AllocateIDs instead. | ||
345 | // | ||
346 | // AllocateIDRange returns nil if the range is successfully allocated. If one or more | ||
347 | // entities with an ID in the given range already exist, it returns a KeyRangeCollisionError. | ||
348 | // If the Datastore has already cached IDs in this range (e.g. from a previous call to | ||
349 | // AllocateIDRange), it returns a KeyRangeContentionError. Errors of other types indicate | ||
350 | // problems with arguments or an error returned directly from the Datastore. | ||
351 | func AllocateIDRange(c context.Context, kind string, parent *Key, start, end int64) (err error) { | ||
352 | if kind == "" { | ||
353 | return errors.New("datastore: AllocateIDRange given an empty kind") | ||
354 | } | ||
355 | |||
356 | if start < 1 || end < 1 { | ||
357 | return errors.New("datastore: AllocateIDRange start and end must both be greater than 0") | ||
358 | } | ||
359 | |||
360 | if start > end { | ||
361 | return errors.New("datastore: AllocateIDRange start must be before end") | ||
362 | } | ||
363 | |||
364 | req := &pb.AllocateIdsRequest{ | ||
365 | ModelKey: keyToProto("", NewIncompleteKey(c, kind, parent)), | ||
366 | Max: proto.Int64(end), | ||
367 | } | ||
368 | res := &pb.AllocateIdsResponse{} | ||
369 | if err := internal.Call(c, "datastore_v3", "AllocateIds", req, res); err != nil { | ||
370 | return err | ||
371 | } | ||
372 | |||
373 | // Check for collisions, i.e. existing entities with IDs in this range. | ||
374 | // We could do this before the allocation, but we'd still have to do it | ||
375 | // afterward as well to catch the race condition where an entity is inserted | ||
376 | // after that initial check but before the allocation. Skip the up-front check | ||
377 | // and just do it once. | ||
378 | q := NewQuery(kind).Filter("__key__ >=", NewKey(c, kind, "", start, parent)). | ||
379 | Filter("__key__ <=", NewKey(c, kind, "", end, parent)).KeysOnly().Limit(1) | ||
380 | |||
381 | keys, err := q.GetAll(c, nil) | ||
382 | if err != nil { | ||
383 | return err | ||
384 | } | ||
385 | if len(keys) != 0 { | ||
386 | return &KeyRangeCollisionError{start: start, end: end} | ||
387 | } | ||
388 | |||
389 | // Check for a race condition, i.e. cases where the datastore may have | ||
390 | // cached ID batches that contain IDs in this range. | ||
391 | if start < res.GetStart() { | ||
392 | return &KeyRangeContentionError{start: start, end: end} | ||
393 | } | ||
394 | |||
395 | return nil | ||
396 | } | ||
diff --git a/vendor/google.golang.org/appengine/datastore/load.go b/vendor/google.golang.org/appengine/datastore/load.go new file mode 100644 index 0000000..38a6365 --- /dev/null +++ b/vendor/google.golang.org/appengine/datastore/load.go | |||
@@ -0,0 +1,429 @@ | |||
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 | "fmt" | ||
9 | "reflect" | ||
10 | "strings" | ||
11 | "time" | ||
12 | |||
13 | "github.com/golang/protobuf/proto" | ||
14 | "google.golang.org/appengine" | ||
15 | pb "google.golang.org/appengine/internal/datastore" | ||
16 | ) | ||
17 | |||
18 | var ( | ||
19 | typeOfBlobKey = reflect.TypeOf(appengine.BlobKey("")) | ||
20 | typeOfByteSlice = reflect.TypeOf([]byte(nil)) | ||
21 | typeOfByteString = reflect.TypeOf(ByteString(nil)) | ||
22 | typeOfGeoPoint = reflect.TypeOf(appengine.GeoPoint{}) | ||
23 | typeOfTime = reflect.TypeOf(time.Time{}) | ||
24 | typeOfKeyPtr = reflect.TypeOf(&Key{}) | ||
25 | typeOfEntityPtr = reflect.TypeOf(&Entity{}) | ||
26 | ) | ||
27 | |||
28 | // typeMismatchReason returns a string explaining why the property p could not | ||
29 | // be stored in an entity field of type v.Type(). | ||
30 | func typeMismatchReason(pValue interface{}, v reflect.Value) string { | ||
31 | entityType := "empty" | ||
32 | switch pValue.(type) { | ||
33 | case int64: | ||
34 | entityType = "int" | ||
35 | case bool: | ||
36 | entityType = "bool" | ||
37 | case string: | ||
38 | entityType = "string" | ||
39 | case float64: | ||
40 | entityType = "float" | ||
41 | case *Key: | ||
42 | entityType = "*datastore.Key" | ||
43 | case time.Time: | ||
44 | entityType = "time.Time" | ||
45 | case appengine.BlobKey: | ||
46 | entityType = "appengine.BlobKey" | ||
47 | case appengine.GeoPoint: | ||
48 | entityType = "appengine.GeoPoint" | ||
49 | case ByteString: | ||
50 | entityType = "datastore.ByteString" | ||
51 | case []byte: | ||
52 | entityType = "[]byte" | ||
53 | } | ||
54 | return fmt.Sprintf("type mismatch: %s versus %v", entityType, v.Type()) | ||
55 | } | ||
56 | |||
57 | type propertyLoader struct { | ||
58 | // m holds the number of times a substruct field like "Foo.Bar.Baz" has | ||
59 | // been seen so far. The map is constructed lazily. | ||
60 | m map[string]int | ||
61 | } | ||
62 | |||
63 | func (l *propertyLoader) load(codec *structCodec, structValue reflect.Value, p Property, requireSlice bool) string { | ||
64 | var v reflect.Value | ||
65 | var sliceIndex int | ||
66 | |||
67 | name := p.Name | ||
68 | |||
69 | // If name ends with a '.', the last field is anonymous. | ||
70 | // In this case, strings.Split will give us "" as the | ||
71 | // last element of our fields slice, which will match the "" | ||
72 | // field name in the substruct codec. | ||
73 | fields := strings.Split(name, ".") | ||
74 | |||
75 | for len(fields) > 0 { | ||
76 | var decoder fieldCodec | ||
77 | var ok bool | ||
78 | |||
79 | // Cut off the last field (delimited by ".") and find its parent | ||
80 | // in the codec. | ||
81 | // eg. for name "A.B.C.D", split off "A.B.C" and try to | ||
82 | // find a field in the codec with this name. | ||
83 | // Loop again with "A.B", etc. | ||
84 | for i := len(fields); i > 0; i-- { | ||
85 | parent := strings.Join(fields[:i], ".") | ||
86 | decoder, ok = codec.fields[parent] | ||
87 | if ok { | ||
88 | fields = fields[i:] | ||
89 | break | ||
90 | } | ||
91 | } | ||
92 | |||
93 | // If we never found a matching field in the codec, return | ||
94 | // error message. | ||
95 | if !ok { | ||
96 | return "no such struct field" | ||
97 | } | ||
98 | |||
99 | v = initField(structValue, decoder.path) | ||
100 | if !v.IsValid() { | ||
101 | return "no such struct field" | ||
102 | } | ||
103 | if !v.CanSet() { | ||
104 | return "cannot set struct field" | ||
105 | } | ||
106 | |||
107 | if decoder.structCodec != nil { | ||
108 | codec = decoder.structCodec | ||
109 | structValue = v | ||
110 | } | ||
111 | |||
112 | if v.Kind() == reflect.Slice && v.Type() != typeOfByteSlice { | ||
113 | if l.m == nil { | ||
114 | l.m = make(map[string]int) | ||
115 | } | ||
116 | sliceIndex = l.m[p.Name] | ||
117 | l.m[p.Name] = sliceIndex + 1 | ||
118 | for v.Len() <= sliceIndex { | ||
119 | v.Set(reflect.Append(v, reflect.New(v.Type().Elem()).Elem())) | ||
120 | } | ||
121 | structValue = v.Index(sliceIndex) | ||
122 | requireSlice = false | ||
123 | } | ||
124 | } | ||
125 | |||
126 | var slice reflect.Value | ||
127 | if v.Kind() == reflect.Slice && v.Type().Elem().Kind() != reflect.Uint8 { | ||
128 | slice = v | ||
129 | v = reflect.New(v.Type().Elem()).Elem() | ||
130 | } else if requireSlice { | ||
131 | return "multiple-valued property requires a slice field type" | ||
132 | } | ||
133 | |||
134 | // Convert indexValues to a Go value with a meaning derived from the | ||
135 | // destination type. | ||
136 | pValue := p.Value | ||
137 | if iv, ok := pValue.(indexValue); ok { | ||
138 | meaning := pb.Property_NO_MEANING | ||
139 | switch v.Type() { | ||
140 | case typeOfBlobKey: | ||
141 | meaning = pb.Property_BLOBKEY | ||
142 | case typeOfByteSlice: | ||
143 | meaning = pb.Property_BLOB | ||
144 | case typeOfByteString: | ||
145 | meaning = pb.Property_BYTESTRING | ||
146 | case typeOfGeoPoint: | ||
147 | meaning = pb.Property_GEORSS_POINT | ||
148 | case typeOfTime: | ||
149 | meaning = pb.Property_GD_WHEN | ||
150 | case typeOfEntityPtr: | ||
151 | meaning = pb.Property_ENTITY_PROTO | ||
152 | } | ||
153 | var err error | ||
154 | pValue, err = propValue(iv.value, meaning) | ||
155 | if err != nil { | ||
156 | return err.Error() | ||
157 | } | ||
158 | } | ||
159 | |||
160 | if errReason := setVal(v, pValue); errReason != "" { | ||
161 | // Set the slice back to its zero value. | ||
162 | if slice.IsValid() { | ||
163 | slice.Set(reflect.Zero(slice.Type())) | ||
164 | } | ||
165 | return errReason | ||
166 | } | ||
167 | |||
168 | if slice.IsValid() { | ||
169 | slice.Index(sliceIndex).Set(v) | ||
170 | } | ||
171 | |||
172 | return "" | ||
173 | } | ||
174 | |||
175 | // setVal sets v to the value pValue. | ||
176 | func setVal(v reflect.Value, pValue interface{}) string { | ||
177 | switch v.Kind() { | ||
178 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||
179 | x, ok := pValue.(int64) | ||
180 | if !ok && pValue != nil { | ||
181 | return typeMismatchReason(pValue, v) | ||
182 | } | ||
183 | if v.OverflowInt(x) { | ||
184 | return fmt.Sprintf("value %v overflows struct field of type %v", x, v.Type()) | ||
185 | } | ||
186 | v.SetInt(x) | ||
187 | case reflect.Bool: | ||
188 | x, ok := pValue.(bool) | ||
189 | if !ok && pValue != nil { | ||
190 | return typeMismatchReason(pValue, v) | ||
191 | } | ||
192 | v.SetBool(x) | ||
193 | case reflect.String: | ||
194 | switch x := pValue.(type) { | ||
195 | case appengine.BlobKey: | ||
196 | v.SetString(string(x)) | ||
197 | case ByteString: | ||
198 | v.SetString(string(x)) | ||
199 | case string: | ||
200 | v.SetString(x) | ||
201 | default: | ||
202 | if pValue != nil { | ||
203 | return typeMismatchReason(pValue, v) | ||
204 | } | ||
205 | } | ||
206 | case reflect.Float32, reflect.Float64: | ||
207 | x, ok := pValue.(float64) | ||
208 | if !ok && pValue != nil { | ||
209 | return typeMismatchReason(pValue, v) | ||
210 | } | ||
211 | if v.OverflowFloat(x) { | ||
212 | return fmt.Sprintf("value %v overflows struct field of type %v", x, v.Type()) | ||
213 | } | ||
214 | v.SetFloat(x) | ||
215 | case reflect.Ptr: | ||
216 | x, ok := pValue.(*Key) | ||
217 | if !ok && pValue != nil { | ||
218 | return typeMismatchReason(pValue, v) | ||
219 | } | ||
220 | if _, ok := v.Interface().(*Key); !ok { | ||
221 | return typeMismatchReason(pValue, v) | ||
222 | } | ||
223 | v.Set(reflect.ValueOf(x)) | ||
224 | case reflect.Struct: | ||
225 | switch v.Type() { | ||
226 | case typeOfTime: | ||
227 | x, ok := pValue.(time.Time) | ||
228 | if !ok && pValue != nil { | ||
229 | return typeMismatchReason(pValue, v) | ||
230 | } | ||
231 | v.Set(reflect.ValueOf(x)) | ||
232 | case typeOfGeoPoint: | ||
233 | x, ok := pValue.(appengine.GeoPoint) | ||
234 | if !ok && pValue != nil { | ||
235 | return typeMismatchReason(pValue, v) | ||
236 | } | ||
237 | v.Set(reflect.ValueOf(x)) | ||
238 | default: | ||
239 | ent, ok := pValue.(*Entity) | ||
240 | if !ok { | ||
241 | return typeMismatchReason(pValue, v) | ||
242 | } | ||
243 | |||
244 | // Recursively load nested struct | ||
245 | pls, err := newStructPLS(v.Addr().Interface()) | ||
246 | if err != nil { | ||
247 | return err.Error() | ||
248 | } | ||
249 | |||
250 | // if ent has a Key value and our struct has a Key field, | ||
251 | // load the Entity's Key value into the Key field on the struct. | ||
252 | if ent.Key != nil && pls.codec.keyField != -1 { | ||
253 | |||
254 | pls.v.Field(pls.codec.keyField).Set(reflect.ValueOf(ent.Key)) | ||
255 | } | ||
256 | |||
257 | err = pls.Load(ent.Properties) | ||
258 | if err != nil { | ||
259 | return err.Error() | ||
260 | } | ||
261 | } | ||
262 | case reflect.Slice: | ||
263 | x, ok := pValue.([]byte) | ||
264 | if !ok { | ||
265 | if y, yok := pValue.(ByteString); yok { | ||
266 | x, ok = []byte(y), true | ||
267 | } | ||
268 | } | ||
269 | if !ok && pValue != nil { | ||
270 | return typeMismatchReason(pValue, v) | ||
271 | } | ||
272 | if v.Type().Elem().Kind() != reflect.Uint8 { | ||
273 | return typeMismatchReason(pValue, v) | ||
274 | } | ||
275 | v.SetBytes(x) | ||
276 | default: | ||
277 | return typeMismatchReason(pValue, v) | ||
278 | } | ||
279 | return "" | ||
280 | } | ||
281 | |||
282 | // initField is similar to reflect's Value.FieldByIndex, in that it | ||
283 | // returns the nested struct field corresponding to index, but it | ||
284 | // initialises any nil pointers encountered when traversing the structure. | ||
285 | func initField(val reflect.Value, index []int) reflect.Value { | ||
286 | for _, i := range index[:len(index)-1] { | ||
287 | val = val.Field(i) | ||
288 | if val.Kind() == reflect.Ptr { | ||
289 | if val.IsNil() { | ||
290 | val.Set(reflect.New(val.Type().Elem())) | ||
291 | } | ||
292 | val = val.Elem() | ||
293 | } | ||
294 | } | ||
295 | return val.Field(index[len(index)-1]) | ||
296 | } | ||
297 | |||
298 | // loadEntity loads an EntityProto into PropertyLoadSaver or struct pointer. | ||
299 | func loadEntity(dst interface{}, src *pb.EntityProto) (err error) { | ||
300 | ent, err := protoToEntity(src) | ||
301 | if err != nil { | ||
302 | return err | ||
303 | } | ||
304 | if e, ok := dst.(PropertyLoadSaver); ok { | ||
305 | return e.Load(ent.Properties) | ||
306 | } | ||
307 | return LoadStruct(dst, ent.Properties) | ||
308 | } | ||
309 | |||
310 | func (s structPLS) Load(props []Property) error { | ||
311 | var fieldName, reason string | ||
312 | var l propertyLoader | ||
313 | for _, p := range props { | ||
314 | if errStr := l.load(s.codec, s.v, p, p.Multiple); errStr != "" { | ||
315 | // We don't return early, as we try to load as many properties as possible. | ||
316 | // It is valid to load an entity into a struct that cannot fully represent it. | ||
317 | // That case returns an error, but the caller is free to ignore it. | ||
318 | fieldName, reason = p.Name, errStr | ||
319 | } | ||
320 | } | ||
321 | if reason != "" { | ||
322 | return &ErrFieldMismatch{ | ||
323 | StructType: s.v.Type(), | ||
324 | FieldName: fieldName, | ||
325 | Reason: reason, | ||
326 | } | ||
327 | } | ||
328 | return nil | ||
329 | } | ||
330 | |||
331 | func protoToEntity(src *pb.EntityProto) (*Entity, error) { | ||
332 | props, rawProps := src.Property, src.RawProperty | ||
333 | outProps := make([]Property, 0, len(props)+len(rawProps)) | ||
334 | for { | ||
335 | var ( | ||
336 | x *pb.Property | ||
337 | noIndex bool | ||
338 | ) | ||
339 | if len(props) > 0 { | ||
340 | x, props = props[0], props[1:] | ||
341 | } else if len(rawProps) > 0 { | ||
342 | x, rawProps = rawProps[0], rawProps[1:] | ||
343 | noIndex = true | ||
344 | } else { | ||
345 | break | ||
346 | } | ||
347 | |||
348 | var value interface{} | ||
349 | if x.Meaning != nil && *x.Meaning == pb.Property_INDEX_VALUE { | ||
350 | value = indexValue{x.Value} | ||
351 | } else { | ||
352 | var err error | ||
353 | value, err = propValue(x.Value, x.GetMeaning()) | ||
354 | if err != nil { | ||
355 | return nil, err | ||
356 | } | ||
357 | } | ||
358 | outProps = append(outProps, Property{ | ||
359 | Name: x.GetName(), | ||
360 | Value: value, | ||
361 | NoIndex: noIndex, | ||
362 | Multiple: x.GetMultiple(), | ||
363 | }) | ||
364 | } | ||
365 | |||
366 | var key *Key | ||
367 | if src.Key != nil { | ||
368 | // Ignore any error, since nested entity values | ||
369 | // are allowed to have an invalid key. | ||
370 | key, _ = protoToKey(src.Key) | ||
371 | } | ||
372 | return &Entity{key, outProps}, nil | ||
373 | } | ||
374 | |||
375 | // propValue returns a Go value that combines the raw PropertyValue with a | ||
376 | // meaning. For example, an Int64Value with GD_WHEN becomes a time.Time. | ||
377 | func propValue(v *pb.PropertyValue, m pb.Property_Meaning) (interface{}, error) { | ||
378 | switch { | ||
379 | case v.Int64Value != nil: | ||
380 | if m == pb.Property_GD_WHEN { | ||
381 | return fromUnixMicro(*v.Int64Value), nil | ||
382 | } else { | ||
383 | return *v.Int64Value, nil | ||
384 | } | ||
385 | case v.BooleanValue != nil: | ||
386 | return *v.BooleanValue, nil | ||
387 | case v.StringValue != nil: | ||
388 | if m == pb.Property_BLOB { | ||
389 | return []byte(*v.StringValue), nil | ||
390 | } else if m == pb.Property_BLOBKEY { | ||
391 | return appengine.BlobKey(*v.StringValue), nil | ||
392 | } else if m == pb.Property_BYTESTRING { | ||
393 | return ByteString(*v.StringValue), nil | ||
394 | } else if m == pb.Property_ENTITY_PROTO { | ||
395 | var ent pb.EntityProto | ||
396 | err := proto.Unmarshal([]byte(*v.StringValue), &ent) | ||
397 | if err != nil { | ||
398 | return nil, err | ||
399 | } | ||
400 | return protoToEntity(&ent) | ||
401 | } else { | ||
402 | return *v.StringValue, nil | ||
403 | } | ||
404 | case v.DoubleValue != nil: | ||
405 | return *v.DoubleValue, nil | ||
406 | case v.Referencevalue != nil: | ||
407 | key, err := referenceValueToKey(v.Referencevalue) | ||
408 | if err != nil { | ||
409 | return nil, err | ||
410 | } | ||
411 | return key, nil | ||
412 | case v.Pointvalue != nil: | ||
413 | // NOTE: Strangely, latitude maps to X, longitude to Y. | ||
414 | return appengine.GeoPoint{Lat: v.Pointvalue.GetX(), Lng: v.Pointvalue.GetY()}, nil | ||
415 | } | ||
416 | return nil, nil | ||
417 | } | ||
418 | |||
419 | // indexValue is a Property value that is created when entities are loaded from | ||
420 | // an index, such as from a projection query. | ||
421 | // | ||
422 | // Such Property values do not contain all of the metadata required to be | ||
423 | // faithfully represented as a Go value, and are instead represented as an | ||
424 | // opaque indexValue. Load the properties into a concrete struct type (e.g. by | ||
425 | // passing a struct pointer to Iterator.Next) to reconstruct actual Go values | ||
426 | // of type int, string, time.Time, etc. | ||
427 | type indexValue struct { | ||
428 | value *pb.PropertyValue | ||
429 | } | ||
diff --git a/vendor/google.golang.org/appengine/datastore/metadata.go b/vendor/google.golang.org/appengine/datastore/metadata.go new file mode 100644 index 0000000..6acacc3 --- /dev/null +++ b/vendor/google.golang.org/appengine/datastore/metadata.go | |||
@@ -0,0 +1,78 @@ | |||
1 | // Copyright 2016 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 "golang.org/x/net/context" | ||
8 | |||
9 | // Datastore kinds for the metadata entities. | ||
10 | const ( | ||
11 | namespaceKind = "__namespace__" | ||
12 | kindKind = "__kind__" | ||
13 | propertyKind = "__property__" | ||
14 | ) | ||
15 | |||
16 | // Namespaces returns all the datastore namespaces. | ||
17 | func Namespaces(ctx context.Context) ([]string, error) { | ||
18 | // TODO(djd): Support range queries. | ||
19 | q := NewQuery(namespaceKind).KeysOnly() | ||
20 | keys, err := q.GetAll(ctx, nil) | ||
21 | if err != nil { | ||
22 | return nil, err | ||
23 | } | ||
24 | // The empty namespace key uses a numeric ID (==1), but luckily | ||
25 | // the string ID defaults to "" for numeric IDs anyway. | ||
26 | return keyNames(keys), nil | ||
27 | } | ||
28 | |||
29 | // Kinds returns the names of all the kinds in the current namespace. | ||
30 | func Kinds(ctx context.Context) ([]string, error) { | ||
31 | // TODO(djd): Support range queries. | ||
32 | q := NewQuery(kindKind).KeysOnly() | ||
33 | keys, err := q.GetAll(ctx, nil) | ||
34 | if err != nil { | ||
35 | return nil, err | ||
36 | } | ||
37 | return keyNames(keys), nil | ||
38 | } | ||
39 | |||
40 | // keyNames returns a slice of the provided keys' names (string IDs). | ||
41 | func keyNames(keys []*Key) []string { | ||
42 | n := make([]string, 0, len(keys)) | ||
43 | for _, k := range keys { | ||
44 | n = append(n, k.StringID()) | ||
45 | } | ||
46 | return n | ||
47 | } | ||
48 | |||
49 | // KindProperties returns all the indexed properties for the given kind. | ||
50 | // The properties are returned as a map of property names to a slice of the | ||
51 | // representation types. The representation types for the supported Go property | ||
52 | // types are: | ||
53 | // "INT64": signed integers and time.Time | ||
54 | // "DOUBLE": float32 and float64 | ||
55 | // "BOOLEAN": bool | ||
56 | // "STRING": string, []byte and ByteString | ||
57 | // "POINT": appengine.GeoPoint | ||
58 | // "REFERENCE": *Key | ||
59 | // "USER": (not used in the Go runtime) | ||
60 | func KindProperties(ctx context.Context, kind string) (map[string][]string, error) { | ||
61 | // TODO(djd): Support range queries. | ||
62 | kindKey := NewKey(ctx, kindKind, kind, 0, nil) | ||
63 | q := NewQuery(propertyKind).Ancestor(kindKey) | ||
64 | |||
65 | propMap := map[string][]string{} | ||
66 | props := []struct { | ||
67 | Repr []string `datastore:"property_representation"` | ||
68 | }{} | ||
69 | |||
70 | keys, err := q.GetAll(ctx, &props) | ||
71 | if err != nil { | ||
72 | return nil, err | ||
73 | } | ||
74 | for i, p := range props { | ||
75 | propMap[keys[i].StringID()] = p.Repr | ||
76 | } | ||
77 | return propMap, nil | ||
78 | } | ||
diff --git a/vendor/google.golang.org/appengine/datastore/prop.go b/vendor/google.golang.org/appengine/datastore/prop.go new file mode 100644 index 0000000..5cb2079 --- /dev/null +++ b/vendor/google.golang.org/appengine/datastore/prop.go | |||
@@ -0,0 +1,330 @@ | |||
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 | "fmt" | ||
9 | "reflect" | ||
10 | "strings" | ||
11 | "sync" | ||
12 | "unicode" | ||
13 | ) | ||
14 | |||
15 | // Entities with more than this many indexed properties will not be saved. | ||
16 | const maxIndexedProperties = 20000 | ||
17 | |||
18 | // []byte fields more than 1 megabyte long will not be loaded or saved. | ||
19 | const maxBlobLen = 1 << 20 | ||
20 | |||
21 | // Property is a name/value pair plus some metadata. A datastore entity's | ||
22 | // contents are loaded and saved as a sequence of Properties. An entity can | ||
23 | // have multiple Properties with the same name, provided that p.Multiple is | ||
24 | // true on all of that entity's Properties with that name. | ||
25 | type Property struct { | ||
26 | // Name is the property name. | ||
27 | Name string | ||
28 | // Value is the property value. The valid types are: | ||
29 | // - int64 | ||
30 | // - bool | ||
31 | // - string | ||
32 | // - float64 | ||
33 | // - ByteString | ||
34 | // - *Key | ||
35 | // - time.Time | ||
36 | // - appengine.BlobKey | ||
37 | // - appengine.GeoPoint | ||
38 | // - []byte (up to 1 megabyte in length) | ||
39 | // - *Entity (representing a nested struct) | ||
40 | // This set is smaller than the set of valid struct field types that the | ||
41 | // datastore can load and save. A Property Value cannot be a slice (apart | ||
42 | // from []byte); use multiple Properties instead. Also, a Value's type | ||
43 | // must be explicitly on the list above; it is not sufficient for the | ||
44 | // underlying type to be on that list. For example, a Value of "type | ||
45 | // myInt64 int64" is invalid. Smaller-width integers and floats are also | ||
46 | // invalid. Again, this is more restrictive than the set of valid struct | ||
47 | // field types. | ||
48 | // | ||
49 | // A Value will have an opaque type when loading entities from an index, | ||
50 | // such as via a projection query. Load entities into a struct instead | ||
51 | // of a PropertyLoadSaver when using a projection query. | ||
52 | // | ||
53 | // A Value may also be the nil interface value; this is equivalent to | ||
54 | // Python's None but not directly representable by a Go struct. Loading | ||
55 | // a nil-valued property into a struct will set that field to the zero | ||
56 | // value. | ||
57 | Value interface{} | ||
58 | // NoIndex is whether the datastore cannot index this property. | ||
59 | NoIndex bool | ||
60 | // Multiple is whether the entity can have multiple properties with | ||
61 | // the same name. Even if a particular instance only has one property with | ||
62 | // a certain name, Multiple should be true if a struct would best represent | ||
63 | // it as a field of type []T instead of type T. | ||
64 | Multiple bool | ||
65 | } | ||
66 | |||
67 | // An Entity is the value type for a nested struct. | ||
68 | // This type is only used for a Property's Value. | ||
69 | type Entity struct { | ||
70 | Key *Key | ||
71 | Properties []Property | ||
72 | } | ||
73 | |||
74 | // ByteString is a short byte slice (up to 1500 bytes) that can be indexed. | ||
75 | type ByteString []byte | ||
76 | |||
77 | // PropertyLoadSaver can be converted from and to a slice of Properties. | ||
78 | type PropertyLoadSaver interface { | ||
79 | Load([]Property) error | ||
80 | Save() ([]Property, error) | ||
81 | } | ||
82 | |||
83 | // PropertyList converts a []Property to implement PropertyLoadSaver. | ||
84 | type PropertyList []Property | ||
85 | |||
86 | var ( | ||
87 | typeOfPropertyLoadSaver = reflect.TypeOf((*PropertyLoadSaver)(nil)).Elem() | ||
88 | typeOfPropertyList = reflect.TypeOf(PropertyList(nil)) | ||
89 | ) | ||
90 | |||
91 | // Load loads all of the provided properties into l. | ||
92 | // It does not first reset *l to an empty slice. | ||
93 | func (l *PropertyList) Load(p []Property) error { | ||
94 | *l = append(*l, p...) | ||
95 | return nil | ||
96 | } | ||
97 | |||
98 | // Save saves all of l's properties as a slice or Properties. | ||
99 | func (l *PropertyList) Save() ([]Property, error) { | ||
100 | return *l, nil | ||
101 | } | ||
102 | |||
103 | // validPropertyName returns whether name consists of one or more valid Go | ||
104 | // identifiers joined by ".". | ||
105 | func validPropertyName(name string) bool { | ||
106 | if name == "" { | ||
107 | return false | ||
108 | } | ||
109 | for _, s := range strings.Split(name, ".") { | ||
110 | if s == "" { | ||
111 | return false | ||
112 | } | ||
113 | first := true | ||
114 | for _, c := range s { | ||
115 | if first { | ||
116 | first = false | ||
117 | if c != '_' && !unicode.IsLetter(c) { | ||
118 | return false | ||
119 | } | ||
120 | } else { | ||
121 | if c != '_' && !unicode.IsLetter(c) && !unicode.IsDigit(c) { | ||
122 | return false | ||
123 | } | ||
124 | } | ||
125 | } | ||
126 | } | ||
127 | return true | ||
128 | } | ||
129 | |||
130 | // structCodec describes how to convert a struct to and from a sequence of | ||
131 | // properties. | ||
132 | type structCodec struct { | ||
133 | // fields gives the field codec for the structTag with the given name. | ||
134 | fields map[string]fieldCodec | ||
135 | // hasSlice is whether a struct or any of its nested or embedded structs | ||
136 | // has a slice-typed field (other than []byte). | ||
137 | hasSlice bool | ||
138 | // keyField is the index of a *Key field with structTag __key__. | ||
139 | // This field is not relevant for the top level struct, only for | ||
140 | // nested structs. | ||
141 | keyField int | ||
142 | // complete is whether the structCodec is complete. An incomplete | ||
143 | // structCodec may be encountered when walking a recursive struct. | ||
144 | complete bool | ||
145 | } | ||
146 | |||
147 | // fieldCodec is a struct field's index and, if that struct field's type is | ||
148 | // itself a struct, that substruct's structCodec. | ||
149 | type fieldCodec struct { | ||
150 | // path is the index path to the field | ||
151 | path []int | ||
152 | noIndex bool | ||
153 | // omitEmpty indicates that the field should be omitted on save | ||
154 | // if empty. | ||
155 | omitEmpty bool | ||
156 | // structCodec is the codec fot the struct field at index 'path', | ||
157 | // or nil if the field is not a struct. | ||
158 | structCodec *structCodec | ||
159 | } | ||
160 | |||
161 | // structCodecs collects the structCodecs that have already been calculated. | ||
162 | var ( | ||
163 | structCodecsMutex sync.Mutex | ||
164 | structCodecs = make(map[reflect.Type]*structCodec) | ||
165 | ) | ||
166 | |||
167 | // getStructCodec returns the structCodec for the given struct type. | ||
168 | func getStructCodec(t reflect.Type) (*structCodec, error) { | ||
169 | structCodecsMutex.Lock() | ||
170 | defer structCodecsMutex.Unlock() | ||
171 | return getStructCodecLocked(t) | ||
172 | } | ||
173 | |||
174 | // getStructCodecLocked implements getStructCodec. The structCodecsMutex must | ||
175 | // be held when calling this function. | ||
176 | func getStructCodecLocked(t reflect.Type) (ret *structCodec, retErr error) { | ||
177 | c, ok := structCodecs[t] | ||
178 | if ok { | ||
179 | return c, nil | ||
180 | } | ||
181 | c = &structCodec{ | ||
182 | fields: make(map[string]fieldCodec), | ||
183 | // We initialize keyField to -1 so that the zero-value is not | ||
184 | // misinterpreted as index 0. | ||
185 | keyField: -1, | ||
186 | } | ||
187 | |||
188 | // Add c to the structCodecs map before we are sure it is good. If t is | ||
189 | // a recursive type, it needs to find the incomplete entry for itself in | ||
190 | // the map. | ||
191 | structCodecs[t] = c | ||
192 | defer func() { | ||
193 | if retErr != nil { | ||
194 | delete(structCodecs, t) | ||
195 | } | ||
196 | }() | ||
197 | |||
198 | for i := 0; i < t.NumField(); i++ { | ||
199 | f := t.Field(i) | ||
200 | // Skip unexported fields. | ||
201 | // Note that if f is an anonymous, unexported struct field, | ||
202 | // we will promote its fields. | ||
203 | if f.PkgPath != "" && !f.Anonymous { | ||
204 | continue | ||
205 | } | ||
206 | |||
207 | tags := strings.Split(f.Tag.Get("datastore"), ",") | ||
208 | name := tags[0] | ||
209 | opts := make(map[string]bool) | ||
210 | for _, t := range tags[1:] { | ||
211 | opts[t] = true | ||
212 | } | ||
213 | switch { | ||
214 | case name == "": | ||
215 | if !f.Anonymous { | ||
216 | name = f.Name | ||
217 | } | ||
218 | case name == "-": | ||
219 | continue | ||
220 | case name == "__key__": | ||
221 | if f.Type != typeOfKeyPtr { | ||
222 | return nil, fmt.Errorf("datastore: __key__ field on struct %v is not a *datastore.Key", t) | ||
223 | } | ||
224 | c.keyField = i | ||
225 | case !validPropertyName(name): | ||
226 | return nil, fmt.Errorf("datastore: struct tag has invalid property name: %q", name) | ||
227 | } | ||
228 | |||
229 | substructType, fIsSlice := reflect.Type(nil), false | ||
230 | switch f.Type.Kind() { | ||
231 | case reflect.Struct: | ||
232 | substructType = f.Type | ||
233 | case reflect.Slice: | ||
234 | if f.Type.Elem().Kind() == reflect.Struct { | ||
235 | substructType = f.Type.Elem() | ||
236 | } | ||
237 | fIsSlice = f.Type != typeOfByteSlice | ||
238 | c.hasSlice = c.hasSlice || fIsSlice | ||
239 | } | ||
240 | |||
241 | var sub *structCodec | ||
242 | if substructType != nil && substructType != typeOfTime && substructType != typeOfGeoPoint { | ||
243 | var err error | ||
244 | sub, err = getStructCodecLocked(substructType) | ||
245 | if err != nil { | ||
246 | return nil, err | ||
247 | } | ||
248 | if !sub.complete { | ||
249 | return nil, fmt.Errorf("datastore: recursive struct: field %q", f.Name) | ||
250 | } | ||
251 | if fIsSlice && sub.hasSlice { | ||
252 | return nil, fmt.Errorf( | ||
253 | "datastore: flattening nested structs leads to a slice of slices: field %q", f.Name) | ||
254 | } | ||
255 | c.hasSlice = c.hasSlice || sub.hasSlice | ||
256 | // If f is an anonymous struct field, we promote the substruct's fields up to this level | ||
257 | // in the linked list of struct codecs. | ||
258 | if f.Anonymous { | ||
259 | for subname, subfield := range sub.fields { | ||
260 | if name != "" { | ||
261 | subname = name + "." + subname | ||
262 | } | ||
263 | if _, ok := c.fields[subname]; ok { | ||
264 | return nil, fmt.Errorf("datastore: struct tag has repeated property name: %q", subname) | ||
265 | } | ||
266 | c.fields[subname] = fieldCodec{ | ||
267 | path: append([]int{i}, subfield.path...), | ||
268 | noIndex: subfield.noIndex || opts["noindex"], | ||
269 | omitEmpty: subfield.omitEmpty, | ||
270 | structCodec: subfield.structCodec, | ||
271 | } | ||
272 | } | ||
273 | continue | ||
274 | } | ||
275 | } | ||
276 | |||
277 | if _, ok := c.fields[name]; ok { | ||
278 | return nil, fmt.Errorf("datastore: struct tag has repeated property name: %q", name) | ||
279 | } | ||
280 | c.fields[name] = fieldCodec{ | ||
281 | path: []int{i}, | ||
282 | noIndex: opts["noindex"], | ||
283 | omitEmpty: opts["omitempty"], | ||
284 | structCodec: sub, | ||
285 | } | ||
286 | } | ||
287 | c.complete = true | ||
288 | return c, nil | ||
289 | } | ||
290 | |||
291 | // structPLS adapts a struct to be a PropertyLoadSaver. | ||
292 | type structPLS struct { | ||
293 | v reflect.Value | ||
294 | codec *structCodec | ||
295 | } | ||
296 | |||
297 | // newStructPLS returns a structPLS, which implements the | ||
298 | // PropertyLoadSaver interface, for the struct pointer p. | ||
299 | func newStructPLS(p interface{}) (*structPLS, error) { | ||
300 | v := reflect.ValueOf(p) | ||
301 | if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct { | ||
302 | return nil, ErrInvalidEntityType | ||
303 | } | ||
304 | v = v.Elem() | ||
305 | codec, err := getStructCodec(v.Type()) | ||
306 | if err != nil { | ||
307 | return nil, err | ||
308 | } | ||
309 | return &structPLS{v, codec}, nil | ||
310 | } | ||
311 | |||
312 | // LoadStruct loads the properties from p to dst. | ||
313 | // dst must be a struct pointer. | ||
314 | func LoadStruct(dst interface{}, p []Property) error { | ||
315 | x, err := newStructPLS(dst) | ||
316 | if err != nil { | ||
317 | return err | ||
318 | } | ||
319 | return x.Load(p) | ||
320 | } | ||
321 | |||
322 | // SaveStruct returns the properties from src as a slice of Properties. | ||
323 | // src must be a struct pointer. | ||
324 | func SaveStruct(src interface{}) ([]Property, error) { | ||
325 | x, err := newStructPLS(src) | ||
326 | if err != nil { | ||
327 | return nil, err | ||
328 | } | ||
329 | return x.Save() | ||
330 | } | ||
diff --git a/vendor/google.golang.org/appengine/datastore/query.go b/vendor/google.golang.org/appengine/datastore/query.go new file mode 100644 index 0000000..c1ea4ad --- /dev/null +++ b/vendor/google.golang.org/appengine/datastore/query.go | |||
@@ -0,0 +1,757 @@ | |||
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 | "encoding/base64" | ||
9 | "errors" | ||
10 | "fmt" | ||
11 | "math" | ||
12 | "reflect" | ||
13 | "strings" | ||
14 | |||
15 | "github.com/golang/protobuf/proto" | ||
16 | "golang.org/x/net/context" | ||
17 | |||
18 | "google.golang.org/appengine/internal" | ||
19 | pb "google.golang.org/appengine/internal/datastore" | ||
20 | ) | ||
21 | |||
22 | type operator int | ||
23 | |||
24 | const ( | ||
25 | lessThan operator = iota | ||
26 | lessEq | ||
27 | equal | ||
28 | greaterEq | ||
29 | greaterThan | ||
30 | ) | ||
31 | |||
32 | var operatorToProto = map[operator]*pb.Query_Filter_Operator{ | ||
33 | lessThan: pb.Query_Filter_LESS_THAN.Enum(), | ||
34 | lessEq: pb.Query_Filter_LESS_THAN_OR_EQUAL.Enum(), | ||
35 | equal: pb.Query_Filter_EQUAL.Enum(), | ||
36 | greaterEq: pb.Query_Filter_GREATER_THAN_OR_EQUAL.Enum(), | ||
37 | greaterThan: pb.Query_Filter_GREATER_THAN.Enum(), | ||
38 | } | ||
39 | |||
40 | // filter is a conditional filter on query results. | ||
41 | type filter struct { | ||
42 | FieldName string | ||
43 | Op operator | ||
44 | Value interface{} | ||
45 | } | ||
46 | |||
47 | type sortDirection int | ||
48 | |||
49 | const ( | ||
50 | ascending sortDirection = iota | ||
51 | descending | ||
52 | ) | ||
53 | |||
54 | var sortDirectionToProto = map[sortDirection]*pb.Query_Order_Direction{ | ||
55 | ascending: pb.Query_Order_ASCENDING.Enum(), | ||
56 | descending: pb.Query_Order_DESCENDING.Enum(), | ||
57 | } | ||
58 | |||
59 | // order is a sort order on query results. | ||
60 | type order struct { | ||
61 | FieldName string | ||
62 | Direction sortDirection | ||
63 | } | ||
64 | |||
65 | // NewQuery creates a new Query for a specific entity kind. | ||
66 | // | ||
67 | // An empty kind means to return all entities, including entities created and | ||
68 | // managed by other App Engine features, and is called a kindless query. | ||
69 | // Kindless queries cannot include filters or sort orders on property values. | ||
70 | func NewQuery(kind string) *Query { | ||
71 | return &Query{ | ||
72 | kind: kind, | ||
73 | limit: -1, | ||
74 | } | ||
75 | } | ||
76 | |||
77 | // Query represents a datastore query. | ||
78 | type Query struct { | ||
79 | kind string | ||
80 | ancestor *Key | ||
81 | filter []filter | ||
82 | order []order | ||
83 | projection []string | ||
84 | |||
85 | distinct bool | ||
86 | keysOnly bool | ||
87 | eventual bool | ||
88 | limit int32 | ||
89 | offset int32 | ||
90 | count int32 | ||
91 | start *pb.CompiledCursor | ||
92 | end *pb.CompiledCursor | ||
93 | |||
94 | err error | ||
95 | } | ||
96 | |||
97 | func (q *Query) clone() *Query { | ||
98 | x := *q | ||
99 | // Copy the contents of the slice-typed fields to a new backing store. | ||
100 | if len(q.filter) > 0 { | ||
101 | x.filter = make([]filter, len(q.filter)) | ||
102 | copy(x.filter, q.filter) | ||
103 | } | ||
104 | if len(q.order) > 0 { | ||
105 | x.order = make([]order, len(q.order)) | ||
106 | copy(x.order, q.order) | ||
107 | } | ||
108 | return &x | ||
109 | } | ||
110 | |||
111 | // Ancestor returns a derivative query with an ancestor filter. | ||
112 | // The ancestor should not be nil. | ||
113 | func (q *Query) Ancestor(ancestor *Key) *Query { | ||
114 | q = q.clone() | ||
115 | if ancestor == nil { | ||
116 | q.err = errors.New("datastore: nil query ancestor") | ||
117 | return q | ||
118 | } | ||
119 | q.ancestor = ancestor | ||
120 | return q | ||
121 | } | ||
122 | |||
123 | // EventualConsistency returns a derivative query that returns eventually | ||
124 | // consistent results. | ||
125 | // It only has an effect on ancestor queries. | ||
126 | func (q *Query) EventualConsistency() *Query { | ||
127 | q = q.clone() | ||
128 | q.eventual = true | ||
129 | return q | ||
130 | } | ||
131 | |||
132 | // Filter returns a derivative query with a field-based filter. | ||
133 | // The filterStr argument must be a field name followed by optional space, | ||
134 | // followed by an operator, one of ">", "<", ">=", "<=", or "=". | ||
135 | // Fields are compared against the provided value using the operator. | ||
136 | // Multiple filters are AND'ed together. | ||
137 | func (q *Query) Filter(filterStr string, value interface{}) *Query { | ||
138 | q = q.clone() | ||
139 | filterStr = strings.TrimSpace(filterStr) | ||
140 | if len(filterStr) < 1 { | ||
141 | q.err = errors.New("datastore: invalid filter: " + filterStr) | ||
142 | return q | ||
143 | } | ||
144 | f := filter{ | ||
145 | FieldName: strings.TrimRight(filterStr, " ><=!"), | ||
146 | Value: value, | ||
147 | } | ||
148 | switch op := strings.TrimSpace(filterStr[len(f.FieldName):]); op { | ||
149 | case "<=": | ||
150 | f.Op = lessEq | ||
151 | case ">=": | ||
152 | f.Op = greaterEq | ||
153 | case "<": | ||
154 | f.Op = lessThan | ||
155 | case ">": | ||
156 | f.Op = greaterThan | ||
157 | case "=": | ||
158 | f.Op = equal | ||
159 | default: | ||
160 | q.err = fmt.Errorf("datastore: invalid operator %q in filter %q", op, filterStr) | ||
161 | return q | ||
162 | } | ||
163 | q.filter = append(q.filter, f) | ||
164 | return q | ||
165 | } | ||
166 | |||
167 | // Order returns a derivative query with a field-based sort order. Orders are | ||
168 | // applied in the order they are added. The default order is ascending; to sort | ||
169 | // in descending order prefix the fieldName with a minus sign (-). | ||
170 | func (q *Query) Order(fieldName string) *Query { | ||
171 | q = q.clone() | ||
172 | fieldName = strings.TrimSpace(fieldName) | ||
173 | o := order{ | ||
174 | Direction: ascending, | ||
175 | FieldName: fieldName, | ||
176 | } | ||
177 | if strings.HasPrefix(fieldName, "-") { | ||
178 | o.Direction = descending | ||
179 | o.FieldName = strings.TrimSpace(fieldName[1:]) | ||
180 | } else if strings.HasPrefix(fieldName, "+") { | ||
181 | q.err = fmt.Errorf("datastore: invalid order: %q", fieldName) | ||
182 | return q | ||
183 | } | ||
184 | if len(o.FieldName) == 0 { | ||
185 | q.err = errors.New("datastore: empty order") | ||
186 | return q | ||
187 | } | ||
188 | q.order = append(q.order, o) | ||
189 | return q | ||
190 | } | ||
191 | |||
192 | // Project returns a derivative query that yields only the given fields. It | ||
193 | // cannot be used with KeysOnly. | ||
194 | func (q *Query) Project(fieldNames ...string) *Query { | ||
195 | q = q.clone() | ||
196 | q.projection = append([]string(nil), fieldNames...) | ||
197 | return q | ||
198 | } | ||
199 | |||
200 | // Distinct returns a derivative query that yields de-duplicated entities with | ||
201 | // respect to the set of projected fields. It is only used for projection | ||
202 | // queries. | ||
203 | func (q *Query) Distinct() *Query { | ||
204 | q = q.clone() | ||
205 | q.distinct = true | ||
206 | return q | ||
207 | } | ||
208 | |||
209 | // KeysOnly returns a derivative query that yields only keys, not keys and | ||
210 | // entities. It cannot be used with projection queries. | ||
211 | func (q *Query) KeysOnly() *Query { | ||
212 | q = q.clone() | ||
213 | q.keysOnly = true | ||
214 | return q | ||
215 | } | ||
216 | |||
217 | // Limit returns a derivative query that has a limit on the number of results | ||
218 | // returned. A negative value means unlimited. | ||
219 | func (q *Query) Limit(limit int) *Query { | ||
220 | q = q.clone() | ||
221 | if limit < math.MinInt32 || limit > math.MaxInt32 { | ||
222 | q.err = errors.New("datastore: query limit overflow") | ||
223 | return q | ||
224 | } | ||
225 | q.limit = int32(limit) | ||
226 | return q | ||
227 | } | ||
228 | |||
229 | // Offset returns a derivative query that has an offset of how many keys to | ||
230 | // skip over before returning results. A negative value is invalid. | ||
231 | func (q *Query) Offset(offset int) *Query { | ||
232 | q = q.clone() | ||
233 | if offset < 0 { | ||
234 | q.err = errors.New("datastore: negative query offset") | ||
235 | return q | ||
236 | } | ||
237 | if offset > math.MaxInt32 { | ||
238 | q.err = errors.New("datastore: query offset overflow") | ||
239 | return q | ||
240 | } | ||
241 | q.offset = int32(offset) | ||
242 | return q | ||
243 | } | ||
244 | |||
245 | // BatchSize returns a derivative query to fetch the supplied number of results | ||
246 | // at once. This value should be greater than zero, and equal to or less than | ||
247 | // the Limit. | ||
248 | func (q *Query) BatchSize(size int) *Query { | ||
249 | q = q.clone() | ||
250 | if size <= 0 || size > math.MaxInt32 { | ||
251 | q.err = errors.New("datastore: query batch size overflow") | ||
252 | return q | ||
253 | } | ||
254 | q.count = int32(size) | ||
255 | return q | ||
256 | } | ||
257 | |||
258 | // Start returns a derivative query with the given start point. | ||
259 | func (q *Query) Start(c Cursor) *Query { | ||
260 | q = q.clone() | ||
261 | if c.cc == nil { | ||
262 | q.err = errors.New("datastore: invalid cursor") | ||
263 | return q | ||
264 | } | ||
265 | q.start = c.cc | ||
266 | return q | ||
267 | } | ||
268 | |||
269 | // End returns a derivative query with the given end point. | ||
270 | func (q *Query) End(c Cursor) *Query { | ||
271 | q = q.clone() | ||
272 | if c.cc == nil { | ||
273 | q.err = errors.New("datastore: invalid cursor") | ||
274 | return q | ||
275 | } | ||
276 | q.end = c.cc | ||
277 | return q | ||
278 | } | ||
279 | |||
280 | // toProto converts the query to a protocol buffer. | ||
281 | func (q *Query) toProto(dst *pb.Query, appID string) error { | ||
282 | if len(q.projection) != 0 && q.keysOnly { | ||
283 | return errors.New("datastore: query cannot both project and be keys-only") | ||
284 | } | ||
285 | dst.Reset() | ||
286 | dst.App = proto.String(appID) | ||
287 | if q.kind != "" { | ||
288 | dst.Kind = proto.String(q.kind) | ||
289 | } | ||
290 | if q.ancestor != nil { | ||
291 | dst.Ancestor = keyToProto(appID, q.ancestor) | ||
292 | if q.eventual { | ||
293 | dst.Strong = proto.Bool(false) | ||
294 | } | ||
295 | } | ||
296 | if q.projection != nil { | ||
297 | dst.PropertyName = q.projection | ||
298 | if q.distinct { | ||
299 | dst.GroupByPropertyName = q.projection | ||
300 | } | ||
301 | } | ||
302 | if q.keysOnly { | ||
303 | dst.KeysOnly = proto.Bool(true) | ||
304 | dst.RequirePerfectPlan = proto.Bool(true) | ||
305 | } | ||
306 | for _, qf := range q.filter { | ||
307 | if qf.FieldName == "" { | ||
308 | return errors.New("datastore: empty query filter field name") | ||
309 | } | ||
310 | p, errStr := valueToProto(appID, qf.FieldName, reflect.ValueOf(qf.Value), false) | ||
311 | if errStr != "" { | ||
312 | return errors.New("datastore: bad query filter value type: " + errStr) | ||
313 | } | ||
314 | xf := &pb.Query_Filter{ | ||
315 | Op: operatorToProto[qf.Op], | ||
316 | Property: []*pb.Property{p}, | ||
317 | } | ||
318 | if xf.Op == nil { | ||
319 | return errors.New("datastore: unknown query filter operator") | ||
320 | } | ||
321 | dst.Filter = append(dst.Filter, xf) | ||
322 | } | ||
323 | for _, qo := range q.order { | ||
324 | if qo.FieldName == "" { | ||
325 | return errors.New("datastore: empty query order field name") | ||
326 | } | ||
327 | xo := &pb.Query_Order{ | ||
328 | Property: proto.String(qo.FieldName), | ||
329 | Direction: sortDirectionToProto[qo.Direction], | ||
330 | } | ||
331 | if xo.Direction == nil { | ||
332 | return errors.New("datastore: unknown query order direction") | ||
333 | } | ||
334 | dst.Order = append(dst.Order, xo) | ||
335 | } | ||
336 | if q.limit >= 0 { | ||
337 | dst.Limit = proto.Int32(q.limit) | ||
338 | } | ||
339 | if q.offset != 0 { | ||
340 | dst.Offset = proto.Int32(q.offset) | ||
341 | } | ||
342 | if q.count != 0 { | ||
343 | dst.Count = proto.Int32(q.count) | ||
344 | } | ||
345 | dst.CompiledCursor = q.start | ||
346 | dst.EndCompiledCursor = q.end | ||
347 | dst.Compile = proto.Bool(true) | ||
348 | return nil | ||
349 | } | ||
350 | |||
351 | // Count returns the number of results for the query. | ||
352 | // | ||
353 | // The running time and number of API calls made by Count scale linearly with | ||
354 | // the sum of the query's offset and limit. Unless the result count is | ||
355 | // expected to be small, it is best to specify a limit; otherwise Count will | ||
356 | // continue until it finishes counting or the provided context expires. | ||
357 | func (q *Query) Count(c context.Context) (int, error) { | ||
358 | // Check that the query is well-formed. | ||
359 | if q.err != nil { | ||
360 | return 0, q.err | ||
361 | } | ||
362 | |||
363 | // Run a copy of the query, with keysOnly true (if we're not a projection, | ||
364 | // since the two are incompatible), and an adjusted offset. We also set the | ||
365 | // limit to zero, as we don't want any actual entity data, just the number | ||
366 | // of skipped results. | ||
367 | newQ := q.clone() | ||
368 | newQ.keysOnly = len(newQ.projection) == 0 | ||
369 | newQ.limit = 0 | ||
370 | if q.limit < 0 { | ||
371 | // If the original query was unlimited, set the new query's offset to maximum. | ||
372 | newQ.offset = math.MaxInt32 | ||
373 | } else { | ||
374 | newQ.offset = q.offset + q.limit | ||
375 | if newQ.offset < 0 { | ||
376 | // Do the best we can, in the presence of overflow. | ||
377 | newQ.offset = math.MaxInt32 | ||
378 | } | ||
379 | } | ||
380 | req := &pb.Query{} | ||
381 | if err := newQ.toProto(req, internal.FullyQualifiedAppID(c)); err != nil { | ||
382 | return 0, err | ||
383 | } | ||
384 | res := &pb.QueryResult{} | ||
385 | if err := internal.Call(c, "datastore_v3", "RunQuery", req, res); err != nil { | ||
386 | return 0, err | ||
387 | } | ||
388 | |||
389 | // n is the count we will return. For example, suppose that our original | ||
390 | // query had an offset of 4 and a limit of 2008: the count will be 2008, | ||
391 | // provided that there are at least 2012 matching entities. However, the | ||
392 | // RPCs will only skip 1000 results at a time. The RPC sequence is: | ||
393 | // call RunQuery with (offset, limit) = (2012, 0) // 2012 == newQ.offset | ||
394 | // response has (skippedResults, moreResults) = (1000, true) | ||
395 | // n += 1000 // n == 1000 | ||
396 | // call Next with (offset, limit) = (1012, 0) // 1012 == newQ.offset - n | ||
397 | // response has (skippedResults, moreResults) = (1000, true) | ||
398 | // n += 1000 // n == 2000 | ||
399 | // call Next with (offset, limit) = (12, 0) // 12 == newQ.offset - n | ||
400 | // response has (skippedResults, moreResults) = (12, false) | ||
401 | // n += 12 // n == 2012 | ||
402 | // // exit the loop | ||
403 | // n -= 4 // n == 2008 | ||
404 | var n int32 | ||
405 | for { | ||
406 | // The QueryResult should have no actual entity data, just skipped results. | ||
407 | if len(res.Result) != 0 { | ||
408 | return 0, errors.New("datastore: internal error: Count request returned too much data") | ||
409 | } | ||
410 | n += res.GetSkippedResults() | ||
411 | if !res.GetMoreResults() { | ||
412 | break | ||
413 | } | ||
414 | if err := callNext(c, res, newQ.offset-n, q.count); err != nil { | ||
415 | return 0, err | ||
416 | } | ||
417 | } | ||
418 | n -= q.offset | ||
419 | if n < 0 { | ||
420 | // If the offset was greater than the number of matching entities, | ||
421 | // return 0 instead of negative. | ||
422 | n = 0 | ||
423 | } | ||
424 | return int(n), nil | ||
425 | } | ||
426 | |||
427 | // callNext issues a datastore_v3/Next RPC to advance a cursor, such as that | ||
428 | // returned by a query with more results. | ||
429 | func callNext(c context.Context, res *pb.QueryResult, offset, count int32) error { | ||
430 | if res.Cursor == nil { | ||
431 | return errors.New("datastore: internal error: server did not return a cursor") | ||
432 | } | ||
433 | req := &pb.NextRequest{ | ||
434 | Cursor: res.Cursor, | ||
435 | } | ||
436 | if count >= 0 { | ||
437 | req.Count = proto.Int32(count) | ||
438 | } | ||
439 | if offset != 0 { | ||
440 | req.Offset = proto.Int32(offset) | ||
441 | } | ||
442 | if res.CompiledCursor != nil { | ||
443 | req.Compile = proto.Bool(true) | ||
444 | } | ||
445 | res.Reset() | ||
446 | return internal.Call(c, "datastore_v3", "Next", req, res) | ||
447 | } | ||
448 | |||
449 | // GetAll runs the query in the given context and returns all keys that match | ||
450 | // that query, as well as appending the values to dst. | ||
451 | // | ||
452 | // dst must have type *[]S or *[]*S or *[]P, for some struct type S or some non- | ||
453 | // interface, non-pointer type P such that P or *P implements PropertyLoadSaver. | ||
454 | // | ||
455 | // As a special case, *PropertyList is an invalid type for dst, even though a | ||
456 | // PropertyList is a slice of structs. It is treated as invalid to avoid being | ||
457 | // mistakenly passed when *[]PropertyList was intended. | ||
458 | // | ||
459 | // The keys returned by GetAll will be in a 1-1 correspondence with the entities | ||
460 | // added to dst. | ||
461 | // | ||
462 | // If q is a ``keys-only'' query, GetAll ignores dst and only returns the keys. | ||
463 | // | ||
464 | // The running time and number of API calls made by GetAll scale linearly with | ||
465 | // the sum of the query's offset and limit. Unless the result count is | ||
466 | // expected to be small, it is best to specify a limit; otherwise GetAll will | ||
467 | // continue until it finishes collecting results or the provided context | ||
468 | // expires. | ||
469 | func (q *Query) GetAll(c context.Context, dst interface{}) ([]*Key, error) { | ||
470 | var ( | ||
471 | dv reflect.Value | ||
472 | mat multiArgType | ||
473 | elemType reflect.Type | ||
474 | errFieldMismatch error | ||
475 | ) | ||
476 | if !q.keysOnly { | ||
477 | dv = reflect.ValueOf(dst) | ||
478 | if dv.Kind() != reflect.Ptr || dv.IsNil() { | ||
479 | return nil, ErrInvalidEntityType | ||
480 | } | ||
481 | dv = dv.Elem() | ||
482 | mat, elemType = checkMultiArg(dv) | ||
483 | if mat == multiArgTypeInvalid || mat == multiArgTypeInterface { | ||
484 | return nil, ErrInvalidEntityType | ||
485 | } | ||
486 | } | ||
487 | |||
488 | var keys []*Key | ||
489 | for t := q.Run(c); ; { | ||
490 | k, e, err := t.next() | ||
491 | if err == Done { | ||
492 | break | ||
493 | } | ||
494 | if err != nil { | ||
495 | return keys, err | ||
496 | } | ||
497 | if !q.keysOnly { | ||
498 | ev := reflect.New(elemType) | ||
499 | if elemType.Kind() == reflect.Map { | ||
500 | // This is a special case. The zero values of a map type are | ||
501 | // not immediately useful; they have to be make'd. | ||
502 | // | ||
503 | // Funcs and channels are similar, in that a zero value is not useful, | ||
504 | // but even a freshly make'd channel isn't useful: there's no fixed | ||
505 | // channel buffer size that is always going to be large enough, and | ||
506 | // there's no goroutine to drain the other end. Theoretically, these | ||
507 | // types could be supported, for example by sniffing for a constructor | ||
508 | // method or requiring prior registration, but for now it's not a | ||
509 | // frequent enough concern to be worth it. Programmers can work around | ||
510 | // it by explicitly using Iterator.Next instead of the Query.GetAll | ||
511 | // convenience method. | ||
512 | x := reflect.MakeMap(elemType) | ||
513 | ev.Elem().Set(x) | ||
514 | } | ||
515 | if err = loadEntity(ev.Interface(), e); err != nil { | ||
516 | if _, ok := err.(*ErrFieldMismatch); ok { | ||
517 | // We continue loading entities even in the face of field mismatch errors. | ||
518 | // If we encounter any other error, that other error is returned. Otherwise, | ||
519 | // an ErrFieldMismatch is returned. | ||
520 | errFieldMismatch = err | ||
521 | } else { | ||
522 | return keys, err | ||
523 | } | ||
524 | } | ||
525 | if mat != multiArgTypeStructPtr { | ||
526 | ev = ev.Elem() | ||
527 | } | ||
528 | dv.Set(reflect.Append(dv, ev)) | ||
529 | } | ||
530 | keys = append(keys, k) | ||
531 | } | ||
532 | return keys, errFieldMismatch | ||
533 | } | ||
534 | |||
535 | // Run runs the query in the given context. | ||
536 | func (q *Query) Run(c context.Context) *Iterator { | ||
537 | if q.err != nil { | ||
538 | return &Iterator{err: q.err} | ||
539 | } | ||
540 | t := &Iterator{ | ||
541 | c: c, | ||
542 | limit: q.limit, | ||
543 | count: q.count, | ||
544 | q: q, | ||
545 | prevCC: q.start, | ||
546 | } | ||
547 | var req pb.Query | ||
548 | if err := q.toProto(&req, internal.FullyQualifiedAppID(c)); err != nil { | ||
549 | t.err = err | ||
550 | return t | ||
551 | } | ||
552 | if err := internal.Call(c, "datastore_v3", "RunQuery", &req, &t.res); err != nil { | ||
553 | t.err = err | ||
554 | return t | ||
555 | } | ||
556 | offset := q.offset - t.res.GetSkippedResults() | ||
557 | var count int32 | ||
558 | if t.count > 0 && (t.limit < 0 || t.count < t.limit) { | ||
559 | count = t.count | ||
560 | } else { | ||
561 | count = t.limit | ||
562 | } | ||
563 | for offset > 0 && t.res.GetMoreResults() { | ||
564 | t.prevCC = t.res.CompiledCursor | ||
565 | if err := callNext(t.c, &t.res, offset, count); err != nil { | ||
566 | t.err = err | ||
567 | break | ||
568 | } | ||
569 | skip := t.res.GetSkippedResults() | ||
570 | if skip < 0 { | ||
571 | t.err = errors.New("datastore: internal error: negative number of skipped_results") | ||
572 | break | ||
573 | } | ||
574 | offset -= skip | ||
575 | } | ||
576 | if offset < 0 { | ||
577 | t.err = errors.New("datastore: internal error: query offset was overshot") | ||
578 | } | ||
579 | return t | ||
580 | } | ||
581 | |||
582 | // Iterator is the result of running a query. | ||
583 | type Iterator struct { | ||
584 | c context.Context | ||
585 | err error | ||
586 | // res is the result of the most recent RunQuery or Next API call. | ||
587 | res pb.QueryResult | ||
588 | // i is how many elements of res.Result we have iterated over. | ||
589 | i int | ||
590 | // limit is the limit on the number of results this iterator should return. | ||
591 | // A negative value means unlimited. | ||
592 | limit int32 | ||
593 | // count is the number of results this iterator should fetch at once. This | ||
594 | // should be equal to or greater than zero. | ||
595 | count int32 | ||
596 | // q is the original query which yielded this iterator. | ||
597 | q *Query | ||
598 | // prevCC is the compiled cursor that marks the end of the previous batch | ||
599 | // of results. | ||
600 | prevCC *pb.CompiledCursor | ||
601 | } | ||
602 | |||
603 | // Done is returned when a query iteration has completed. | ||
604 | var Done = errors.New("datastore: query has no more results") | ||
605 | |||
606 | // Next returns the key of the next result. When there are no more results, | ||
607 | // Done is returned as the error. | ||
608 | // | ||
609 | // If the query is not keys only and dst is non-nil, it also loads the entity | ||
610 | // stored for that key into the struct pointer or PropertyLoadSaver dst, with | ||
611 | // the same semantics and possible errors as for the Get function. | ||
612 | func (t *Iterator) Next(dst interface{}) (*Key, error) { | ||
613 | k, e, err := t.next() | ||
614 | if err != nil { | ||
615 | return nil, err | ||
616 | } | ||
617 | if dst != nil && !t.q.keysOnly { | ||
618 | err = loadEntity(dst, e) | ||
619 | } | ||
620 | return k, err | ||
621 | } | ||
622 | |||
623 | func (t *Iterator) next() (*Key, *pb.EntityProto, error) { | ||
624 | if t.err != nil { | ||
625 | return nil, nil, t.err | ||
626 | } | ||
627 | |||
628 | // Issue datastore_v3/Next RPCs as necessary. | ||
629 | for t.i == len(t.res.Result) { | ||
630 | if !t.res.GetMoreResults() { | ||
631 | t.err = Done | ||
632 | return nil, nil, t.err | ||
633 | } | ||
634 | t.prevCC = t.res.CompiledCursor | ||
635 | var count int32 | ||
636 | if t.count > 0 && (t.limit < 0 || t.count < t.limit) { | ||
637 | count = t.count | ||
638 | } else { | ||
639 | count = t.limit | ||
640 | } | ||
641 | if err := callNext(t.c, &t.res, 0, count); err != nil { | ||
642 | t.err = err | ||
643 | return nil, nil, t.err | ||
644 | } | ||
645 | if t.res.GetSkippedResults() != 0 { | ||
646 | t.err = errors.New("datastore: internal error: iterator has skipped results") | ||
647 | return nil, nil, t.err | ||
648 | } | ||
649 | t.i = 0 | ||
650 | if t.limit >= 0 { | ||
651 | t.limit -= int32(len(t.res.Result)) | ||
652 | if t.limit < 0 { | ||
653 | t.err = errors.New("datastore: internal error: query returned more results than the limit") | ||
654 | return nil, nil, t.err | ||
655 | } | ||
656 | } | ||
657 | } | ||
658 | |||
659 | // Extract the key from the t.i'th element of t.res.Result. | ||
660 | e := t.res.Result[t.i] | ||
661 | t.i++ | ||
662 | if e.Key == nil { | ||
663 | return nil, nil, errors.New("datastore: internal error: server did not return a key") | ||
664 | } | ||
665 | k, err := protoToKey(e.Key) | ||
666 | if err != nil || k.Incomplete() { | ||
667 | return nil, nil, errors.New("datastore: internal error: server returned an invalid key") | ||
668 | } | ||
669 | return k, e, nil | ||
670 | } | ||
671 | |||
672 | // Cursor returns a cursor for the iterator's current location. | ||
673 | func (t *Iterator) Cursor() (Cursor, error) { | ||
674 | if t.err != nil && t.err != Done { | ||
675 | return Cursor{}, t.err | ||
676 | } | ||
677 | // If we are at either end of the current batch of results, | ||
678 | // return the compiled cursor at that end. | ||
679 | skipped := t.res.GetSkippedResults() | ||
680 | if t.i == 0 && skipped == 0 { | ||
681 | if t.prevCC == nil { | ||
682 | // A nil pointer (of type *pb.CompiledCursor) means no constraint: | ||
683 | // passing it as the end cursor of a new query means unlimited results | ||
684 | // (glossing over the integer limit parameter for now). | ||
685 | // A non-nil pointer to an empty pb.CompiledCursor means the start: | ||
686 | // passing it as the end cursor of a new query means 0 results. | ||
687 | // If prevCC was nil, then the original query had no start cursor, but | ||
688 | // Iterator.Cursor should return "the start" instead of unlimited. | ||
689 | return Cursor{&zeroCC}, nil | ||
690 | } | ||
691 | return Cursor{t.prevCC}, nil | ||
692 | } | ||
693 | if t.i == len(t.res.Result) { | ||
694 | return Cursor{t.res.CompiledCursor}, nil | ||
695 | } | ||
696 | // Otherwise, re-run the query offset to this iterator's position, starting from | ||
697 | // the most recent compiled cursor. This is done on a best-effort basis, as it | ||
698 | // is racy; if a concurrent process has added or removed entities, then the | ||
699 | // cursor returned may be inconsistent. | ||
700 | q := t.q.clone() | ||
701 | q.start = t.prevCC | ||
702 | q.offset = skipped + int32(t.i) | ||
703 | q.limit = 0 | ||
704 | q.keysOnly = len(q.projection) == 0 | ||
705 | t1 := q.Run(t.c) | ||
706 | _, _, err := t1.next() | ||
707 | if err != Done { | ||
708 | if err == nil { | ||
709 | err = fmt.Errorf("datastore: internal error: zero-limit query did not have zero results") | ||
710 | } | ||
711 | return Cursor{}, err | ||
712 | } | ||
713 | return Cursor{t1.res.CompiledCursor}, nil | ||
714 | } | ||
715 | |||
716 | var zeroCC pb.CompiledCursor | ||
717 | |||
718 | // Cursor is an iterator's position. It can be converted to and from an opaque | ||
719 | // string. A cursor can be used from different HTTP requests, but only with a | ||
720 | // query with the same kind, ancestor, filter and order constraints. | ||
721 | type Cursor struct { | ||
722 | cc *pb.CompiledCursor | ||
723 | } | ||
724 | |||
725 | // String returns a base-64 string representation of a cursor. | ||
726 | func (c Cursor) String() string { | ||
727 | if c.cc == nil { | ||
728 | return "" | ||
729 | } | ||
730 | b, err := proto.Marshal(c.cc) | ||
731 | if err != nil { | ||
732 | // The only way to construct a Cursor with a non-nil cc field is to | ||
733 | // unmarshal from the byte representation. We panic if the unmarshal | ||
734 | // succeeds but the marshaling of the unchanged protobuf value fails. | ||
735 | panic(fmt.Sprintf("datastore: internal error: malformed cursor: %v", err)) | ||
736 | } | ||
737 | return strings.TrimRight(base64.URLEncoding.EncodeToString(b), "=") | ||
738 | } | ||
739 | |||
740 | // Decode decodes a cursor from its base-64 string representation. | ||
741 | func DecodeCursor(s string) (Cursor, error) { | ||
742 | if s == "" { | ||
743 | return Cursor{&zeroCC}, nil | ||
744 | } | ||
745 | if n := len(s) % 4; n != 0 { | ||
746 | s += strings.Repeat("=", 4-n) | ||
747 | } | ||
748 | b, err := base64.URLEncoding.DecodeString(s) | ||
749 | if err != nil { | ||
750 | return Cursor{}, err | ||
751 | } | ||
752 | cc := &pb.CompiledCursor{} | ||
753 | if err := proto.Unmarshal(b, cc); err != nil { | ||
754 | return Cursor{}, err | ||
755 | } | ||
756 | return Cursor{cc}, nil | ||
757 | } | ||
diff --git a/vendor/google.golang.org/appengine/datastore/save.go b/vendor/google.golang.org/appengine/datastore/save.go new file mode 100644 index 0000000..7b045a5 --- /dev/null +++ b/vendor/google.golang.org/appengine/datastore/save.go | |||
@@ -0,0 +1,333 @@ | |||
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 | "math" | ||
11 | "reflect" | ||
12 | "time" | ||
13 | |||
14 | "github.com/golang/protobuf/proto" | ||
15 | |||
16 | "google.golang.org/appengine" | ||
17 | pb "google.golang.org/appengine/internal/datastore" | ||
18 | ) | ||
19 | |||
20 | func toUnixMicro(t time.Time) int64 { | ||
21 | // We cannot use t.UnixNano() / 1e3 because we want to handle times more than | ||
22 | // 2^63 nanoseconds (which is about 292 years) away from 1970, and those cannot | ||
23 | // be represented in the numerator of a single int64 divide. | ||
24 | return t.Unix()*1e6 + int64(t.Nanosecond()/1e3) | ||
25 | } | ||
26 | |||
27 | func fromUnixMicro(t int64) time.Time { | ||
28 | return time.Unix(t/1e6, (t%1e6)*1e3).UTC() | ||
29 | } | ||
30 | |||
31 | var ( | ||
32 | minTime = time.Unix(int64(math.MinInt64)/1e6, (int64(math.MinInt64)%1e6)*1e3) | ||
33 | maxTime = time.Unix(int64(math.MaxInt64)/1e6, (int64(math.MaxInt64)%1e6)*1e3) | ||
34 | ) | ||
35 | |||
36 | // valueToProto converts a named value to a newly allocated Property. | ||
37 | // The returned error string is empty on success. | ||
38 | func valueToProto(defaultAppID, name string, v reflect.Value, multiple bool) (p *pb.Property, errStr string) { | ||
39 | var ( | ||
40 | pv pb.PropertyValue | ||
41 | unsupported bool | ||
42 | ) | ||
43 | switch v.Kind() { | ||
44 | case reflect.Invalid: | ||
45 | // No-op. | ||
46 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||
47 | pv.Int64Value = proto.Int64(v.Int()) | ||
48 | case reflect.Bool: | ||
49 | pv.BooleanValue = proto.Bool(v.Bool()) | ||
50 | case reflect.String: | ||
51 | pv.StringValue = proto.String(v.String()) | ||
52 | case reflect.Float32, reflect.Float64: | ||
53 | pv.DoubleValue = proto.Float64(v.Float()) | ||
54 | case reflect.Ptr: | ||
55 | if k, ok := v.Interface().(*Key); ok { | ||
56 | if k != nil { | ||
57 | pv.Referencevalue = keyToReferenceValue(defaultAppID, k) | ||
58 | } | ||
59 | } else { | ||
60 | unsupported = true | ||
61 | } | ||
62 | case reflect.Struct: | ||
63 | switch t := v.Interface().(type) { | ||
64 | case time.Time: | ||
65 | if t.Before(minTime) || t.After(maxTime) { | ||
66 | return nil, "time value out of range" | ||
67 | } | ||
68 | pv.Int64Value = proto.Int64(toUnixMicro(t)) | ||
69 | case appengine.GeoPoint: | ||
70 | if !t.Valid() { | ||
71 | return nil, "invalid GeoPoint value" | ||
72 | } | ||
73 | // NOTE: Strangely, latitude maps to X, longitude to Y. | ||
74 | pv.Pointvalue = &pb.PropertyValue_PointValue{X: &t.Lat, Y: &t.Lng} | ||
75 | default: | ||
76 | unsupported = true | ||
77 | } | ||
78 | case reflect.Slice: | ||
79 | if b, ok := v.Interface().([]byte); ok { | ||
80 | pv.StringValue = proto.String(string(b)) | ||
81 | } else { | ||
82 | // nvToProto should already catch slice values. | ||
83 | // If we get here, we have a slice of slice values. | ||
84 | unsupported = true | ||
85 | } | ||
86 | default: | ||
87 | unsupported = true | ||
88 | } | ||
89 | if unsupported { | ||
90 | return nil, "unsupported datastore value type: " + v.Type().String() | ||
91 | } | ||
92 | p = &pb.Property{ | ||
93 | Name: proto.String(name), | ||
94 | Value: &pv, | ||
95 | Multiple: proto.Bool(multiple), | ||
96 | } | ||
97 | if v.IsValid() { | ||
98 | switch v.Interface().(type) { | ||
99 | case []byte: | ||
100 | p.Meaning = pb.Property_BLOB.Enum() | ||
101 | case ByteString: | ||
102 | p.Meaning = pb.Property_BYTESTRING.Enum() | ||
103 | case appengine.BlobKey: | ||
104 | p.Meaning = pb.Property_BLOBKEY.Enum() | ||
105 | case time.Time: | ||
106 | p.Meaning = pb.Property_GD_WHEN.Enum() | ||
107 | case appengine.GeoPoint: | ||
108 | p.Meaning = pb.Property_GEORSS_POINT.Enum() | ||
109 | } | ||
110 | } | ||
111 | return p, "" | ||
112 | } | ||
113 | |||
114 | type saveOpts struct { | ||
115 | noIndex bool | ||
116 | multiple bool | ||
117 | omitEmpty bool | ||
118 | } | ||
119 | |||
120 | // saveEntity saves an EntityProto into a PropertyLoadSaver or struct pointer. | ||
121 | func saveEntity(defaultAppID string, key *Key, src interface{}) (*pb.EntityProto, error) { | ||
122 | var err error | ||
123 | var props []Property | ||
124 | if e, ok := src.(PropertyLoadSaver); ok { | ||
125 | props, err = e.Save() | ||
126 | } else { | ||
127 | props, err = SaveStruct(src) | ||
128 | } | ||
129 | if err != nil { | ||
130 | return nil, err | ||
131 | } | ||
132 | return propertiesToProto(defaultAppID, key, props) | ||
133 | } | ||
134 | |||
135 | func saveStructProperty(props *[]Property, name string, opts saveOpts, v reflect.Value) error { | ||
136 | if opts.omitEmpty && isEmptyValue(v) { | ||
137 | return nil | ||
138 | } | ||
139 | p := Property{ | ||
140 | Name: name, | ||
141 | NoIndex: opts.noIndex, | ||
142 | Multiple: opts.multiple, | ||
143 | } | ||
144 | switch x := v.Interface().(type) { | ||
145 | case *Key: | ||
146 | p.Value = x | ||
147 | case time.Time: | ||
148 | p.Value = x | ||
149 | case appengine.BlobKey: | ||
150 | p.Value = x | ||
151 | case appengine.GeoPoint: | ||
152 | p.Value = x | ||
153 | case ByteString: | ||
154 | p.Value = x | ||
155 | default: | ||
156 | switch v.Kind() { | ||
157 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||
158 | p.Value = v.Int() | ||
159 | case reflect.Bool: | ||
160 | p.Value = v.Bool() | ||
161 | case reflect.String: | ||
162 | p.Value = v.String() | ||
163 | case reflect.Float32, reflect.Float64: | ||
164 | p.Value = v.Float() | ||
165 | case reflect.Slice: | ||
166 | if v.Type().Elem().Kind() == reflect.Uint8 { | ||
167 | p.NoIndex = true | ||
168 | p.Value = v.Bytes() | ||
169 | } | ||
170 | case reflect.Struct: | ||
171 | if !v.CanAddr() { | ||
172 | return fmt.Errorf("datastore: unsupported struct field: value is unaddressable") | ||
173 | } | ||
174 | sub, err := newStructPLS(v.Addr().Interface()) | ||
175 | if err != nil { | ||
176 | return fmt.Errorf("datastore: unsupported struct field: %v", err) | ||
177 | } | ||
178 | return sub.save(props, name+".", opts) | ||
179 | } | ||
180 | } | ||
181 | if p.Value == nil { | ||
182 | return fmt.Errorf("datastore: unsupported struct field type: %v", v.Type()) | ||
183 | } | ||
184 | *props = append(*props, p) | ||
185 | return nil | ||
186 | } | ||
187 | |||
188 | func (s structPLS) Save() ([]Property, error) { | ||
189 | var props []Property | ||
190 | if err := s.save(&props, "", saveOpts{}); err != nil { | ||
191 | return nil, err | ||
192 | } | ||
193 | return props, nil | ||
194 | } | ||
195 | |||
196 | func (s structPLS) save(props *[]Property, prefix string, opts saveOpts) error { | ||
197 | for name, f := range s.codec.fields { | ||
198 | name = prefix + name | ||
199 | v := s.v.FieldByIndex(f.path) | ||
200 | if !v.IsValid() || !v.CanSet() { | ||
201 | continue | ||
202 | } | ||
203 | var opts1 saveOpts | ||
204 | opts1.noIndex = opts.noIndex || f.noIndex | ||
205 | opts1.multiple = opts.multiple | ||
206 | opts1.omitEmpty = f.omitEmpty // don't propagate | ||
207 | // For slice fields that aren't []byte, save each element. | ||
208 | if v.Kind() == reflect.Slice && v.Type().Elem().Kind() != reflect.Uint8 { | ||
209 | opts1.multiple = true | ||
210 | for j := 0; j < v.Len(); j++ { | ||
211 | if err := saveStructProperty(props, name, opts1, v.Index(j)); err != nil { | ||
212 | return err | ||
213 | } | ||
214 | } | ||
215 | continue | ||
216 | } | ||
217 | // Otherwise, save the field itself. | ||
218 | if err := saveStructProperty(props, name, opts1, v); err != nil { | ||
219 | return err | ||
220 | } | ||
221 | } | ||
222 | return nil | ||
223 | } | ||
224 | |||
225 | func propertiesToProto(defaultAppID string, key *Key, props []Property) (*pb.EntityProto, error) { | ||
226 | e := &pb.EntityProto{ | ||
227 | Key: keyToProto(defaultAppID, key), | ||
228 | } | ||
229 | if key.parent == nil { | ||
230 | e.EntityGroup = &pb.Path{} | ||
231 | } else { | ||
232 | e.EntityGroup = keyToProto(defaultAppID, key.root()).Path | ||
233 | } | ||
234 | prevMultiple := make(map[string]bool) | ||
235 | |||
236 | for _, p := range props { | ||
237 | if pm, ok := prevMultiple[p.Name]; ok { | ||
238 | if !pm || !p.Multiple { | ||
239 | return nil, fmt.Errorf("datastore: multiple Properties with Name %q, but Multiple is false", p.Name) | ||
240 | } | ||
241 | } else { | ||
242 | prevMultiple[p.Name] = p.Multiple | ||
243 | } | ||
244 | |||
245 | x := &pb.Property{ | ||
246 | Name: proto.String(p.Name), | ||
247 | Value: new(pb.PropertyValue), | ||
248 | Multiple: proto.Bool(p.Multiple), | ||
249 | } | ||
250 | switch v := p.Value.(type) { | ||
251 | case int64: | ||
252 | x.Value.Int64Value = proto.Int64(v) | ||
253 | case bool: | ||
254 | x.Value.BooleanValue = proto.Bool(v) | ||
255 | case string: | ||
256 | x.Value.StringValue = proto.String(v) | ||
257 | if p.NoIndex { | ||
258 | x.Meaning = pb.Property_TEXT.Enum() | ||
259 | } | ||
260 | case float64: | ||
261 | x.Value.DoubleValue = proto.Float64(v) | ||
262 | case *Key: | ||
263 | if v != nil { | ||
264 | x.Value.Referencevalue = keyToReferenceValue(defaultAppID, v) | ||
265 | } | ||
266 | case time.Time: | ||
267 | if v.Before(minTime) || v.After(maxTime) { | ||
268 | return nil, fmt.Errorf("datastore: time value out of range") | ||
269 | } | ||
270 | x.Value.Int64Value = proto.Int64(toUnixMicro(v)) | ||
271 | x.Meaning = pb.Property_GD_WHEN.Enum() | ||
272 | case appengine.BlobKey: | ||
273 | x.Value.StringValue = proto.String(string(v)) | ||
274 | x.Meaning = pb.Property_BLOBKEY.Enum() | ||
275 | case appengine.GeoPoint: | ||
276 | if !v.Valid() { | ||
277 | return nil, fmt.Errorf("datastore: invalid GeoPoint value") | ||
278 | } | ||
279 | // NOTE: Strangely, latitude maps to X, longitude to Y. | ||
280 | x.Value.Pointvalue = &pb.PropertyValue_PointValue{X: &v.Lat, Y: &v.Lng} | ||
281 | x.Meaning = pb.Property_GEORSS_POINT.Enum() | ||
282 | case []byte: | ||
283 | x.Value.StringValue = proto.String(string(v)) | ||
284 | x.Meaning = pb.Property_BLOB.Enum() | ||
285 | if !p.NoIndex { | ||
286 | return nil, fmt.Errorf("datastore: cannot index a []byte valued Property with Name %q", p.Name) | ||
287 | } | ||
288 | case ByteString: | ||
289 | x.Value.StringValue = proto.String(string(v)) | ||
290 | x.Meaning = pb.Property_BYTESTRING.Enum() | ||
291 | default: | ||
292 | if p.Value != nil { | ||
293 | return nil, fmt.Errorf("datastore: invalid Value type for a Property with Name %q", p.Name) | ||
294 | } | ||
295 | } | ||
296 | |||
297 | if p.NoIndex { | ||
298 | e.RawProperty = append(e.RawProperty, x) | ||
299 | } else { | ||
300 | e.Property = append(e.Property, x) | ||
301 | if len(e.Property) > maxIndexedProperties { | ||
302 | return nil, errors.New("datastore: too many indexed properties") | ||
303 | } | ||
304 | } | ||
305 | } | ||
306 | return e, nil | ||
307 | } | ||
308 | |||
309 | // isEmptyValue is taken from the encoding/json package in the standard library. | ||
310 | func isEmptyValue(v reflect.Value) bool { | ||
311 | switch v.Kind() { | ||
312 | case reflect.Array, reflect.Map, reflect.Slice, reflect.String: | ||
313 | // TODO(perfomance): Only reflect.String needed, other property types are not supported (copy/paste from json package) | ||
314 | return v.Len() == 0 | ||
315 | case reflect.Bool: | ||
316 | return !v.Bool() | ||
317 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||
318 | return v.Int() == 0 | ||
319 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: | ||
320 | // TODO(perfomance): Uint* are unsupported property types - should be removed (copy/paste from json package) | ||
321 | return v.Uint() == 0 | ||
322 | case reflect.Float32, reflect.Float64: | ||
323 | return v.Float() == 0 | ||
324 | case reflect.Interface, reflect.Ptr: | ||
325 | return v.IsNil() | ||
326 | case reflect.Struct: | ||
327 | switch x := v.Interface().(type) { | ||
328 | case time.Time: | ||
329 | return x.IsZero() | ||
330 | } | ||
331 | } | ||
332 | return false | ||
333 | } | ||
diff --git a/vendor/google.golang.org/appengine/datastore/transaction.go b/vendor/google.golang.org/appengine/datastore/transaction.go new file mode 100644 index 0000000..2ae8428 --- /dev/null +++ b/vendor/google.golang.org/appengine/datastore/transaction.go | |||
@@ -0,0 +1,96 @@ | |||
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 | |||
10 | "golang.org/x/net/context" | ||
11 | |||
12 | "google.golang.org/appengine/internal" | ||
13 | pb "google.golang.org/appengine/internal/datastore" | ||
14 | ) | ||
15 | |||
16 | func init() { | ||
17 | internal.RegisterTransactionSetter(func(x *pb.Query, t *pb.Transaction) { | ||
18 | x.Transaction = t | ||
19 | }) | ||
20 | internal.RegisterTransactionSetter(func(x *pb.GetRequest, t *pb.Transaction) { | ||
21 | x.Transaction = t | ||
22 | }) | ||
23 | internal.RegisterTransactionSetter(func(x *pb.PutRequest, t *pb.Transaction) { | ||
24 | x.Transaction = t | ||
25 | }) | ||
26 | internal.RegisterTransactionSetter(func(x *pb.DeleteRequest, t *pb.Transaction) { | ||
27 | x.Transaction = t | ||
28 | }) | ||
29 | } | ||
30 | |||
31 | // ErrConcurrentTransaction is returned when a transaction is rolled back due | ||
32 | // to a conflict with a concurrent transaction. | ||
33 | var ErrConcurrentTransaction = errors.New("datastore: concurrent transaction") | ||
34 | |||
35 | // RunInTransaction runs f in a transaction. It calls f with a transaction | ||
36 | // context tc that f should use for all App Engine operations. | ||
37 | // | ||
38 | // If f returns nil, RunInTransaction attempts to commit the transaction, | ||
39 | // returning nil if it succeeds. If the commit fails due to a conflicting | ||
40 | // transaction, RunInTransaction retries f, each time with a new transaction | ||
41 | // context. It gives up and returns ErrConcurrentTransaction after three | ||
42 | // failed attempts. The number of attempts can be configured by specifying | ||
43 | // TransactionOptions.Attempts. | ||
44 | // | ||
45 | // If f returns non-nil, then any datastore changes will not be applied and | ||
46 | // RunInTransaction returns that same error. The function f is not retried. | ||
47 | // | ||
48 | // Note that when f returns, the transaction is not yet committed. Calling code | ||
49 | // must be careful not to assume that any of f's changes have been committed | ||
50 | // until RunInTransaction returns nil. | ||
51 | // | ||
52 | // Since f may be called multiple times, f should usually be idempotent. | ||
53 | // datastore.Get is not idempotent when unmarshaling slice fields. | ||
54 | // | ||
55 | // Nested transactions are not supported; c may not be a transaction context. | ||
56 | func RunInTransaction(c context.Context, f func(tc context.Context) error, opts *TransactionOptions) error { | ||
57 | xg := false | ||
58 | if opts != nil { | ||
59 | xg = opts.XG | ||
60 | } | ||
61 | readOnly := false | ||
62 | if opts != nil { | ||
63 | readOnly = opts.ReadOnly | ||
64 | } | ||
65 | attempts := 3 | ||
66 | if opts != nil && opts.Attempts > 0 { | ||
67 | attempts = opts.Attempts | ||
68 | } | ||
69 | var t *pb.Transaction | ||
70 | var err error | ||
71 | for i := 0; i < attempts; i++ { | ||
72 | if t, err = internal.RunTransactionOnce(c, f, xg, readOnly, t); err != internal.ErrConcurrentTransaction { | ||
73 | return err | ||
74 | } | ||
75 | } | ||
76 | return ErrConcurrentTransaction | ||
77 | } | ||
78 | |||
79 | // TransactionOptions are the options for running a transaction. | ||
80 | type TransactionOptions struct { | ||
81 | // XG is whether the transaction can cross multiple entity groups. In | ||
82 | // comparison, a single group transaction is one where all datastore keys | ||
83 | // used have the same root key. Note that cross group transactions do not | ||
84 | // have the same behavior as single group transactions. In particular, it | ||
85 | // is much more likely to see partially applied transactions in different | ||
86 | // entity groups, in global queries. | ||
87 | // It is valid to set XG to true even if the transaction is within a | ||
88 | // single entity group. | ||
89 | XG bool | ||
90 | // Attempts controls the number of retries to perform when commits fail | ||
91 | // due to a conflicting transaction. If omitted, it defaults to 3. | ||
92 | Attempts int | ||
93 | // ReadOnly controls whether the transaction is a read only transaction. | ||
94 | // Read only transactions are potentially more efficient. | ||
95 | ReadOnly bool | ||
96 | } | ||