From 7f0d356690ea940aed18d706a0d8249ec4fd031c Mon Sep 17 00:00:00 2001 From: Kyle Kloberdanz Date: Thu, 25 Jan 2024 14:04:57 -0600 Subject: [PATCH] RUST-1652 Add a find_one method to GridFsBucket (#1015) Co-authored-by: Isabel Atkinson --- src/gridfs.rs | 20 ++++++++++++++++- src/gridfs/download.rs | 2 +- src/gridfs/options.rs | 30 ++++++++++++++++++++++++- src/test/spec/gridfs.rs | 50 ++++++++++++++++++++++++++++++++++++++--- 4 files changed, 96 insertions(+), 6 deletions(-) diff --git a/src/gridfs.rs b/src/gridfs.rs index 29c757581..263f0f70c 100644 --- a/src/gridfs.rs +++ b/src/gridfs.rs @@ -13,7 +13,14 @@ use crate::{ bson::{doc, oid::ObjectId, Bson, DateTime, Document, RawBinaryRef}, cursor::Cursor, error::{Error, ErrorKind, GridFsErrorKind, GridFsFileIdentifier, Result}, - options::{CollectionOptions, FindOptions, ReadConcern, SelectionCriteria, WriteConcern}, + options::{ + CollectionOptions, + FindOneOptions, + FindOptions, + ReadConcern, + SelectionCriteria, + WriteConcern, + }, Collection, Database, }; @@ -232,6 +239,17 @@ impl GridFsBucket { self.files().find(filter, find_options).await } + /// Finds and returns a single [`FilesCollectionDocument`] within this bucket that matches the + /// given filter. + pub async fn find_one( + &self, + filter: Document, + options: impl Into>, + ) -> Result> { + let find_options = options.into().map(FindOneOptions::from); + self.files().find_one(filter, find_options).await + } + /// Renames the file with the given 'id' to the provided `new_filename`. This method returns an /// error if the `id` does not match any files in the bucket. pub async fn rename(&self, id: Bson, new_filename: impl AsRef) -> Result<()> { diff --git a/src/gridfs/download.rs b/src/gridfs/download.rs index c996394c0..ef23228f6 100644 --- a/src/gridfs/download.rs +++ b/src/gridfs/download.rs @@ -22,7 +22,7 @@ use crate::{ // Utility functions for finding files within the bucket. impl GridFsBucket { async fn find_file_by_id(&self, id: &Bson) -> Result { - match self.files().find_one(doc! { "_id": id }, None).await? { + match self.find_one(doc! { "_id": id }, None).await? { Some(file) => Ok(file), None => Err(ErrorKind::GridFs(GridFsErrorKind::FileNotFound { identifier: GridFsFileIdentifier::Id(id.clone()), diff --git a/src/gridfs/options.rs b/src/gridfs/options.rs index 594eb89f5..96ed2d1cc 100644 --- a/src/gridfs/options.rs +++ b/src/gridfs/options.rs @@ -5,7 +5,7 @@ use typed_builder::TypedBuilder; use crate::{ bson::Document, - options::{FindOptions, ReadConcern, SelectionCriteria, WriteConcern}, + options::{FindOneOptions, FindOptions, ReadConcern, SelectionCriteria, WriteConcern}, }; /// Contains the options for creating a [`GridFsBucket`](crate::gridfs::GridFsBucket). @@ -103,3 +103,31 @@ impl From for FindOptions { } } } + +/// Contains the options for finding a single +/// [`FilesCollectionDocument`](crate::gridfs::FilesCollectionDocument) in a +/// [`GridFsBucket`](crate::gridfs::GridFsBucket). +#[derive(Clone, Debug, Default, Deserialize, TypedBuilder)] +#[builder(field_defaults(default, setter(into)))] +#[non_exhaustive] +pub struct GridFsFindOneOptions { + /// The maximum amount of time to allow the query to run. + pub max_time: Option, + + /// The number of documents to skip before returning. + pub skip: Option, + + /// The order by which to sort results. Defaults to not sorting. + pub sort: Option, +} + +impl From for FindOneOptions { + fn from(options: GridFsFindOneOptions) -> Self { + Self { + max_time: options.max_time, + skip: options.skip, + sort: options.sort, + ..Default::default() + } + } +} diff --git a/src/test/spec/gridfs.rs b/src/test/spec/gridfs.rs index 0f393c602..bf2be6cae 100644 --- a/src/test/spec/gridfs.rs +++ b/src/test/spec/gridfs.rs @@ -5,8 +5,8 @@ use futures_util::io::{AsyncReadExt, AsyncWriteExt}; use crate::{ bson::{doc, Bson, Document}, error::{Error, ErrorKind, GridFsErrorKind}, - gridfs::{GridFsBucket, GridFsUploadStream}, - options::{GridFsBucketOptions, GridFsUploadOptions}, + gridfs::{GridFsBucket, GridFsFindOneOptions, GridFsUploadStream}, + options::{FindOneOptions, GridFsBucketOptions, GridFsUploadOptions}, runtime, test::{ get_client_options, @@ -120,7 +120,6 @@ async fn upload_test(bucket: &GridFsBucket, data: &[u8], options: Option