Skip to content

GODRIVER-3565 Add UnmarshalBSON to GridFSFile #2077

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jun 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions mongo/gridfs_download_stream.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ type GridFSFile struct {
Metadata bson.Raw
}

var _ bson.Unmarshaler = &GridFSFile{}

// findFileResponse is a temporary type used to unmarshal documents from the
// files collection and can be transformed into a File instance. This type
// exists to avoid adding BSON struct tags to the exported File type.
Expand All @@ -96,6 +98,23 @@ func newFileFromResponse(resp findFileResponse) *GridFSFile {
}
}

// UnmarshalBSON implements the bson.Unmarshaler interface.
func (f *GridFSFile) UnmarshalBSON(data []byte) error {
var temp findFileResponse
if err := bson.Unmarshal(data, &temp); err != nil {
return err
}

f.ID = temp.ID
f.Length = temp.Length
f.ChunkSize = temp.ChunkSize
f.UploadDate = temp.UploadDate
f.Name = temp.Name
f.Metadata = temp.Metadata

return nil
}

func newGridFSDownloadStream(
ctx context.Context,
cancel context.CancelFunc,
Expand Down
69 changes: 69 additions & 0 deletions mongo/gridfs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"context"
"testing"

"go.mongodb.org/mongo-driver/v2/bson"
"go.mongodb.org/mongo-driver/v2/event"
"go.mongodb.org/mongo-driver/v2/internal/assert"
"go.mongodb.org/mongo-driver/v2/internal/integtest"
Expand Down Expand Up @@ -109,3 +110,71 @@ func TestGridFS(t *testing.T) {
}
})
}

func TestGridFSFile_UnmarshalBSON(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test in short mode")
}

cs := integtest.ConnString(t)

clientOpts := options.Client().
ApplyURI(cs.Original).
SetReadPreference(readpref.Primary()).
SetWriteConcern(writeconcern.Majority()).
// Connect to a single host. For sharded clusters, this will pin to a single mongos, which avoids
// non-deterministic versioning errors in the server. This has no effect for replica sets because the driver
// will discover the other hosts during SDAM checks.
SetHosts(cs.Hosts[:1])

integtest.AddTestServerAPIVersion(clientOpts)

client, err := Connect(clientOpts)
require.NoError(t, err)

defer func() {
err := client.Disconnect(context.Background())
require.NoError(t, err)
}()

// Get the database and create a GridFS bucket
db := client.Database("gridfs_test_db")

// Drop the collection
err = db.Collection("myfiles.files").Drop(context.Background())
require.NoError(t, err)

err = db.Collection("myfiles.chunks").Drop(context.Background())
require.NoError(t, err)

bucket := db.GridFSBucket(options.GridFSBucket().SetName("myfiles"))

// Data to upload
fileName := "example-file.txt"
fileContent := []byte("Hello GridFS! This is a test file.")

// Upload data into GridFS
uploadStream, err := bucket.OpenUploadStream(context.Background(), fileName)
require.NoError(t, err)

_, err = uploadStream.Write(fileContent)
require.NoError(t, err)

uploadStream.Close()

// Verify the file metadata
fileCursor, err := bucket.Find(context.Background(), bson.D{})
require.NoError(t, err)

for fileCursor.Next(context.Background()) {
var file GridFSFile
err := fileCursor.Decode(&file)
require.NoError(t, err)

assert.NotNil(t, file.ID)
assert.Equal(t, int64(34), file.Length)
assert.Equal(t, int32(261120), file.ChunkSize)
assert.NotNil(t, file.UploadDate)
assert.Equal(t, fileName, file.Name)
}
}
Loading