Given a document body, invokes the callback once for each attachment that doesn't include its data, and isn't present with a matching digest on the existing doc (existingDigests). The callback is told whether the attachment body is known to the database, according to its digest. If the attachment is
(body Body, minRevpos int, docID string, existingDigests map[string]string, callback AttachmentCallback)
| 289 | // to its digest. If the attachment isn't known, the callback can return data for it, which will |
| 290 | // be added to the metadata as a "data" property. |
| 291 | func (c *DatabaseCollection) ForEachStubAttachment(body Body, minRevpos int, docID string, existingDigests map[string]string, callback AttachmentCallback) error { |
| 292 | atts := GetBodyAttachments(body) |
| 293 | if atts == nil && body[BodyAttachments] != nil { |
| 294 | return base.HTTPErrorf(http.StatusBadRequest, "Invalid _attachments") |
| 295 | } |
| 296 | for name, value := range atts { |
| 297 | meta, ok := value.(map[string]interface{}) |
| 298 | if !ok { |
| 299 | return base.HTTPErrorf(http.StatusBadRequest, "Invalid attachment") |
| 300 | } |
| 301 | if meta["data"] == nil { |
| 302 | if revpos, ok := base.ToInt64(meta["revpos"]); revpos < int64(minRevpos) || (!ok && minRevpos > 0) { |
| 303 | continue |
| 304 | } |
| 305 | digest, ok := meta["digest"].(string) |
| 306 | if !ok { |
| 307 | return base.HTTPErrorf(http.StatusBadRequest, "Invalid attachment") |
| 308 | } |
| 309 | |
| 310 | // If digest matches the one on existing doc, SG doesn't need to prove/get |
| 311 | existingDigest, existingOk := existingDigests[name] |
| 312 | if existingOk && existingDigest == digest { |
| 313 | // see CBG-2010 for discussion of potential existence check here |
| 314 | continue |
| 315 | } |
| 316 | |
| 317 | // Assumes the attachment is always AttVersion2 while checking whether it has already been uploaded. |
| 318 | attachmentKey := MakeAttachmentKey(AttVersion2, docID, digest) |
| 319 | data, err := c.GetAttachment(attachmentKey) |
| 320 | if err != nil && !base.IsDocNotFoundError(err) { |
| 321 | return err |
| 322 | } |
| 323 | newData, err := callback(name, digest, data, meta) |
| 324 | if err != nil { |
| 325 | return err |
| 326 | } |
| 327 | if newData != nil { |
| 328 | meta["data"] = newData |
| 329 | delete(meta, "stub") |
| 330 | delete(meta, "follows") |
| 331 | } else { |
| 332 | // Update version in the case where this is a new attachment on the doc sharing a V2 digest with |
| 333 | // an existing attachment |
| 334 | meta["ver"] = AttVersion2 |
| 335 | } |
| 336 | } |
| 337 | } |
| 338 | return nil |
| 339 | } |
| 340 | |
| 341 | func GetAttachmentVersion(meta map[string]interface{}) (int, bool) { |
| 342 | ver, ok := meta["ver"] |