...

Source file src/github.com/go-kivik/kivik/v4/x/fsdb/revsdiff.go

Documentation: github.com/go-kivik/kivik/v4/x/fsdb

     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 fs
    14  
    15  import (
    16  	"bytes"
    17  	"context"
    18  	"encoding/json"
    19  	"io"
    20  	"net/http"
    21  
    22  	"github.com/go-kivik/kivik/v4"
    23  	"github.com/go-kivik/kivik/v4/driver"
    24  )
    25  
    26  var _ driver.RevsDiffer = &db{}
    27  
    28  func toRevmap(i interface{}) (map[string][]string, error) {
    29  	if t, ok := i.(map[string][]string); ok {
    30  		return t, nil
    31  	}
    32  	encoded, err := json.Marshal(i)
    33  	if err != nil {
    34  		return nil, statusError{status: http.StatusBadRequest, error: err}
    35  	}
    36  	revmap := make(map[string][]string)
    37  	err = json.Unmarshal(encoded, &revmap)
    38  	return revmap, statusError{status: http.StatusBadRequest, error: err}
    39  }
    40  
    41  func (d *db) RevsDiff(ctx context.Context, revMap interface{}) (driver.Rows, error) {
    42  	revmap, err := toRevmap(revMap)
    43  	if err != nil {
    44  		return nil, err
    45  	}
    46  	return &revDiffRows{
    47  		ctx:    ctx,
    48  		db:     d,
    49  		revmap: revmap,
    50  	}, nil
    51  }
    52  
    53  type revDiffRows struct {
    54  	ctx    context.Context
    55  	db     *db
    56  	revmap map[string][]string
    57  }
    58  
    59  var _ driver.Rows = &revDiffRows{}
    60  
    61  func (r *revDiffRows) Close() error {
    62  	r.revmap = nil
    63  	return nil
    64  }
    65  
    66  // maxRev returns the highest key from the map
    67  func maxRev(revs map[string]struct{}) string {
    68  	var max string
    69  	for k := range revs {
    70  		if k > max {
    71  			max = k
    72  		}
    73  	}
    74  	return max
    75  }
    76  
    77  func (r *revDiffRows) next() (docID string, missing []string, err error) {
    78  	if len(r.revmap) == 0 {
    79  		return "", nil, io.EOF
    80  	}
    81  	if err := r.ctx.Err(); err != nil {
    82  		return "", nil, err
    83  	}
    84  	revs := map[string]struct{}{}
    85  	for k, v := range r.revmap {
    86  		docID = k
    87  		for _, rev := range v {
    88  			revs[rev] = struct{}{}
    89  		}
    90  		break
    91  	}
    92  	delete(r.revmap, docID)
    93  	for len(revs) > 0 {
    94  		rev := maxRev(revs)
    95  		delete(revs, rev)
    96  		doc, err := r.db.cdb.OpenDocID(docID, kivik.Rev(rev))
    97  		if kivik.HTTPStatus(err) == http.StatusNotFound {
    98  			missing = append(missing, rev)
    99  			continue
   100  		}
   101  		if err != nil {
   102  			return "", nil, err
   103  		}
   104  		for _, revid := range doc.Revisions[0].RevHistory.Ancestors()[1:] {
   105  			delete(revs, revid)
   106  		}
   107  	}
   108  	if len(missing) == 0 {
   109  		return r.next()
   110  	}
   111  	return docID, missing, nil
   112  }
   113  
   114  func (r *revDiffRows) Next(row *driver.Row) error {
   115  	docID, missing, err := r.next()
   116  	if err != nil {
   117  		return err
   118  	}
   119  	row.ID = docID
   120  	value, err := json.Marshal(map[string][]string{
   121  		"missing": missing,
   122  	})
   123  	row.Value = bytes.NewReader(value)
   124  	return err
   125  }
   126  
   127  func (r *revDiffRows) Offset() int64     { return 0 }
   128  func (r *revDiffRows) TotalRows() int64  { return 0 }
   129  func (r *revDiffRows) UpdateSeq() string { return "" }
   130  

View as plain text