...
1
2
3
4
5
6
7
8
9
10
11
12
13 package kivik
14
15 import (
16 "bytes"
17 "encoding/json"
18 "io"
19
20 "github.com/go-kivik/kivik/v4/driver"
21 )
22
23
24 type Attachments map[string]*Attachment
25
26
27 func (a *Attachments) Get(filename string) *Attachment {
28 return map[string]*Attachment(*a)[filename]
29 }
30
31
32
33 func (a *Attachments) Set(filename string, att *Attachment) {
34 map[string]*Attachment(*a)[filename] = att
35 }
36
37
38 func (a *Attachments) Delete(filename string) {
39 delete(map[string]*Attachment(*a), filename)
40 }
41
42
43 type Attachment struct {
44
45 Filename string `json:"-"`
46
47
48 ContentType string `json:"content_type"`
49
50
51
52
53
54 Stub bool `json:"stub"`
55
56
57
58 Follows bool `json:"follows"`
59
60
61
62
63
64
65 Content io.ReadCloser `json:"-"`
66
67
68
69
70
71 Size int64 `json:"length"`
72
73
74
75 ContentEncoding string `json:"encoding"`
76
77
78
79 EncodedLength int64 `json:"encoded_length"`
80
81
82 RevPos int64 `json:"revpos"`
83
84
85 Digest string `json:"digest"`
86 }
87
88
89 type bufCloser struct {
90 *bytes.Buffer
91 }
92
93 var _ io.ReadCloser = &bufCloser{}
94
95 func (b *bufCloser) Close() error { return nil }
96
97
98 func (a *Attachment) validate() error {
99 if a == nil {
100 return missingArg("attachment")
101 }
102 if a.Filename == "" {
103 return missingArg("filename")
104 }
105 return nil
106 }
107
108
109 func (a *Attachment) MarshalJSON() ([]byte, error) {
110 type jsonAttachment struct {
111 ContentType string `json:"content_type"`
112 Stub *bool `json:"stub,omitempty"`
113 Follows *bool `json:"follows,omitempty"`
114 Size int64 `json:"length,omitempty"`
115 RevPos int64 `json:"revpos,omitempty"`
116 Data []byte `json:"data,omitempty"`
117 Digest string `json:"digest,omitempty"`
118 }
119 att := &jsonAttachment{
120 ContentType: a.ContentType,
121 Size: a.Size,
122 RevPos: a.RevPos,
123 Digest: a.Digest,
124 }
125 switch {
126 case a.Stub:
127 att.Stub = &a.Stub
128 case a.Follows:
129 att.Follows = &a.Follows
130 default:
131 defer a.Content.Close()
132 data, err := io.ReadAll(a.Content)
133 if err != nil {
134 return nil, err
135 }
136 att.Data = data
137 }
138 return json.Marshal(att)
139 }
140
141
142 func (a *Attachment) UnmarshalJSON(data []byte) error {
143 type clone Attachment
144 type jsonAtt struct {
145 clone
146 Data []byte `json:"data"`
147 }
148 var att jsonAtt
149 if err := json.Unmarshal(data, &att); err != nil {
150 return err
151 }
152 *a = Attachment(att.clone)
153 if att.Data != nil {
154 a.Content = io.NopCloser(bytes.NewReader(att.Data))
155 } else {
156 a.Content = nilContent
157 }
158 return nil
159 }
160
161
162 func (a *Attachments) UnmarshalJSON(data []byte) error {
163 atts := make(map[string]*Attachment)
164 if err := json.Unmarshal(data, &atts); err != nil {
165 return err
166 }
167 for filename, att := range atts {
168 att.Filename = filename
169 }
170 *a = atts
171 return nil
172 }
173
174
175
176 type AttachmentsIterator struct {
177 atti driver.Attachments
178 onClose func()
179 }
180
181
182
183
184
185
186 func (i *AttachmentsIterator) Next() (*Attachment, error) {
187 att := new(driver.Attachment)
188 if err := i.atti.Next(att); err != nil {
189 if err == io.EOF {
190 if e2 := i.Close(); e2 != nil {
191 return nil, e2
192 }
193 }
194 return nil, err
195 }
196 katt := Attachment(*att)
197 return &katt, nil
198 }
199
200
201
202 func (i *AttachmentsIterator) Close() error {
203 if i.onClose != nil {
204 i.onClose()
205 }
206 return i.atti.Close()
207 }
208
209
210
211
212 func (i *AttachmentsIterator) Iterator() func(yield func(*Attachment, error) bool) {
213 return func(yield func(*Attachment, error) bool) {
214 for {
215 att, err := i.Next()
216 if err == io.EOF {
217 return
218 }
219 if !yield(att, err) || err != nil {
220 _ = i.Close()
221 return
222 }
223 }
224 }
225 }
226
View as plain text