gopkg.in/rethinkdb/rethinkdb-go.v6@v6.2.2/cursor.go (about) 1 package rethinkdb 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "errors" 7 "reflect" 8 "sync" 9 10 "github.com/opentracing/opentracing-go" 11 "golang.org/x/net/context" 12 "gopkg.in/rethinkdb/rethinkdb-go.v6/encoding" 13 p "gopkg.in/rethinkdb/rethinkdb-go.v6/ql2" 14 ) 15 16 var ( 17 errNilCursor = errors.New("cursor is nil") 18 errCursorClosed = errors.New("connection connClosed, cannot read cursor") 19 ) 20 21 func newCursor(ctx context.Context, conn *Connection, cursorType string, token int64, term *Term, opts map[string]interface{}) *Cursor { 22 if cursorType == "" { 23 cursorType = "Cursor" 24 } 25 26 connOpts := &ConnectOpts{} 27 if conn != nil { 28 connOpts = conn.opts 29 } 30 31 cursor := &Cursor{ 32 conn: conn, 33 connOpts: connOpts, 34 token: token, 35 cursorType: cursorType, 36 term: term, 37 opts: opts, 38 buffer: make([]interface{}, 0), 39 responses: make([]json.RawMessage, 0), 40 ctx: ctx, 41 } 42 43 return cursor 44 } 45 46 // Cursor is the result of a query. Its cursor starts before the first row 47 // of the result set. A Cursor is not thread safe and should only be accessed 48 // by a single goroutine at any given time. Use Next to advance through the 49 // rows: 50 // 51 // cursor, err := query.Run(session) 52 // ... 53 // defer cursor.Close() 54 // 55 // var response interface{} 56 // for cursor.Next(&response) { 57 // ... 58 // } 59 // err = cursor.Err() // get any error encountered during iteration 60 // ... 61 type Cursor struct { 62 releaseConn func() error 63 64 conn *Connection 65 connOpts *ConnectOpts 66 token int64 67 cursorType string 68 term *Term 69 opts map[string]interface{} 70 ctx context.Context 71 72 mu sync.RWMutex 73 lastErr error 74 fetching bool 75 closed bool 76 finished bool 77 isAtom bool 78 isSingleValue bool 79 pendingSkips int 80 buffer []interface{} 81 responses []json.RawMessage 82 profile interface{} 83 } 84 85 // Profile returns the information returned from the query profiler. 86 func (c *Cursor) Profile() interface{} { 87 if c == nil { 88 return nil 89 } 90 91 c.mu.RLock() 92 defer c.mu.RUnlock() 93 94 return c.profile 95 } 96 97 // Type returns the cursor type (by default "Cursor") 98 func (c *Cursor) Type() string { 99 if c == nil { 100 return "Cursor" 101 } 102 103 c.mu.RLock() 104 defer c.mu.RUnlock() 105 106 return c.cursorType 107 } 108 109 // Err returns nil if no errors happened during iteration, or the actual 110 // error otherwise. 111 func (c *Cursor) Err() error { 112 if c == nil { 113 return errNilCursor 114 } 115 116 c.mu.RLock() 117 defer c.mu.RUnlock() 118 119 return c.lastErr 120 } 121 122 // Close closes the cursor, preventing further enumeration. If the end is 123 // encountered, the cursor is connClosed automatically. Close is idempotent. 124 func (c *Cursor) Close() error { 125 if c == nil { 126 return errNilCursor 127 } 128 129 c.mu.Lock() 130 defer c.mu.Unlock() 131 132 var err error 133 134 // If cursor is already connClosed return immediately 135 closed := c.closed 136 if closed { 137 return nil 138 } 139 140 // Get connection and check its valid, don't need to lock as this is only 141 // set when the cursor is created 142 conn := c.conn 143 if conn == nil { 144 return nil 145 } 146 if conn.isClosed() { 147 return nil 148 } 149 150 // Stop any unfinished queries 151 if !c.finished { 152 _, _, err = conn.Query(c.ctx, newStopQuery(c.token)) 153 } 154 155 if c.releaseConn != nil { 156 if err := c.releaseConn(); err != nil { 157 return err 158 } 159 } 160 161 if span := opentracing.SpanFromContext(c.ctx); span != nil { 162 span.Finish() 163 } 164 165 c.closed = true 166 c.conn = nil 167 c.buffer = nil 168 c.responses = nil 169 170 return err 171 } 172 173 // Next retrieves the next document from the result set, blocking if necessary. 174 // This method will also automatically retrieve another batch of documents from 175 // the server when the current one is exhausted, or before that in background 176 // if possible. 177 // 178 // Next returns true if a document was successfully unmarshalled onto result, 179 // and false at the end of the result set or if an error happened. 180 // When Next returns false, the Err method should be called to verify if 181 // there was an error during iteration. 182 // 183 // Also note that you are able to reuse the same variable multiple times as 184 // `Next` zeroes the value before scanning in the result. 185 func (c *Cursor) Next(dest interface{}) bool { 186 if c == nil { 187 return false 188 } 189 190 c.mu.Lock() 191 if c.closed { 192 c.mu.Unlock() 193 return false 194 } 195 196 hasMore, err := c.nextLocked(dest, true) 197 if c.handleErrorLocked(err) != nil { 198 c.mu.Unlock() 199 c.Close() 200 return false 201 } 202 c.mu.Unlock() 203 204 if !hasMore { 205 c.Close() 206 } 207 208 return hasMore 209 } 210 211 func (c *Cursor) nextLocked(dest interface{}, progressCursor bool) (bool, error) { 212 for { 213 if err := c.seekCursor(true); err != nil { 214 return false, err 215 } 216 217 if c.closed { 218 return false, nil 219 } 220 221 if len(c.buffer) == 0 && c.finished { 222 return false, nil 223 } 224 225 if len(c.buffer) > 0 { 226 data := c.buffer[0] 227 if progressCursor { 228 c.buffer = c.buffer[1:] 229 } 230 err := encoding.Decode(dest, data) 231 if err != nil { 232 return false, err 233 } 234 235 return true, nil 236 } 237 } 238 } 239 240 // Peek behaves similarly to Next, retreiving the next document from the result set 241 // and blocking if necessary. Peek, however, does not progress the position of the cursor. 242 // This can be useful for expressions which can return different types to attempt to 243 // decode them into different interfaces. 244 // 245 // Like Next, it will also automatically retrieve another batch of documents from 246 // the server when the current one is exhausted, or before that in background 247 // if possible. 248 // 249 // Unlike Next, Peek does not progress the position of the cursor. Peek 250 // will return errors from decoding, but they will not be persisted in the cursor 251 // and therefore will not be available on cursor.Err(). This can be useful for 252 // expressions that can return different types to attempt to decode them into 253 // different interfaces. 254 // 255 // Peek returns true if a document was successfully unmarshalled onto result, 256 // and false at the end of the result set or if an error happened. Peek also 257 // returns the error (if any) that occured 258 func (c *Cursor) Peek(dest interface{}) (bool, error) { 259 if c == nil { 260 return false, errNilCursor 261 } 262 263 c.mu.Lock() 264 if c.closed { 265 c.mu.Unlock() 266 return false, nil 267 } 268 269 hasMore, err := c.nextLocked(dest, false) 270 if _, isDecodeErr := err.(*encoding.DecodeTypeError); isDecodeErr { 271 c.mu.Unlock() 272 return false, err 273 } 274 275 if c.handleErrorLocked(err) != nil { 276 c.mu.Unlock() 277 c.Close() 278 return false, err 279 } 280 c.mu.Unlock() 281 282 return hasMore, nil 283 } 284 285 // Skip progresses the cursor by one record. It is useful after a successful 286 // Peek to avoid duplicate decoding work. 287 func (c *Cursor) Skip() { 288 if c == nil { 289 return 290 } 291 292 c.mu.Lock() 293 defer c.mu.Unlock() 294 c.pendingSkips++ 295 } 296 297 // NextResponse retrieves the next raw response from the result set, blocking if necessary. 298 // Unlike Next the returned response is the raw JSON document returned from the 299 // database. 300 // 301 // NextResponse returns false (and a nil byte slice) at the end of the result 302 // set or if an error happened. 303 func (c *Cursor) NextResponse() ([]byte, bool) { 304 if c == nil { 305 return nil, false 306 } 307 308 c.mu.Lock() 309 if c.closed { 310 c.mu.Unlock() 311 return nil, false 312 } 313 314 b, hasMore, err := c.nextResponseLocked() 315 if c.handleErrorLocked(err) != nil { 316 c.mu.Unlock() 317 c.Close() 318 return nil, false 319 } 320 c.mu.Unlock() 321 322 if !hasMore { 323 c.Close() 324 } 325 326 return b, hasMore 327 } 328 329 func (c *Cursor) nextResponseLocked() ([]byte, bool, error) { 330 for { 331 if err := c.seekCursor(false); err != nil { 332 return nil, false, err 333 } 334 335 if len(c.responses) == 0 && c.finished { 336 return nil, false, nil 337 } 338 339 if len(c.responses) > 0 { 340 var response json.RawMessage 341 response, c.responses = c.responses[0], c.responses[1:] 342 343 return []byte(response), true, nil 344 } 345 } 346 } 347 348 // All retrieves all documents from the result set into the provided slice 349 // and closes the cursor. 350 // 351 // The result argument must necessarily be the address for a slice. The slice 352 // may be nil or previously allocated. 353 // 354 // Also note that you are able to reuse the same variable multiple times as 355 // `All` zeroes the value before scanning in the result. It also attempts 356 // to reuse the existing slice without allocating any more space by either 357 // resizing or returning a selection of the slice if necessary. 358 func (c *Cursor) All(result interface{}) error { 359 if c == nil { 360 return errNilCursor 361 } 362 363 resultv := reflect.ValueOf(result) 364 if resultv.Kind() != reflect.Ptr || resultv.Elem().Kind() != reflect.Slice { 365 panic("result argument must be a slice address") 366 } 367 slicev := resultv.Elem() 368 slicev = slicev.Slice(0, slicev.Cap()) 369 elemt := slicev.Type().Elem() 370 i := 0 371 for { 372 if slicev.Len() == i { 373 elemp := reflect.New(elemt) 374 if !c.Next(elemp.Interface()) { 375 break 376 } 377 slicev = reflect.Append(slicev, elemp.Elem()) 378 slicev = slicev.Slice(0, slicev.Cap()) 379 } else { 380 if !c.Next(slicev.Index(i).Addr().Interface()) { 381 break 382 } 383 } 384 i++ 385 } 386 resultv.Elem().Set(slicev.Slice(0, i)) 387 388 if err := c.Err(); err != nil { 389 _ = c.Close() 390 return err 391 } 392 393 if err := c.Close(); err != nil { 394 return err 395 } 396 397 return nil 398 } 399 400 // One retrieves a single document from the result set into the provided 401 // slice and closes the cursor. 402 // 403 // Also note that you are able to reuse the same variable multiple times as 404 // `One` zeroes the value before scanning in the result. 405 func (c *Cursor) One(result interface{}) error { 406 if c == nil { 407 return errNilCursor 408 } 409 410 if c.IsNil() { 411 c.Close() 412 return ErrEmptyResult 413 } 414 415 hasResult := c.Next(result) 416 417 if err := c.Err(); err != nil { 418 c.Close() 419 return err 420 } 421 422 if err := c.Close(); err != nil { 423 return err 424 } 425 426 if !hasResult { 427 return ErrEmptyResult 428 } 429 430 return nil 431 } 432 433 // Interface retrieves all documents from the result set and returns the data 434 // as an interface{} and closes the cursor. 435 // 436 // If the query returns multiple documents then a slice will be returned, 437 // otherwise a single value will be returned. 438 func (c *Cursor) Interface() (interface{}, error) { 439 if c == nil { 440 return nil, errNilCursor 441 } 442 443 var results []interface{} 444 var result interface{} 445 for c.Next(&result) { 446 results = append(results, result) 447 } 448 449 if err := c.Err(); err != nil { 450 return nil, err 451 } 452 453 c.mu.RLock() 454 isSingleValue := c.isSingleValue 455 c.mu.RUnlock() 456 457 if isSingleValue { 458 if len(results) == 0 { 459 return nil, nil 460 } 461 462 return results[0], nil 463 } 464 465 return results, nil 466 } 467 468 // Listen listens for rows from the database and sends the result onto the given 469 // channel. The type that the row is scanned into is determined by the element 470 // type of the channel. 471 // 472 // Also note that this function returns immediately. 473 // 474 // cursor, err := r.Expr([]int{1,2,3}).Run(session) 475 // if err != nil { 476 // panic(err) 477 // } 478 // 479 // ch := make(chan int) 480 // cursor.Listen(ch) 481 // <- ch // 1 482 // <- ch // 2 483 // <- ch // 3 484 func (c *Cursor) Listen(channel interface{}) { 485 go func() { 486 channelv := reflect.ValueOf(channel) 487 if channelv.Kind() != reflect.Chan { 488 panic("input argument must be a channel") 489 } 490 elemt := channelv.Type().Elem() 491 for { 492 elemp := reflect.New(elemt) 493 if !c.Next(elemp.Interface()) { 494 break 495 } 496 channelv.Send(elemp.Elem()) 497 } 498 499 c.Close() 500 channelv.Close() 501 }() 502 } 503 504 // IsNil tests if the current row is nil. 505 func (c *Cursor) IsNil() bool { 506 if c == nil { 507 return true 508 } 509 510 c.mu.RLock() 511 defer c.mu.RUnlock() 512 513 if len(c.buffer) > 0 { 514 return c.buffer[0] == nil 515 } 516 517 if len(c.responses) > 0 { 518 response := c.responses[0] 519 if response == nil { 520 return true 521 } 522 523 if string(response) == "null" { 524 return true 525 } 526 527 return false 528 } 529 530 return true 531 } 532 533 // fetchMore fetches more rows from the database. 534 // 535 // If wait is true then it will wait for the database to reply otherwise it 536 // will return after sending the continue query. 537 func (c *Cursor) fetchMore() error { 538 var err error 539 540 if !c.fetching { 541 c.fetching = true 542 543 if c.closed { 544 return errCursorClosed 545 } 546 547 q := Query{ 548 Type: p.Query_CONTINUE, 549 Token: c.token, 550 } 551 552 c.mu.Unlock() 553 _, _, err = c.conn.Query(c.ctx, q) 554 c.mu.Lock() 555 } 556 557 return err 558 } 559 560 // handleError sets the value of lastErr to err if lastErr is not yet set. 561 func (c *Cursor) handleError(err error) error { 562 c.mu.Lock() 563 defer c.mu.Unlock() 564 565 return c.handleErrorLocked(err) 566 } 567 568 func (c *Cursor) handleErrorLocked(err error) error { 569 if c.lastErr == nil { 570 c.lastErr = err 571 } 572 573 return c.lastErr 574 } 575 576 // extend adds the result of a continue query to the cursor. 577 func (c *Cursor) extend(response *Response) { 578 c.mu.Lock() 579 defer c.mu.Unlock() 580 581 c.extendLocked(response) 582 } 583 584 func (c *Cursor) extendLocked(response *Response) { 585 c.responses = append(c.responses, response.Responses...) 586 c.finished = response.Type != p.Response_SUCCESS_PARTIAL 587 c.fetching = false 588 c.isAtom = response.Type == p.Response_SUCCESS_ATOM 589 } 590 591 // seekCursor takes care of loading more data if needed and applying pending skips 592 // 593 // bufferResponse determines whether the response will be parsed into the buffer 594 func (c *Cursor) seekCursor(bufferResponse bool) error { 595 if c.lastErr != nil { 596 return c.lastErr 597 } 598 599 if len(c.buffer) == 0 && len(c.responses) == 0 && c.closed { 600 return errCursorClosed 601 } 602 603 // Loop over loading data, applying skips as necessary and loading more data as needed 604 // until either the cursor is connClosed or finished, or we have applied all outstanding 605 // skips and data is available 606 for { 607 c.applyPendingSkips(bufferResponse) // if we are buffering the responses, skip can drain from the buffer 608 609 if bufferResponse && len(c.buffer) == 0 && len(c.responses) > 0 { 610 if err := c.bufferNextResponse(); err != nil { 611 return err 612 } 613 continue // go around the loop again to re-apply pending skips 614 } else if len(c.buffer) == 0 && len(c.responses) == 0 && !c.finished { 615 // We skipped all of our data, load some more 616 if err := c.fetchMore(); err != nil { 617 return err 618 } 619 if c.closed { 620 return nil 621 } 622 continue // go around the loop again to re-apply pending skips 623 } 624 return nil 625 } 626 } 627 628 // applyPendingSkips applies all pending skips to the buffer and 629 // returns whether there are more pending skips to be applied 630 // 631 // if drainFromBuffer is true, we will drain from the buffer, otherwise 632 // we drain from the responses 633 func (c *Cursor) applyPendingSkips(drainFromBuffer bool) (stillPending bool) { 634 if c.pendingSkips == 0 { 635 return false 636 } 637 638 if drainFromBuffer { 639 if len(c.buffer) > c.pendingSkips { 640 c.buffer = c.buffer[c.pendingSkips:] 641 c.pendingSkips = 0 642 return false 643 } 644 645 c.pendingSkips -= len(c.buffer) 646 c.buffer = c.buffer[:0] 647 return c.pendingSkips > 0 648 } 649 650 if len(c.responses) > c.pendingSkips { 651 c.responses = c.responses[c.pendingSkips:] 652 c.pendingSkips = 0 653 return false 654 } 655 656 c.pendingSkips -= len(c.responses) 657 c.responses = c.responses[:0] 658 return c.pendingSkips > 0 659 } 660 661 // bufferResponse reads a single response and stores the result into the buffer 662 // if the response is from an atomic response, it will check if the 663 // response contains multiple records and store them all into the buffer 664 func (c *Cursor) bufferNextResponse() error { 665 if c.closed { 666 return errCursorClosed 667 } 668 // If there are no responses, nothing to do 669 if len(c.responses) == 0 { 670 return nil 671 } 672 673 response := c.responses[0] 674 c.responses = c.responses[1:] 675 676 var value interface{} 677 decoder := json.NewDecoder(bytes.NewBuffer(response)) 678 if c.connOpts.UseJSONNumber { 679 decoder.UseNumber() 680 } 681 err := decoder.Decode(&value) 682 if err != nil { 683 return err 684 } 685 686 value, err = recursivelyConvertPseudotype(value, c.opts) 687 if err != nil { 688 return err 689 } 690 691 // If response is an ATOM then try and convert to an array 692 if data, ok := value.([]interface{}); ok && c.isAtom { 693 c.buffer = append(c.buffer, data...) 694 } else if value == nil { 695 c.buffer = append(c.buffer, nil) 696 } else { 697 c.buffer = append(c.buffer, value) 698 699 // If this is the only value in the response and the response was an 700 // atom then set the single value flag 701 if c.isAtom { 702 c.isSingleValue = true 703 } 704 } 705 return nil 706 }