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 }