You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

789 lines
23 KiB

  1. // Copyright 2014 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package datastore
  15. import (
  16. "context"
  17. "encoding/base64"
  18. "errors"
  19. "fmt"
  20. "math"
  21. "reflect"
  22. "strconv"
  23. "strings"
  24. "cloud.google.com/go/internal/trace"
  25. wrapperspb "github.com/golang/protobuf/ptypes/wrappers"
  26. "google.golang.org/api/iterator"
  27. pb "google.golang.org/genproto/googleapis/datastore/v1"
  28. )
  29. type operator int
  30. const (
  31. lessThan operator = iota + 1
  32. lessEq
  33. equal
  34. greaterEq
  35. greaterThan
  36. keyFieldName = "__key__"
  37. )
  38. var operatorToProto = map[operator]pb.PropertyFilter_Operator{
  39. lessThan: pb.PropertyFilter_LESS_THAN,
  40. lessEq: pb.PropertyFilter_LESS_THAN_OR_EQUAL,
  41. equal: pb.PropertyFilter_EQUAL,
  42. greaterEq: pb.PropertyFilter_GREATER_THAN_OR_EQUAL,
  43. greaterThan: pb.PropertyFilter_GREATER_THAN,
  44. }
  45. // filter is a conditional filter on query results.
  46. type filter struct {
  47. FieldName string
  48. Op operator
  49. Value interface{}
  50. }
  51. type sortDirection bool
  52. const (
  53. ascending sortDirection = false
  54. descending sortDirection = true
  55. )
  56. var sortDirectionToProto = map[sortDirection]pb.PropertyOrder_Direction{
  57. ascending: pb.PropertyOrder_ASCENDING,
  58. descending: pb.PropertyOrder_DESCENDING,
  59. }
  60. // order is a sort order on query results.
  61. type order struct {
  62. FieldName string
  63. Direction sortDirection
  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. // Query represents a datastore query.
  77. type Query struct {
  78. kind string
  79. ancestor *Key
  80. filter []filter
  81. order []order
  82. projection []string
  83. distinct bool
  84. distinctOn []string
  85. keysOnly bool
  86. eventual bool
  87. limit int32
  88. offset int32
  89. start []byte
  90. end []byte
  91. namespace string
  92. trans *Transaction
  93. err error
  94. }
  95. func (q *Query) clone() *Query {
  96. x := *q
  97. // Copy the contents of the slice-typed fields to a new backing store.
  98. if len(q.filter) > 0 {
  99. x.filter = make([]filter, len(q.filter))
  100. copy(x.filter, q.filter)
  101. }
  102. if len(q.order) > 0 {
  103. x.order = make([]order, len(q.order))
  104. copy(x.order, q.order)
  105. }
  106. return &x
  107. }
  108. // Ancestor returns a derivative query with an ancestor filter.
  109. // The ancestor should not be nil.
  110. func (q *Query) Ancestor(ancestor *Key) *Query {
  111. q = q.clone()
  112. if ancestor == nil {
  113. q.err = errors.New("datastore: nil query ancestor")
  114. return q
  115. }
  116. q.ancestor = ancestor
  117. return q
  118. }
  119. // EventualConsistency returns a derivative query that returns eventually
  120. // consistent results.
  121. // It only has an effect on ancestor queries.
  122. func (q *Query) EventualConsistency() *Query {
  123. q = q.clone()
  124. q.eventual = true
  125. return q
  126. }
  127. // Namespace returns a derivative query that is associated with the given
  128. // namespace.
  129. //
  130. // A namespace may be used to partition data for multi-tenant applications.
  131. // For details, see https://cloud.google.com/datastore/docs/concepts/multitenancy.
  132. func (q *Query) Namespace(ns string) *Query {
  133. q = q.clone()
  134. q.namespace = ns
  135. return q
  136. }
  137. // Transaction returns a derivative query that is associated with the given
  138. // transaction.
  139. //
  140. // All reads performed as part of the transaction will come from a single
  141. // consistent snapshot. Furthermore, if the transaction is set to a
  142. // serializable isolation level, another transaction cannot concurrently modify
  143. // the data that is read or modified by this transaction.
  144. func (q *Query) Transaction(t *Transaction) *Query {
  145. q = q.clone()
  146. q.trans = t
  147. return q
  148. }
  149. // Filter returns a derivative query with a field-based filter.
  150. // The filterStr argument must be a field name followed by optional space,
  151. // followed by an operator, one of ">", "<", ">=", "<=", or "=".
  152. // Fields are compared against the provided value using the operator.
  153. // Multiple filters are AND'ed together.
  154. // Field names which contain spaces, quote marks, or operator characters
  155. // should be passed as quoted Go string literals as returned by strconv.Quote
  156. // or the fmt package's %q verb.
  157. func (q *Query) Filter(filterStr string, value interface{}) *Query {
  158. q = q.clone()
  159. filterStr = strings.TrimSpace(filterStr)
  160. if filterStr == "" {
  161. q.err = fmt.Errorf("datastore: invalid filter %q", filterStr)
  162. return q
  163. }
  164. f := filter{
  165. FieldName: strings.TrimRight(filterStr, " ><=!"),
  166. Value: value,
  167. }
  168. switch op := strings.TrimSpace(filterStr[len(f.FieldName):]); op {
  169. case "<=":
  170. f.Op = lessEq
  171. case ">=":
  172. f.Op = greaterEq
  173. case "<":
  174. f.Op = lessThan
  175. case ">":
  176. f.Op = greaterThan
  177. case "=":
  178. f.Op = equal
  179. default:
  180. q.err = fmt.Errorf("datastore: invalid operator %q in filter %q", op, filterStr)
  181. return q
  182. }
  183. var err error
  184. f.FieldName, err = unquote(f.FieldName)
  185. if err != nil {
  186. q.err = fmt.Errorf("datastore: invalid syntax for quoted field name %q", f.FieldName)
  187. return q
  188. }
  189. q.filter = append(q.filter, f)
  190. return q
  191. }
  192. // Order returns a derivative query with a field-based sort order. Orders are
  193. // applied in the order they are added. The default order is ascending; to sort
  194. // in descending order prefix the fieldName with a minus sign (-).
  195. // Field names which contain spaces, quote marks, or the minus sign
  196. // should be passed as quoted Go string literals as returned by strconv.Quote
  197. // or the fmt package's %q verb.
  198. func (q *Query) Order(fieldName string) *Query {
  199. q = q.clone()
  200. fieldName, dir := strings.TrimSpace(fieldName), ascending
  201. if strings.HasPrefix(fieldName, "-") {
  202. fieldName, dir = strings.TrimSpace(fieldName[1:]), descending
  203. } else if strings.HasPrefix(fieldName, "+") {
  204. q.err = fmt.Errorf("datastore: invalid order: %q", fieldName)
  205. return q
  206. }
  207. fieldName, err := unquote(fieldName)
  208. if err != nil {
  209. q.err = fmt.Errorf("datastore: invalid syntax for quoted field name %q", fieldName)
  210. return q
  211. }
  212. if fieldName == "" {
  213. q.err = errors.New("datastore: empty order")
  214. return q
  215. }
  216. q.order = append(q.order, order{
  217. Direction: dir,
  218. FieldName: fieldName,
  219. })
  220. return q
  221. }
  222. // unquote optionally interprets s as a double-quoted or backquoted Go
  223. // string literal if it begins with the relevant character.
  224. func unquote(s string) (string, error) {
  225. if s == "" || (s[0] != '`' && s[0] != '"') {
  226. return s, nil
  227. }
  228. return strconv.Unquote(s)
  229. }
  230. // Project returns a derivative query that yields only the given fields. It
  231. // cannot be used with KeysOnly.
  232. func (q *Query) Project(fieldNames ...string) *Query {
  233. q = q.clone()
  234. q.projection = append([]string(nil), fieldNames...)
  235. return q
  236. }
  237. // Distinct returns a derivative query that yields de-duplicated entities with
  238. // respect to the set of projected fields. It is only used for projection
  239. // queries. Distinct cannot be used with DistinctOn.
  240. func (q *Query) Distinct() *Query {
  241. q = q.clone()
  242. q.distinct = true
  243. return q
  244. }
  245. // DistinctOn returns a derivative query that yields de-duplicated entities with
  246. // respect to the set of the specified fields. It is only used for projection
  247. // queries. The field list should be a subset of the projected field list.
  248. // DistinctOn cannot be used with Distinct.
  249. func (q *Query) DistinctOn(fieldNames ...string) *Query {
  250. q = q.clone()
  251. q.distinctOn = fieldNames
  252. return q
  253. }
  254. // KeysOnly returns a derivative query that yields only keys, not keys and
  255. // entities. It cannot be used with projection queries.
  256. func (q *Query) KeysOnly() *Query {
  257. q = q.clone()
  258. q.keysOnly = true
  259. return q
  260. }
  261. // Limit returns a derivative query that has a limit on the number of results
  262. // returned. A negative value means unlimited.
  263. func (q *Query) Limit(limit int) *Query {
  264. q = q.clone()
  265. if limit < math.MinInt32 || limit > math.MaxInt32 {
  266. q.err = errors.New("datastore: query limit overflow")
  267. return q
  268. }
  269. q.limit = int32(limit)
  270. return q
  271. }
  272. // Offset returns a derivative query that has an offset of how many keys to
  273. // skip over before returning results. A negative value is invalid.
  274. func (q *Query) Offset(offset int) *Query {
  275. q = q.clone()
  276. if offset < 0 {
  277. q.err = errors.New("datastore: negative query offset")
  278. return q
  279. }
  280. if offset > math.MaxInt32 {
  281. q.err = errors.New("datastore: query offset overflow")
  282. return q
  283. }
  284. q.offset = int32(offset)
  285. return q
  286. }
  287. // Start returns a derivative query with the given start point.
  288. func (q *Query) Start(c Cursor) *Query {
  289. q = q.clone()
  290. q.start = c.cc
  291. return q
  292. }
  293. // End returns a derivative query with the given end point.
  294. func (q *Query) End(c Cursor) *Query {
  295. q = q.clone()
  296. q.end = c.cc
  297. return q
  298. }
  299. // toProto converts the query to a protocol buffer.
  300. func (q *Query) toProto(req *pb.RunQueryRequest) error {
  301. if len(q.projection) != 0 && q.keysOnly {
  302. return errors.New("datastore: query cannot both project and be keys-only")
  303. }
  304. if len(q.distinctOn) != 0 && q.distinct {
  305. return errors.New("datastore: query cannot be both distinct and distinct-on")
  306. }
  307. dst := &pb.Query{}
  308. if q.kind != "" {
  309. dst.Kind = []*pb.KindExpression{{Name: q.kind}}
  310. }
  311. if q.projection != nil {
  312. for _, propertyName := range q.projection {
  313. dst.Projection = append(dst.Projection, &pb.Projection{Property: &pb.PropertyReference{Name: propertyName}})
  314. }
  315. for _, propertyName := range q.distinctOn {
  316. dst.DistinctOn = append(dst.DistinctOn, &pb.PropertyReference{Name: propertyName})
  317. }
  318. if q.distinct {
  319. for _, propertyName := range q.projection {
  320. dst.DistinctOn = append(dst.DistinctOn, &pb.PropertyReference{Name: propertyName})
  321. }
  322. }
  323. }
  324. if q.keysOnly {
  325. dst.Projection = []*pb.Projection{{Property: &pb.PropertyReference{Name: keyFieldName}}}
  326. }
  327. var filters []*pb.Filter
  328. for _, qf := range q.filter {
  329. if qf.FieldName == "" {
  330. return errors.New("datastore: empty query filter field name")
  331. }
  332. v, err := interfaceToProto(reflect.ValueOf(qf.Value).Interface(), false)
  333. if err != nil {
  334. return fmt.Errorf("datastore: bad query filter value type: %v", err)
  335. }
  336. op, ok := operatorToProto[qf.Op]
  337. if !ok {
  338. return errors.New("datastore: unknown query filter operator")
  339. }
  340. xf := &pb.PropertyFilter{
  341. Op: op,
  342. Property: &pb.PropertyReference{Name: qf.FieldName},
  343. Value: v,
  344. }
  345. filters = append(filters, &pb.Filter{
  346. FilterType: &pb.Filter_PropertyFilter{PropertyFilter: xf},
  347. })
  348. }
  349. if q.ancestor != nil {
  350. filters = append(filters, &pb.Filter{
  351. FilterType: &pb.Filter_PropertyFilter{PropertyFilter: &pb.PropertyFilter{
  352. Property: &pb.PropertyReference{Name: keyFieldName},
  353. Op: pb.PropertyFilter_HAS_ANCESTOR,
  354. Value: &pb.Value{ValueType: &pb.Value_KeyValue{KeyValue: keyToProto(q.ancestor)}},
  355. }}})
  356. }
  357. if len(filters) == 1 {
  358. dst.Filter = filters[0]
  359. } else if len(filters) > 1 {
  360. dst.Filter = &pb.Filter{FilterType: &pb.Filter_CompositeFilter{CompositeFilter: &pb.CompositeFilter{
  361. Op: pb.CompositeFilter_AND,
  362. Filters: filters,
  363. }}}
  364. }
  365. for _, qo := range q.order {
  366. if qo.FieldName == "" {
  367. return errors.New("datastore: empty query order field name")
  368. }
  369. xo := &pb.PropertyOrder{
  370. Property: &pb.PropertyReference{Name: qo.FieldName},
  371. Direction: sortDirectionToProto[qo.Direction],
  372. }
  373. dst.Order = append(dst.Order, xo)
  374. }
  375. if q.limit >= 0 {
  376. dst.Limit = &wrapperspb.Int32Value{Value: q.limit}
  377. }
  378. dst.Offset = q.offset
  379. dst.StartCursor = q.start
  380. dst.EndCursor = q.end
  381. if t := q.trans; t != nil {
  382. if t.id == nil {
  383. return errExpiredTransaction
  384. }
  385. if q.eventual {
  386. return errors.New("datastore: cannot use EventualConsistency query in a transaction")
  387. }
  388. req.ReadOptions = &pb.ReadOptions{
  389. ConsistencyType: &pb.ReadOptions_Transaction{Transaction: t.id},
  390. }
  391. }
  392. if q.eventual {
  393. req.ReadOptions = &pb.ReadOptions{ConsistencyType: &pb.ReadOptions_ReadConsistency_{ReadConsistency: pb.ReadOptions_EVENTUAL}}
  394. }
  395. req.QueryType = &pb.RunQueryRequest_Query{Query: dst}
  396. return nil
  397. }
  398. // Count returns the number of results for the given query.
  399. //
  400. // The running time and number of API calls made by Count scale linearly with
  401. // the sum of the query's offset and limit. Unless the result count is
  402. // expected to be small, it is best to specify a limit; otherwise Count will
  403. // continue until it finishes counting or the provided context expires.
  404. func (c *Client) Count(ctx context.Context, q *Query) (n int, err error) {
  405. ctx = trace.StartSpan(ctx, "cloud.google.com/go/datastore.Query.Count")
  406. defer func() { trace.EndSpan(ctx, err) }()
  407. // Check that the query is well-formed.
  408. if q.err != nil {
  409. return 0, q.err
  410. }
  411. // Create a copy of the query, with keysOnly true (if we're not a projection,
  412. // since the two are incompatible).
  413. newQ := q.clone()
  414. newQ.keysOnly = len(newQ.projection) == 0
  415. // Create an iterator and use it to walk through the batches of results
  416. // directly.
  417. it := c.Run(ctx, newQ)
  418. for {
  419. err := it.nextBatch()
  420. if err == iterator.Done {
  421. return n, nil
  422. }
  423. if err != nil {
  424. return 0, err
  425. }
  426. n += len(it.results)
  427. }
  428. }
  429. // GetAll runs the provided query in the given context and returns all keys
  430. // that match that query, as well as appending the values to dst.
  431. //
  432. // dst must have type *[]S or *[]*S or *[]P, for some struct type S or some non-
  433. // interface, non-pointer type P such that P or *P implements PropertyLoadSaver.
  434. //
  435. // As a special case, *PropertyList is an invalid type for dst, even though a
  436. // PropertyList is a slice of structs. It is treated as invalid to avoid being
  437. // mistakenly passed when *[]PropertyList was intended.
  438. //
  439. // The keys returned by GetAll will be in a 1-1 correspondence with the entities
  440. // added to dst.
  441. //
  442. // If q is a ``keys-only'' query, GetAll ignores dst and only returns the keys.
  443. //
  444. // The running time and number of API calls made by GetAll scale linearly with
  445. // with the sum of the query's offset and limit. Unless the result count is
  446. // expected to be small, it is best to specify a limit; otherwise GetAll will
  447. // continue until it finishes collecting results or the provided context
  448. // expires.
  449. func (c *Client) GetAll(ctx context.Context, q *Query, dst interface{}) (keys []*Key, err error) {
  450. ctx = trace.StartSpan(ctx, "cloud.google.com/go/datastore.Query.GetAll")
  451. defer func() { trace.EndSpan(ctx, err) }()
  452. var (
  453. dv reflect.Value
  454. mat multiArgType
  455. elemType reflect.Type
  456. errFieldMismatch error
  457. )
  458. if !q.keysOnly {
  459. dv = reflect.ValueOf(dst)
  460. if dv.Kind() != reflect.Ptr || dv.IsNil() {
  461. return nil, ErrInvalidEntityType
  462. }
  463. dv = dv.Elem()
  464. mat, elemType = checkMultiArg(dv)
  465. if mat == multiArgTypeInvalid || mat == multiArgTypeInterface {
  466. return nil, ErrInvalidEntityType
  467. }
  468. }
  469. for t := c.Run(ctx, q); ; {
  470. k, e, err := t.next()
  471. if err == iterator.Done {
  472. break
  473. }
  474. if err != nil {
  475. return keys, err
  476. }
  477. if !q.keysOnly {
  478. ev := reflect.New(elemType)
  479. if elemType.Kind() == reflect.Map {
  480. // This is a special case. The zero values of a map type are
  481. // not immediately useful; they have to be make'd.
  482. //
  483. // Funcs and channels are similar, in that a zero value is not useful,
  484. // but even a freshly make'd channel isn't useful: there's no fixed
  485. // channel buffer size that is always going to be large enough, and
  486. // there's no goroutine to drain the other end. Theoretically, these
  487. // types could be supported, for example by sniffing for a constructor
  488. // method or requiring prior registration, but for now it's not a
  489. // frequent enough concern to be worth it. Programmers can work around
  490. // it by explicitly using Iterator.Next instead of the Query.GetAll
  491. // convenience method.
  492. x := reflect.MakeMap(elemType)
  493. ev.Elem().Set(x)
  494. }
  495. if err = loadEntityProto(ev.Interface(), e); err != nil {
  496. if _, ok := err.(*ErrFieldMismatch); ok {
  497. // We continue loading entities even in the face of field mismatch errors.
  498. // If we encounter any other error, that other error is returned. Otherwise,
  499. // an ErrFieldMismatch is returned.
  500. errFieldMismatch = err
  501. } else {
  502. return keys, err
  503. }
  504. }
  505. if mat != multiArgTypeStructPtr {
  506. ev = ev.Elem()
  507. }
  508. dv.Set(reflect.Append(dv, ev))
  509. }
  510. keys = append(keys, k)
  511. }
  512. return keys, errFieldMismatch
  513. }
  514. // Run runs the given query in the given context.
  515. func (c *Client) Run(ctx context.Context, q *Query) *Iterator {
  516. if q.err != nil {
  517. return &Iterator{err: q.err}
  518. }
  519. t := &Iterator{
  520. ctx: ctx,
  521. client: c,
  522. limit: q.limit,
  523. offset: q.offset,
  524. keysOnly: q.keysOnly,
  525. pageCursor: q.start,
  526. entityCursor: q.start,
  527. req: &pb.RunQueryRequest{
  528. ProjectId: c.dataset,
  529. },
  530. }
  531. ctx = trace.StartSpan(ctx, "cloud.google.com/go/datastore.Query.Run")
  532. defer func() { trace.EndSpan(ctx, t.err) }()
  533. if q.namespace != "" {
  534. t.req.PartitionId = &pb.PartitionId{
  535. NamespaceId: q.namespace,
  536. }
  537. }
  538. if err := q.toProto(t.req); err != nil {
  539. t.err = err
  540. }
  541. return t
  542. }
  543. // Iterator is the result of running a query.
  544. type Iterator struct {
  545. ctx context.Context
  546. client *Client
  547. err error
  548. // results is the list of EntityResults still to be iterated over from the
  549. // most recent API call. It will be nil if no requests have yet been issued.
  550. results []*pb.EntityResult
  551. // req is the request to send. It may be modified and used multiple times.
  552. req *pb.RunQueryRequest
  553. // limit is the limit on the number of results this iterator should return.
  554. // The zero value is used to prevent further fetches from the server.
  555. // A negative value means unlimited.
  556. limit int32
  557. // offset is the number of results that still need to be skipped.
  558. offset int32
  559. // keysOnly records whether the query was keys-only (skip entity loading).
  560. keysOnly bool
  561. // pageCursor is the compiled cursor for the next batch/page of result.
  562. // TODO(djd): Can we delete this in favour of paging with the last
  563. // entityCursor from each batch?
  564. pageCursor []byte
  565. // entityCursor is the compiled cursor of the next result.
  566. entityCursor []byte
  567. }
  568. // Next returns the key of the next result. When there are no more results,
  569. // iterator.Done is returned as the error.
  570. //
  571. // If the query is not keys only and dst is non-nil, it also loads the entity
  572. // stored for that key into the struct pointer or PropertyLoadSaver dst, with
  573. // the same semantics and possible errors as for the Get function.
  574. func (t *Iterator) Next(dst interface{}) (k *Key, err error) {
  575. k, e, err := t.next()
  576. if err != nil {
  577. return nil, err
  578. }
  579. if dst != nil && !t.keysOnly {
  580. err = loadEntityProto(dst, e)
  581. }
  582. return k, err
  583. }
  584. func (t *Iterator) next() (*Key, *pb.Entity, error) {
  585. // Fetch additional batches while there are no more results.
  586. for t.err == nil && len(t.results) == 0 {
  587. t.err = t.nextBatch()
  588. }
  589. if t.err != nil {
  590. return nil, nil, t.err
  591. }
  592. // Extract the next result, update cursors, and parse the entity's key.
  593. e := t.results[0]
  594. t.results = t.results[1:]
  595. t.entityCursor = e.Cursor
  596. if len(t.results) == 0 {
  597. t.entityCursor = t.pageCursor // At the end of the batch.
  598. }
  599. if e.Entity.Key == nil {
  600. return nil, nil, errors.New("datastore: internal error: server did not return a key")
  601. }
  602. k, err := protoToKey(e.Entity.Key)
  603. if err != nil || k.Incomplete() {
  604. return nil, nil, errors.New("datastore: internal error: server returned an invalid key")
  605. }
  606. return k, e.Entity, nil
  607. }
  608. // nextBatch makes a single call to the server for a batch of results.
  609. func (t *Iterator) nextBatch() error {
  610. if t.err != nil {
  611. return t.err
  612. }
  613. if t.limit == 0 {
  614. return iterator.Done // Short-circuits the zero-item response.
  615. }
  616. // Adjust the query with the latest start cursor, limit and offset.
  617. q := t.req.GetQuery()
  618. q.StartCursor = t.pageCursor
  619. q.Offset = t.offset
  620. if t.limit >= 0 {
  621. q.Limit = &wrapperspb.Int32Value{Value: t.limit}
  622. } else {
  623. q.Limit = nil
  624. }
  625. // Run the query.
  626. resp, err := t.client.client.RunQuery(t.ctx, t.req)
  627. if err != nil {
  628. return err
  629. }
  630. // Adjust any offset from skipped results.
  631. skip := resp.Batch.SkippedResults
  632. if skip < 0 {
  633. return errors.New("datastore: internal error: negative number of skipped_results")
  634. }
  635. t.offset -= skip
  636. if t.offset < 0 {
  637. return errors.New("datastore: internal error: query skipped too many results")
  638. }
  639. if t.offset > 0 && len(resp.Batch.EntityResults) > 0 {
  640. return errors.New("datastore: internal error: query returned results before requested offset")
  641. }
  642. // Adjust the limit.
  643. if t.limit >= 0 {
  644. t.limit -= int32(len(resp.Batch.EntityResults))
  645. if t.limit < 0 {
  646. return errors.New("datastore: internal error: query returned more results than the limit")
  647. }
  648. }
  649. // If there are no more results available, set limit to zero to prevent
  650. // further fetches. Otherwise, check that there is a next page cursor available.
  651. if resp.Batch.MoreResults != pb.QueryResultBatch_NOT_FINISHED {
  652. t.limit = 0
  653. } else if resp.Batch.EndCursor == nil {
  654. return errors.New("datastore: internal error: server did not return a cursor")
  655. }
  656. // Update cursors.
  657. // If any results were skipped, use the SkippedCursor as the next entity cursor.
  658. if skip > 0 {
  659. t.entityCursor = resp.Batch.SkippedCursor
  660. } else {
  661. t.entityCursor = q.StartCursor
  662. }
  663. t.pageCursor = resp.Batch.EndCursor
  664. t.results = resp.Batch.EntityResults
  665. return nil
  666. }
  667. // Cursor returns a cursor for the iterator's current location.
  668. func (t *Iterator) Cursor() (c Cursor, err error) {
  669. t.ctx = trace.StartSpan(t.ctx, "cloud.google.com/go/datastore.Query.Cursor")
  670. defer func() { trace.EndSpan(t.ctx, err) }()
  671. // If there is still an offset, we need to the skip those results first.
  672. for t.err == nil && t.offset > 0 {
  673. t.err = t.nextBatch()
  674. }
  675. if t.err != nil && t.err != iterator.Done {
  676. return Cursor{}, t.err
  677. }
  678. return Cursor{t.entityCursor}, nil
  679. }
  680. // Cursor is an iterator's position. It can be converted to and from an opaque
  681. // string. A cursor can be used from different HTTP requests, but only with a
  682. // query with the same kind, ancestor, filter and order constraints.
  683. //
  684. // The zero Cursor can be used to indicate that there is no start and/or end
  685. // constraint for a query.
  686. type Cursor struct {
  687. cc []byte
  688. }
  689. // String returns a base-64 string representation of a cursor.
  690. func (c Cursor) String() string {
  691. if c.cc == nil {
  692. return ""
  693. }
  694. return strings.TrimRight(base64.URLEncoding.EncodeToString(c.cc), "=")
  695. }
  696. // DecodeCursor decodes a cursor from its base-64 string representation.
  697. func DecodeCursor(s string) (Cursor, error) {
  698. if s == "" {
  699. return Cursor{}, nil
  700. }
  701. if n := len(s) % 4; n != 0 {
  702. s += strings.Repeat("=", 4-n)
  703. }
  704. b, err := base64.URLEncoding.DecodeString(s)
  705. if err != nil {
  706. return Cursor{}, err
  707. }
  708. return Cursor{b}, nil
  709. }