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  }