github.com/go-kivik/kivik/v4@v4.3.2/couchdb/rows.go (about)

     1  // Licensed under the Apache License, Version 2.0 (the "License"); you may not
     2  // use this file except in compliance with the License. You may obtain a copy of
     3  // the License at
     4  //
     5  //  http://www.apache.org/licenses/LICENSE-2.0
     6  //
     7  // Unless required by applicable law or agreed to in writing, software
     8  // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
     9  // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    10  // License for the specific language governing permissions and limitations under
    11  // the License.
    12  
    13  package couchdb
    14  
    15  import (
    16  	"bytes"
    17  	"context"
    18  	"encoding/json"
    19  	"errors"
    20  	"io"
    21  	"strings"
    22  	"sync/atomic"
    23  
    24  	"github.com/go-kivik/kivik/v4/driver"
    25  )
    26  
    27  type rowsMeta struct {
    28  	offset    int64
    29  	totalRows int64
    30  	updateSeq sequenceID
    31  	warning   string
    32  	bookmark  string
    33  }
    34  
    35  type rows struct {
    36  	*iter
    37  	meta *rowsMeta
    38  }
    39  
    40  var _ driver.Rows = &rows{}
    41  
    42  type rowsMetaParser struct{}
    43  
    44  func (p *rowsMetaParser) parseMeta(i interface{}, dec *json.Decoder, key string) error {
    45  	meta := i.(*rowsMeta)
    46  	return meta.parseMeta(key, dec)
    47  }
    48  
    49  type rowParser struct {
    50  	rowsMetaParser
    51  }
    52  
    53  var _ parser = &rowParser{}
    54  
    55  func (p *rowParser) decodeItem(i interface{}, dec *json.Decoder) error {
    56  	row := i.(*driver.Row)
    57  	target := struct {
    58  		*driver.Row
    59  		Value json.RawMessage `json:"value"`
    60  		Doc   json.RawMessage `json:"doc"`
    61  	}{
    62  		Row: row,
    63  	}
    64  	if err := dec.Decode(&target); err != nil {
    65  		return err
    66  	}
    67  	if len(target.Value) > 0 {
    68  		row.Value = bytes.NewReader(target.Value)
    69  	}
    70  	if len(target.Doc) > 0 {
    71  		row.Doc = bytes.NewReader(target.Doc)
    72  	}
    73  	return nil
    74  }
    75  
    76  func newRows(ctx context.Context, in io.ReadCloser) driver.Rows {
    77  	meta := &rowsMeta{}
    78  	return &rows{
    79  		iter: newIter(ctx, meta, "rows", in, &rowParser{}),
    80  		meta: meta,
    81  	}
    82  }
    83  
    84  type findParser struct {
    85  	rowsMetaParser
    86  }
    87  
    88  var _ parser = &findParser{}
    89  
    90  func (p *findParser) decodeItem(i interface{}, dec *json.Decoder) error {
    91  	var doc json.RawMessage
    92  	if err := dec.Decode(&doc); err != nil {
    93  		return err
    94  	}
    95  	row := i.(*driver.Row)
    96  	row.Doc = bytes.NewReader(doc)
    97  	return nil
    98  }
    99  
   100  func newFindRows(ctx context.Context, in io.ReadCloser) driver.Rows {
   101  	meta := &rowsMeta{}
   102  	return &rows{
   103  		iter: newIter(ctx, meta, "docs", in, &findParser{}),
   104  		meta: meta,
   105  	}
   106  }
   107  
   108  type bulkParser struct {
   109  	rowsMetaParser
   110  }
   111  
   112  var _ parser = &bulkParser{}
   113  
   114  func (p *bulkParser) decodeItem(i interface{}, dec *json.Decoder) error {
   115  	row := i.(*driver.Row)
   116  	var result bulkResult
   117  	if err := dec.Decode(&result); err != nil {
   118  		return err
   119  	}
   120  	row.ID = result.ID
   121  	row.Doc = bytes.NewReader(result.Docs[0].Doc)
   122  	row.Error = nil
   123  	if err := result.Docs[0].Error; err != nil {
   124  		row.Error = err
   125  	}
   126  	return nil
   127  }
   128  
   129  func newBulkGetRows(ctx context.Context, in io.ReadCloser) driver.Rows {
   130  	meta := &rowsMeta{}
   131  	return &rows{
   132  		iter: newIter(ctx, meta, "results", in, &bulkParser{}),
   133  		meta: meta,
   134  	}
   135  }
   136  
   137  func (r *rows) Offset() int64 {
   138  	if r.meta == nil {
   139  		return 0
   140  	}
   141  	return r.meta.offset
   142  }
   143  
   144  func (r *rows) TotalRows() int64 {
   145  	if r.meta == nil {
   146  		return 0
   147  	}
   148  	return r.meta.totalRows
   149  }
   150  
   151  func (r *rows) Warning() string {
   152  	if r.meta == nil {
   153  		return ""
   154  	}
   155  	return r.meta.warning
   156  }
   157  
   158  func (r *rows) Bookmark() string {
   159  	if r.meta == nil {
   160  		return ""
   161  	}
   162  	return r.meta.bookmark
   163  }
   164  
   165  func (r *rows) UpdateSeq() string {
   166  	if r.meta == nil {
   167  		return ""
   168  	}
   169  	return string(r.meta.updateSeq)
   170  }
   171  
   172  func (r *rows) Next(row *driver.Row) error {
   173  	row.Error = nil
   174  	return r.iter.next(row)
   175  }
   176  
   177  // parseMeta parses result metadata
   178  func (r *rowsMeta) parseMeta(key string, dec *json.Decoder) error {
   179  	switch key {
   180  	case "update_seq":
   181  		return dec.Decode(&r.updateSeq)
   182  	case "offset":
   183  		return dec.Decode(&r.offset)
   184  	case "total_rows":
   185  		return dec.Decode(&r.totalRows)
   186  	case "warning":
   187  		return dec.Decode(&r.warning)
   188  	case "bookmark":
   189  		return dec.Decode(&r.bookmark)
   190  	default:
   191  		// Just consume the value, since we don't know what it means.
   192  		var discard json.RawMessage
   193  		return dec.Decode(&discard)
   194  	}
   195  }
   196  
   197  func newMultiQueriesRows(ctx context.Context, in io.ReadCloser) driver.Rows {
   198  	return &multiQueriesRows{
   199  		ctx: ctx,
   200  		r:   in,
   201  	}
   202  }
   203  
   204  type multiQueriesRows struct {
   205  	*rows
   206  	ctx        context.Context
   207  	r          io.ReadCloser
   208  	dec        *json.Decoder
   209  	queryIndex int
   210  	closed     int32
   211  
   212  	// legacy indicates this is an old-style iterator, and won't have more than
   213  	// one resultset.
   214  	legacy int32
   215  }
   216  
   217  func (r *multiQueriesRows) Next(row *driver.Row) error {
   218  	if atomic.LoadInt32(&r.closed) == 1 {
   219  		return io.EOF
   220  	}
   221  	if r.rows != nil && atomic.LoadInt32(&r.rows.closed) == 1 {
   222  		if err := r.nextQuery(); err != nil {
   223  			return err
   224  		}
   225  	}
   226  	if r.dec == nil {
   227  		if err := r.begin(); err != nil {
   228  			return err
   229  		}
   230  	}
   231  	if err := r.rows.Next(row); err != nil {
   232  		if err == io.EOF && atomic.LoadInt32(&r.legacy) == 0 {
   233  			return driver.EOQ
   234  		}
   235  		return err
   236  	}
   237  	return nil
   238  }
   239  
   240  func (r *multiQueriesRows) begin() error {
   241  	r.dec = json.NewDecoder(r.r)
   242  	// consume the first '{'
   243  	if err := consumeDelim(r.dec, json.Delim('{')); err != nil {
   244  		return err
   245  	}
   246  	key, err := nextKey(r.dec)
   247  	if err != nil {
   248  		return err
   249  	}
   250  	if key != "results" {
   251  		// These indicate the server does not support multiple queries; probably
   252  		// an old version.  Fall back to the standard iterator.
   253  		atomic.StoreInt32(&r.legacy, 1)
   254  		keyJSON, _ := json.Marshal(key)
   255  		var in io.ReadCloser = struct {
   256  			io.Reader
   257  			io.Closer
   258  		}{
   259  			Reader: io.MultiReader(
   260  				strings.NewReader("{"),
   261  				bytes.NewReader(keyJSON),
   262  				r.dec.Buffered(),
   263  				r.r),
   264  			Closer: r.r,
   265  		}
   266  		r.rows = newRows(r.ctx, in).(*rows)
   267  		r.rows.body = nil
   268  		r.rows.dec = json.NewDecoder(in)
   269  		return r.rows.begin()
   270  	}
   271  	// consume the opening '['
   272  	if err := consumeDelim(r.dec, json.Delim('[')); err != nil {
   273  		return err
   274  	}
   275  	r.rows = newRows(r.ctx, r.r).(*rows)
   276  	r.rows.body = nil
   277  	r.rows.iter.dec = r.dec
   278  	return r.rows.iter.begin()
   279  }
   280  
   281  func (r *multiQueriesRows) nextQuery() error {
   282  	if atomic.LoadInt32(&r.legacy) == 1 {
   283  		if err := r.Close(); err != nil {
   284  			return err
   285  		}
   286  		return io.EOF
   287  	}
   288  	rows := newRows(r.ctx, r.r).(*rows)
   289  	rows.iter.dec = r.dec
   290  	if err := rows.iter.begin(); err != nil {
   291  		var ud unexpectedDelim
   292  		if errors.As(err, &ud); ud == unexpectedDelim(']') {
   293  			if err := r.Close(); err != nil {
   294  				return err
   295  			}
   296  			return io.EOF
   297  		}
   298  		return err
   299  	}
   300  	r.queryIndex++
   301  	r.rows = rows
   302  	r.rows.body = nil
   303  	return nil
   304  }
   305  
   306  func (r *multiQueriesRows) Close() error {
   307  	if atomic.AddInt32(&r.closed, 1) > 1 {
   308  		return nil
   309  	}
   310  	r.dec = nil
   311  	if r.rows != nil {
   312  		defer r.rows.Close()
   313  	}
   314  	defer r.r.Close()
   315  	if _, err := io.ReadAll(r.r); err != nil {
   316  		return err
   317  	}
   318  	if err := r.r.Close(); err != nil {
   319  		return err
   320  	}
   321  	if r.rows == nil {
   322  		return nil
   323  	}
   324  	return r.rows.Close()
   325  }
   326  
   327  func (r *multiQueriesRows) QueryIndex() int {
   328  	return r.queryIndex
   329  }