diff options
Diffstat (limited to 'vendor/google.golang.org/appengine/datastore/query.go')
-rw-r--r-- | vendor/google.golang.org/appengine/datastore/query.go | 757 |
1 files changed, 757 insertions, 0 deletions
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 | } | ||