Skip to content

Commit

Permalink
Return attachment metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
flimzy committed Mar 4, 2024
1 parent 82d7a54 commit 5cc8215
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 17 deletions.
32 changes: 18 additions & 14 deletions x/sqlite/getattachment.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package sqlite

import (
"context"
"database/sql"
"errors"
"fmt"
"net/http"

Expand All @@ -10,21 +12,23 @@ import (
)

func (d *db) GetAttachment(ctx context.Context, docID string, filename string, _ driver.Options) (*driver.Attachment, error) {
var found bool

err := d.db.QueryRowContext(ctx, fmt.Sprintf(`
SELECT EXISTS (
SELECT 1
FROM %[1]q AS att
WHERE att.id = $1
AND att.filename = $2
)
`, d.name+"_attachments"), docID, filename).Scan(&found)
attachment, err := d.attachmentExists(ctx, docID, filename)
if errors.Is(err, sql.ErrNoRows) {
return nil, &internal.Error{Status: http.StatusNotFound, Message: "Not Found: missing"}
}
if err != nil {
return nil, err
}
if found {
return &driver.Attachment{}, nil
}
return nil, &internal.Error{Status: http.StatusNotFound, Message: "Not Found: missing"}

return attachment, nil
}

func (d *db) attachmentExists(ctx context.Context, docID string, filename string) (*driver.Attachment, error) {
var att driver.Attachment
err := d.db.QueryRowContext(ctx, fmt.Sprintf(`
SELECT filename, content_type, length, rev
FROM %s
WHERE id = $1 AND filename = $2
`, d.name+"_attachments"), docID, filename).Scan(&att.Filename, &att.ContentType, &att.Size, &att.RevPos)
return &att, err
}
62 changes: 59 additions & 3 deletions x/sqlite/getattachment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"net/http"
"testing"

"github.com/google/go-cmp/cmp"
"gitlab.com/flimzy/testy"

"github.com/go-kivik/kivik/v4"
Expand All @@ -14,12 +15,18 @@ import (

func TestDBGetAttachment(t *testing.T) {
t.Parallel()
type attachmentMetadata struct {
Filename string
ContentType string
Length int64
RevPos int64
}
type test struct {
setup func(t *testing.T, db driver.DB)
docID string
filename string

wantAttachment *driver.Attachment
wantAttachment *attachmentMetadata
wantStatus int
wantErr string
}
Expand All @@ -31,7 +38,7 @@ func TestDBGetAttachment(t *testing.T) {
wantStatus: http.StatusNotFound,
wantErr: "Not Found: missing",
})
tests.Add("when document exists and file exists we get the valid status", test{
tests.Add("when the attachment exists, return it", test{
setup: func(t *testing.T, db driver.DB) {
_, err := db.Put(context.Background(), "foo", map[string]interface{}{
"_id": "foo",
Expand All @@ -49,13 +56,49 @@ func TestDBGetAttachment(t *testing.T) {
docID: "foo",
filename: "foo.txt",
})
tests.Add("when an attachment is returned, it contains metadata...", test{
setup: func(t *testing.T, db driver.DB) {
_, err := db.Put(context.Background(), "foo", map[string]interface{}{
"_id": "foo",
"_attachments": map[string]interface{}{
"foo.txt": map[string]interface{}{
"content_type": "text/plain",
"data": "VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGluZw==",
},
},
}, mock.NilOption)
if err != nil {
t.Fatal(err)
}
},
docID: "foo",
filename: "foo.txt",
wantAttachment: &attachmentMetadata{
Filename: "foo.txt",
ContentType: "text/plain",
Length: 25,
RevPos: 1,
},
})
// GetAttachment returns the latest revision by default
//

/*
TODO:
- doc exists, and file exists, but doc is deleted
- return correct attachment in case of a conflict
- return existing file from existing doc
- request attachment from historical revision
- failure: request attachment from historical revision that does not exist
- GetAttachment returns 404 when the document does exist, but the attachment has never existed
- GetAttachment returns 404 when the document has never existed
- GetAttachment returns 404 when the document was deleted
- GetAttachment returns 404 when the latest revision was deleted
- GetAttachment returns 404 when the document does exist, but the attachment has been deleted
- GetAttachment returns the latest revision
*/

tests.Run(t, func(t *testing.T, tt test) {
Expand All @@ -68,12 +111,25 @@ func TestDBGetAttachment(t *testing.T) {
// if opts == nil {
opts := mock.NilOption
// }
_, err := db.GetAttachment(context.Background(), tt.docID, tt.filename, opts)
attachment, err := db.GetAttachment(context.Background(), tt.docID, tt.filename, opts)
if !testy.ErrorMatches(tt.wantErr, err) {
t.Errorf("Unexpected error: %s", err)
}
if status := kivik.HTTPStatus(err); status != tt.wantStatus {
t.Errorf("Unexpected status: %d", status)
}

if tt.wantAttachment == nil {
return
}
got := &attachmentMetadata{
Filename: attachment.Filename,
ContentType: attachment.ContentType,
Length: attachment.Size,
RevPos: attachment.RevPos,
}
if d := cmp.Diff(tt.wantAttachment, got); d != "" {
t.Errorf("Unexpected attachment metadata:\n%s", d)
}
})
}

0 comments on commit 5cc8215

Please sign in to comment.