summaryrefslogtreecommitdiffstats
path: root/vendor/google.golang.org/appengine/datastore/query.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/google.golang.org/appengine/datastore/query.go')
-rw-r--r--vendor/google.golang.org/appengine/datastore/query.go724
1 files changed, 0 insertions, 724 deletions
diff --git a/vendor/google.golang.org/appengine/datastore/query.go b/vendor/google.golang.org/appengine/datastore/query.go
deleted file mode 100644
index 3847b0fa6..000000000
--- a/vendor/google.golang.org/appengine/datastore/query.go
+++ /dev/null
@@ -1,724 +0,0 @@
-// Copyright 2011 Google Inc. All rights reserved.
-// Use of this source code is governed by the Apache 2.0
-// license that can be found in the LICENSE file.
-
-package datastore
-
-import (
- "encoding/base64"
- "errors"
- "fmt"
- "math"
- "reflect"
- "strings"
-
- "github.com/golang/protobuf/proto"
- "golang.org/x/net/context"
-
- "google.golang.org/appengine/internal"
- pb "google.golang.org/appengine/internal/datastore"
-)
-
-type operator int
-
-const (
- lessThan operator = iota
- lessEq
- equal
- greaterEq
- greaterThan
-)
-
-var operatorToProto = map[operator]*pb.Query_Filter_Operator{
- lessThan: pb.Query_Filter_LESS_THAN.Enum(),
- lessEq: pb.Query_Filter_LESS_THAN_OR_EQUAL.Enum(),
- equal: pb.Query_Filter_EQUAL.Enum(),
- greaterEq: pb.Query_Filter_GREATER_THAN_OR_EQUAL.Enum(),
- greaterThan: pb.Query_Filter_GREATER_THAN.Enum(),
-}
-
-// filter is a conditional filter on query results.
-type filter struct {
- FieldName string
- Op operator
- Value interface{}
-}
-
-type sortDirection int
-
-const (
- ascending sortDirection = iota
- descending
-)
-
-var sortDirectionToProto = map[sortDirection]*pb.Query_Order_Direction{
- ascending: pb.Query_Order_ASCENDING.Enum(),
- descending: pb.Query_Order_DESCENDING.Enum(),
-}
-
-// order is a sort order on query results.
-type order struct {
- FieldName string
- Direction sortDirection
-}
-
-// NewQuery creates a new Query for a specific entity kind.
-//
-// An empty kind means to return all entities, including entities created and
-// managed by other App Engine features, and is called a kindless query.
-// Kindless queries cannot include filters or sort orders on property values.
-func NewQuery(kind string) *Query {
- return &Query{
- kind: kind,
- limit: -1,
- }
-}
-
-// Query represents a datastore query.
-type Query struct {
- kind string
- ancestor *Key
- filter []filter
- order []order
- projection []string
-
- distinct bool
- keysOnly bool
- eventual bool
- limit int32
- offset int32
- start *pb.CompiledCursor
- end *pb.CompiledCursor
-
- err error
-}
-
-func (q *Query) clone() *Query {
- x := *q
- // Copy the contents of the slice-typed fields to a new backing store.
- if len(q.filter) > 0 {
- x.filter = make([]filter, len(q.filter))
- copy(x.filter, q.filter)
- }
- if len(q.order) > 0 {
- x.order = make([]order, len(q.order))
- copy(x.order, q.order)
- }
- return &x
-}
-
-// Ancestor returns a derivative query with an ancestor filter.
-// The ancestor should not be nil.
-func (q *Query) Ancestor(ancestor *Key) *Query {
- q = q.clone()
- if ancestor == nil {
- q.err = errors.New("datastore: nil query ancestor")
- return q
- }
- q.ancestor = ancestor
- return q
-}
-
-// EventualConsistency returns a derivative query that returns eventually
-// consistent results.
-// It only has an effect on ancestor queries.
-func (q *Query) EventualConsistency() *Query {
- q = q.clone()
- q.eventual = true
- return q
-}
-
-// Filter returns a derivative query with a field-based filter.
-// The filterStr argument must be a field name followed by optional space,
-// followed by an operator, one of ">", "<", ">=", "<=", or "=".
-// Fields are compared against the provided value using the operator.
-// Multiple filters are AND'ed together.
-func (q *Query) Filter(filterStr string, value interface{}) *Query {
- q = q.clone()
- filterStr = strings.TrimSpace(filterStr)
- if len(filterStr) < 1 {
- q.err = errors.New("datastore: invalid filter: " + filterStr)
- return q
- }
- f := filter{
- FieldName: strings.TrimRight(filterStr, " ><=!"),
- Value: value,
- }
- switch op := strings.TrimSpace(filterStr[len(f.FieldName):]); op {
- case "<=":
- f.Op = lessEq
- case ">=":
- f.Op = greaterEq
- case "<":
- f.Op = lessThan
- case ">":
- f.Op = greaterThan
- case "=":
- f.Op = equal
- default:
- q.err = fmt.Errorf("datastore: invalid operator %q in filter %q", op, filterStr)
- return q
- }
- q.filter = append(q.filter, f)
- return q
-}
-
-// Order returns a derivative query with a field-based sort order. Orders are
-// applied in the order they are added. The default order is ascending; to sort
-// in descending order prefix the fieldName with a minus sign (-).
-func (q *Query) Order(fieldName string) *Query {
- q = q.clone()
- fieldName = strings.TrimSpace(fieldName)
- o := order{
- Direction: ascending,
- FieldName: fieldName,
- }
- if strings.HasPrefix(fieldName, "-") {
- o.Direction = descending
- o.FieldName = strings.TrimSpace(fieldName[1:])
- } else if strings.HasPrefix(fieldName, "+") {
- q.err = fmt.Errorf("datastore: invalid order: %q", fieldName)
- return q
- }
- if len(o.FieldName) == 0 {
- q.err = errors.New("datastore: empty order")
- return q
- }
- q.order = append(q.order, o)
- return q
-}
-
-// Project returns a derivative query that yields only the given fields. It
-// cannot be used with KeysOnly.
-func (q *Query) Project(fieldNames ...string) *Query {
- q = q.clone()
- q.projection = append([]string(nil), fieldNames...)
- return q
-}
-
-// Distinct returns a derivative query that yields de-duplicated entities with
-// respect to the set of projected fields. It is only used for projection
-// queries.
-func (q *Query) Distinct() *Query {
- q = q.clone()
- q.distinct = true
- return q
-}
-
-// KeysOnly returns a derivative query that yields only keys, not keys and
-// entities. It cannot be used with projection queries.
-func (q *Query) KeysOnly() *Query {
- q = q.clone()
- q.keysOnly = true
- return q
-}
-
-// Limit returns a derivative query that has a limit on the number of results
-// returned. A negative value means unlimited.
-func (q *Query) Limit(limit int) *Query {
- q = q.clone()
- if limit < math.MinInt32 || limit > math.MaxInt32 {
- q.err = errors.New("datastore: query limit overflow")
- return q
- }
- q.limit = int32(limit)
- return q
-}
-
-// Offset returns a derivative query that has an offset of how many keys to
-// skip over before returning results. A negative value is invalid.
-func (q *Query) Offset(offset int) *Query {
- q = q.clone()
- if offset < 0 {
- q.err = errors.New("datastore: negative query offset")
- return q
- }
- if offset > math.MaxInt32 {
- q.err = errors.New("datastore: query offset overflow")
- return q
- }
- q.offset = int32(offset)
- return q
-}
-
-// Start returns a derivative query with the given start point.
-func (q *Query) Start(c Cursor) *Query {
- q = q.clone()
- if c.cc == nil {
- q.err = errors.New("datastore: invalid cursor")
- return q
- }
- q.start = c.cc
- return q
-}
-
-// End returns a derivative query with the given end point.
-func (q *Query) End(c Cursor) *Query {
- q = q.clone()
- if c.cc == nil {
- q.err = errors.New("datastore: invalid cursor")
- return q
- }
- q.end = c.cc
- return q
-}
-
-// toProto converts the query to a protocol buffer.
-func (q *Query) toProto(dst *pb.Query, appID string) error {
- if len(q.projection) != 0 && q.keysOnly {
- return errors.New("datastore: query cannot both project and be keys-only")
- }
- dst.Reset()
- dst.App = proto.String(appID)
- if q.kind != "" {
- dst.Kind = proto.String(q.kind)
- }
- if q.ancestor != nil {
- dst.Ancestor = keyToProto(appID, q.ancestor)
- if q.eventual {
- dst.Strong = proto.Bool(false)
- }
- }
- if q.projection != nil {
- dst.PropertyName = q.projection
- if q.distinct {
- dst.GroupByPropertyName = q.projection
- }
- }
- if q.keysOnly {
- dst.KeysOnly = proto.Bool(true)
- dst.RequirePerfectPlan = proto.Bool(true)
- }
- for _, qf := range q.filter {
- if qf.FieldName == "" {
- return errors.New("datastore: empty query filter field name")
- }
- p, errStr := valueToProto(appID, qf.FieldName, reflect.ValueOf(qf.Value), false)
- if errStr != "" {
- return errors.New("datastore: bad query filter value type: " + errStr)
- }
- xf := &pb.Query_Filter{
- Op: operatorToProto[qf.Op],
- Property: []*pb.Property{p},
- }
- if xf.Op == nil {
- return errors.New("datastore: unknown query filter operator")
- }
- dst.Filter = append(dst.Filter, xf)
- }
- for _, qo := range q.order {
- if qo.FieldName == "" {
- return errors.New("datastore: empty query order field name")
- }
- xo := &pb.Query_Order{
- Property: proto.String(qo.FieldName),
- Direction: sortDirectionToProto[qo.Direction],
- }
- if xo.Direction == nil {
- return errors.New("datastore: unknown query order direction")
- }
- dst.Order = append(dst.Order, xo)
- }
- if q.limit >= 0 {
- dst.Limit = proto.Int32(q.limit)
- }
- if q.offset != 0 {
- dst.Offset = proto.Int32(q.offset)
- }
- dst.CompiledCursor = q.start
- dst.EndCompiledCursor = q.end
- dst.Compile = proto.Bool(true)
- return nil
-}
-
-// Count returns the number of results for the query.
-//
-// The running time and number of API calls made by Count scale linearly with
-// the sum of the query's offset and limit. Unless the result count is
-// expected to be small, it is best to specify a limit; otherwise Count will
-// continue until it finishes counting or the provided context expires.
-func (q *Query) Count(c context.Context) (int, error) {
- // Check that the query is well-formed.
- if q.err != nil {
- return 0, q.err
- }
-
- // Run a copy of the query, with keysOnly true (if we're not a projection,
- // since the two are incompatible), and an adjusted offset. We also set the
- // limit to zero, as we don't want any actual entity data, just the number
- // of skipped results.
- newQ := q.clone()
- newQ.keysOnly = len(newQ.projection) == 0
- newQ.limit = 0
- if q.limit < 0 {
- // If the original query was unlimited, set the new query's offset to maximum.
- newQ.offset = math.MaxInt32
- } else {
- newQ.offset = q.offset + q.limit
- if newQ.offset < 0 {
- // Do the best we can, in the presence of overflow.
- newQ.offset = math.MaxInt32
- }
- }
- req := &pb.Query{}
- if err := newQ.toProto(req, internal.FullyQualifiedAppID(c)); err != nil {
- return 0, err
- }
- res := &pb.QueryResult{}
- if err := internal.Call(c, "datastore_v3", "RunQuery", req, res); err != nil {
- return 0, err
- }
-
- // n is the count we will return. For example, suppose that our original
- // query had an offset of 4 and a limit of 2008: the count will be 2008,
- // provided that there are at least 2012 matching entities. However, the
- // RPCs will only skip 1000 results at a time. The RPC sequence is:
- // call RunQuery with (offset, limit) = (2012, 0) // 2012 == newQ.offset
- // response has (skippedResults, moreResults) = (1000, true)
- // n += 1000 // n == 1000
- // call Next with (offset, limit) = (1012, 0) // 1012 == newQ.offset - n
- // response has (skippedResults, moreResults) = (1000, true)
- // n += 1000 // n == 2000
- // call Next with (offset, limit) = (12, 0) // 12 == newQ.offset - n
- // response has (skippedResults, moreResults) = (12, false)
- // n += 12 // n == 2012
- // // exit the loop
- // n -= 4 // n == 2008
- var n int32
- for {
- // The QueryResult should have no actual entity data, just skipped results.
- if len(res.Result) != 0 {
- return 0, errors.New("datastore: internal error: Count request returned too much data")
- }
- n += res.GetSkippedResults()
- if !res.GetMoreResults() {
- break
- }
- if err := callNext(c, res, newQ.offset-n, 0); err != nil {
- return 0, err
- }
- }
- n -= q.offset
- if n < 0 {
- // If the offset was greater than the number of matching entities,
- // return 0 instead of negative.
- n = 0
- }
- return int(n), nil
-}
-
-// callNext issues a datastore_v3/Next RPC to advance a cursor, such as that
-// returned by a query with more results.
-func callNext(c context.Context, res *pb.QueryResult, offset, limit int32) error {
- if res.Cursor == nil {
- return errors.New("datastore: internal error: server did not return a cursor")
- }
- req := &pb.NextRequest{
- Cursor: res.Cursor,
- }
- if limit >= 0 {
- req.Count = proto.Int32(limit)
- }
- if offset != 0 {
- req.Offset = proto.Int32(offset)
- }
- if res.CompiledCursor != nil {
- req.Compile = proto.Bool(true)
- }
- res.Reset()
- return internal.Call(c, "datastore_v3", "Next", req, res)
-}
-
-// GetAll runs the query in the given context and returns all keys that match
-// that query, as well as appending the values to dst.
-//
-// dst must have type *[]S or *[]*S or *[]P, for some struct type S or some non-
-// interface, non-pointer type P such that P or *P implements PropertyLoadSaver.
-//
-// As a special case, *PropertyList is an invalid type for dst, even though a
-// PropertyList is a slice of structs. It is treated as invalid to avoid being
-// mistakenly passed when *[]PropertyList was intended.
-//
-// The keys returned by GetAll will be in a 1-1 correspondence with the entities
-// added to dst.
-//
-// If q is a ``keys-only'' query, GetAll ignores dst and only returns the keys.
-//
-// The running time and number of API calls made by GetAll scale linearly with
-// with the sum of the query's offset and limit. Unless the result count is
-// expected to be small, it is best to specify a limit; otherwise GetAll will
-// continue until it finishes collecting results or the provided context
-// expires.
-func (q *Query) GetAll(c context.Context, dst interface{}) ([]*Key, error) {
- var (
- dv reflect.Value
- mat multiArgType
- elemType reflect.Type
- errFieldMismatch error
- )
- if !q.keysOnly {
- dv = reflect.ValueOf(dst)
- if dv.Kind() != reflect.Ptr || dv.IsNil() {
- return nil, ErrInvalidEntityType
- }
- dv = dv.Elem()
- mat, elemType = checkMultiArg(dv)
- if mat == multiArgTypeInvalid || mat == multiArgTypeInterface {
- return nil, ErrInvalidEntityType
- }
- }
-
- var keys []*Key
- for t := q.Run(c); ; {
- k, e, err := t.next()
- if err == Done {
- break
- }
- if err != nil {
- return keys, err
- }
- if !q.keysOnly {
- ev := reflect.New(elemType)
- if elemType.Kind() == reflect.Map {
- // This is a special case. The zero values of a map type are
- // not immediately useful; they have to be make'd.
- //
- // Funcs and channels are similar, in that a zero value is not useful,
- // but even a freshly make'd channel isn't useful: there's no fixed
- // channel buffer size that is always going to be large enough, and
- // there's no goroutine to drain the other end. Theoretically, these
- // types could be supported, for example by sniffing for a constructor
- // method or requiring prior registration, but for now it's not a
- // frequent enough concern to be worth it. Programmers can work around
- // it by explicitly using Iterator.Next instead of the Query.GetAll
- // convenience method.
- x := reflect.MakeMap(elemType)
- ev.Elem().Set(x)
- }
- if err = loadEntity(ev.Interface(), e); err != nil {
- if _, ok := err.(*ErrFieldMismatch); ok {
- // We continue loading entities even in the face of field mismatch errors.
- // If we encounter any other error, that other error is returned. Otherwise,
- // an ErrFieldMismatch is returned.
- errFieldMismatch = err
- } else {
- return keys, err
- }
- }
- if mat != multiArgTypeStructPtr {
- ev = ev.Elem()
- }
- dv.Set(reflect.Append(dv, ev))
- }
- keys = append(keys, k)
- }
- return keys, errFieldMismatch
-}
-
-// Run runs the query in the given context.
-func (q *Query) Run(c context.Context) *Iterator {
- if q.err != nil {
- return &Iterator{err: q.err}
- }
- t := &Iterator{
- c: c,
- limit: q.limit,
- q: q,
- prevCC: q.start,
- }
- var req pb.Query
- if err := q.toProto(&req, internal.FullyQualifiedAppID(c)); err != nil {
- t.err = err
- return t
- }
- if err := internal.Call(c, "datastore_v3", "RunQuery", &req, &t.res); err != nil {
- t.err = err
- return t
- }
- offset := q.offset - t.res.GetSkippedResults()
- for offset > 0 && t.res.GetMoreResults() {
- t.prevCC = t.res.CompiledCursor
- if err := callNext(t.c, &t.res, offset, t.limit); err != nil {
- t.err = err
- break
- }
- skip := t.res.GetSkippedResults()
- if skip < 0 {
- t.err = errors.New("datastore: internal error: negative number of skipped_results")
- break
- }
- offset -= skip
- }
- if offset < 0 {
- t.err = errors.New("datastore: internal error: query offset was overshot")
- }
- return t
-}
-
-// Iterator is the result of running a query.
-type Iterator struct {
- c context.Context
- err error
- // res is the result of the most recent RunQuery or Next API call.
- res pb.QueryResult
- // i is how many elements of res.Result we have iterated over.
- i int
- // limit is the limit on the number of results this iterator should return.
- // A negative value means unlimited.
- limit int32
- // q is the original query which yielded this iterator.
- q *Query
- // prevCC is the compiled cursor that marks the end of the previous batch
- // of results.
- prevCC *pb.CompiledCursor
-}
-
-// Done is returned when a query iteration has completed.
-var Done = errors.New("datastore: query has no more results")
-
-// Next returns the key of the next result. When there are no more results,
-// Done is returned as the error.
-//
-// If the query is not keys only and dst is non-nil, it also loads the entity
-// stored for that key into the struct pointer or PropertyLoadSaver dst, with
-// the same semantics and possible errors as for the Get function.
-func (t *Iterator) Next(dst interface{}) (*Key, error) {
- k, e, err := t.next()
- if err != nil {
- return nil, err
- }
- if dst != nil && !t.q.keysOnly {
- err = loadEntity(dst, e)
- }
- return k, err
-}
-
-func (t *Iterator) next() (*Key, *pb.EntityProto, error) {
- if t.err != nil {
- return nil, nil, t.err
- }
-
- // Issue datastore_v3/Next RPCs as necessary.
- for t.i == len(t.res.Result) {
- if !t.res.GetMoreResults() {
- t.err = Done
- return nil, nil, t.err
- }
- t.prevCC = t.res.CompiledCursor
- if err := callNext(t.c, &t.res, 0, t.limit); err != nil {
- t.err = err
- return nil, nil, t.err
- }
- if t.res.GetSkippedResults() != 0 {
- t.err = errors.New("datastore: internal error: iterator has skipped results")
- return nil, nil, t.err
- }
- t.i = 0
- if t.limit >= 0 {
- t.limit -= int32(len(t.res.Result))
- if t.limit < 0 {
- t.err = errors.New("datastore: internal error: query returned more results than the limit")
- return nil, nil, t.err
- }
- }
- }
-
- // Extract the key from the t.i'th element of t.res.Result.
- e := t.res.Result[t.i]
- t.i++
- if e.Key == nil {
- return nil, nil, errors.New("datastore: internal error: server did not return a key")
- }
- k, err := protoToKey(e.Key)
- if err != nil || k.Incomplete() {
- return nil, nil, errors.New("datastore: internal error: server returned an invalid key")
- }
- return k, e, nil
-}
-
-// Cursor returns a cursor for the iterator's current location.
-func (t *Iterator) Cursor() (Cursor, error) {
- if t.err != nil && t.err != Done {
- return Cursor{}, t.err
- }
- // If we are at either end of the current batch of results,
- // return the compiled cursor at that end.
- skipped := t.res.GetSkippedResults()
- if t.i == 0 && skipped == 0 {
- if t.prevCC == nil {
- // A nil pointer (of type *pb.CompiledCursor) means no constraint:
- // passing it as the end cursor of a new query means unlimited results
- // (glossing over the integer limit parameter for now).
- // A non-nil pointer to an empty pb.CompiledCursor means the start:
- // passing it as the end cursor of a new query means 0 results.
- // If prevCC was nil, then the original query had no start cursor, but
- // Iterator.Cursor should return "the start" instead of unlimited.
- return Cursor{&zeroCC}, nil
- }
- return Cursor{t.prevCC}, nil
- }
- if t.i == len(t.res.Result) {
- return Cursor{t.res.CompiledCursor}, nil
- }
- // Otherwise, re-run the query offset to this iterator's position, starting from
- // the most recent compiled cursor. This is done on a best-effort basis, as it
- // is racy; if a concurrent process has added or removed entities, then the
- // cursor returned may be inconsistent.
- q := t.q.clone()
- q.start = t.prevCC
- q.offset = skipped + int32(t.i)
- q.limit = 0
- q.keysOnly = len(q.projection) == 0
- t1 := q.Run(t.c)
- _, _, err := t1.next()
- if err != Done {
- if err == nil {
- err = fmt.Errorf("datastore: internal error: zero-limit query did not have zero results")
- }
- return Cursor{}, err
- }
- return Cursor{t1.res.CompiledCursor}, nil
-}
-
-var zeroCC pb.CompiledCursor
-
-// Cursor is an iterator's position. It can be converted to and from an opaque
-// string. A cursor can be used from different HTTP requests, but only with a
-// query with the same kind, ancestor, filter and order constraints.
-type Cursor struct {
- cc *pb.CompiledCursor
-}
-
-// String returns a base-64 string representation of a cursor.
-func (c Cursor) String() string {
- if c.cc == nil {
- return ""
- }
- b, err := proto.Marshal(c.cc)
- if err != nil {
- // The only way to construct a Cursor with a non-nil cc field is to
- // unmarshal from the byte representation. We panic if the unmarshal
- // succeeds but the marshaling of the unchanged protobuf value fails.
- panic(fmt.Sprintf("datastore: internal error: malformed cursor: %v", err))
- }
- return strings.TrimRight(base64.URLEncoding.EncodeToString(b), "=")
-}
-
-// Decode decodes a cursor from its base-64 string representation.
-func DecodeCursor(s string) (Cursor, error) {
- if s == "" {
- return Cursor{&zeroCC}, nil
- }
- if n := len(s) % 4; n != 0 {
- s += strings.Repeat("=", 4-n)
- }
- b, err := base64.URLEncoding.DecodeString(s)
- if err != nil {
- return Cursor{}, err
- }
- cc := &pb.CompiledCursor{}
- if err := proto.Unmarshal(b, cc); err != nil {
- return Cursor{}, err
- }
- return Cursor{cc}, nil
-}