func callNext(ctx context.Context, req *pb.RunQueryRequest, res *pb.RunQueryResponse, offset, limit int32) error { if res.GetBatch().EndCursor == nil { return errors.New("datastore: internal error: server did not return a cursor") } req.Query.StartCursor = res.GetBatch().GetEndCursor() if limit >= 0 { req.Query.Limit = proto.Int32(limit) } if offset != 0 { req.Query.Offset = proto.Int32(offset) } res.Reset() return call(ctx, "runQuery", req, res) }
// toProto converts the query to a protocol buffer. func (q *Query) toProto(req *pb.RunQueryRequest) error { dst := pb.Query{} if len(q.projection) != 0 && q.keysOnly { return errors.New("datastore: query cannot both project and be keys-only") } dst.Reset() if q.kind != "" { dst.Kind = []*pb.KindExpression{&pb.KindExpression{Name: proto.String(q.kind)}} } if q.projection != nil { for _, propertyName := range q.projection { dst.Projection = append(dst.Projection, &pb.PropertyExpression{Property: &pb.PropertyReference{Name: proto.String(propertyName)}}) } if q.distinct { for _, propertyName := range q.projection { dst.GroupBy = append(dst.GroupBy, &pb.PropertyReference{Name: proto.String(propertyName)}) } } } if q.keysOnly { dst.Projection = []*pb.PropertyExpression{&pb.PropertyExpression{Property: &pb.PropertyReference{Name: proto.String(keyFieldName)}}} } var filters []*pb.Filter for _, qf := range q.filter { if qf.FieldName == "" { return errors.New("datastore: empty query filter field name") } v, errStr := interfaceToProto(reflect.ValueOf(qf.Value).Interface()) if errStr != "" { return errors.New("datastore: bad query filter value type: " + errStr) } xf := &pb.PropertyFilter{ Operator: operatorToProto[qf.Op], Property: &pb.PropertyReference{Name: proto.String(qf.FieldName)}, Value: v, } if xf.Operator == nil { return errors.New("datastore: unknown query filter operator") } filters = append(filters, &pb.Filter{PropertyFilter: xf}) } if q.ancestor != nil { filters = append(filters, &pb.Filter{ PropertyFilter: &pb.PropertyFilter{ Property: &pb.PropertyReference{Name: proto.String("__key__")}, Operator: pb.PropertyFilter_HAS_ANCESTOR.Enum(), Value: &pb.Value{KeyValue: keyToProto(q.ancestor)}, }}) } if len(filters) == 1 { dst.Filter = filters[0] } else if len(filters) > 1 { dst.Filter = &pb.Filter{CompositeFilter: &pb.CompositeFilter{ Operator: pb.CompositeFilter_AND.Enum(), Filter: filters, }} } for _, qo := range q.order { if qo.FieldName == "" { return errors.New("datastore: empty query order field name") } xo := &pb.PropertyOrder{ Property: &pb.PropertyReference{Name: 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.StartCursor = q.start dst.EndCursor = q.end req.Query = &dst return nil }