...
1
2
3
4
5
6
7
8
9
10
11
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
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