Skip to content

Commit 74c2895

Browse files
RUST-1401 Additional GridFS API (#763)
1 parent c9c4e3f commit 74c2895

File tree

4 files changed

+98
-22
lines changed

4 files changed

+98
-22
lines changed

src/gridfs.rs

Lines changed: 58 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ use crate::{
1717
bson::{doc, oid::ObjectId, Bson, DateTime, Document, RawBinaryRef},
1818
concern::{ReadConcern, WriteConcern},
1919
cursor::Cursor,
20-
error::Result,
21-
options::SelectionCriteria,
20+
error::{ErrorKind, GridFsErrorKind, GridFsFileIdentifier, Result},
21+
options::{CollectionOptions, FindOptions, SelectionCriteria},
2222
Collection,
2323
Database,
2424
};
@@ -171,8 +171,19 @@ impl GridFsBucket {
171171
.as_deref()
172172
.unwrap_or(DEFAULT_BUCKET_NAME);
173173

174-
let files = db.collection::<FilesCollectionDocument>(&format!("{}.files", bucket_name));
175-
let chunks = db.collection::<Chunk>(&format!("{}.chunks", bucket_name));
174+
let collection_options = CollectionOptions::builder()
175+
.read_concern(options.read_concern.clone())
176+
.write_concern(options.write_concern.clone())
177+
.selection_criteria(options.selection_criteria.clone())
178+
.build();
179+
let files = db.collection_with_options::<FilesCollectionDocument>(
180+
&format!("{}.files", bucket_name),
181+
collection_options.clone(),
182+
);
183+
let chunks = db.collection_with_options::<Chunk>(
184+
&format!("{}.chunks", bucket_name),
185+
collection_options,
186+
);
176187

177188
GridFsBucket {
178189
inner: Arc::new(GridFsBucketInner {
@@ -318,28 +329,58 @@ impl GridFsBucket {
318329
todo!()
319330
}
320331

321-
/// Given an `id`, deletes the stored file's files collection document and
322-
/// associated chunks from a [`GridFsBucket`].
323-
pub async fn delete(&self, id: Bson) {
324-
todo!()
332+
/// Deletes the [`FilesCollectionDocument`] with the given `id `and its associated chunks from
333+
/// this bucket.
334+
pub async fn delete(&self, id: Bson) -> Result<()> {
335+
let delete_result = self
336+
.files()
337+
.delete_one(doc! { "_id": id.clone() }, None)
338+
.await?;
339+
// Delete chunks regardless of whether a file was found. This will remove any possibly
340+
// orphaned chunks.
341+
self.chunks()
342+
.delete_many(doc! { "files_id": id.clone() }, None)
343+
.await?;
344+
345+
if delete_result.deleted_count == 0 {
346+
return Err(ErrorKind::GridFs(GridFsErrorKind::FileNotFound {
347+
identifier: GridFsFileIdentifier::Id(id),
348+
})
349+
.into());
350+
}
351+
352+
Ok(())
325353
}
326354

327-
/// Finds and returns the files collection documents that match the filter.
355+
/// Finds and returns the [`FilesCollectionDocument`]s within this bucket that match the given
356+
/// filter.
328357
pub async fn find(
329358
&self,
330359
filter: Document,
331-
options: impl Into<Option<GridFsBucketOptions>>,
360+
options: impl Into<Option<GridFsFindOptions>>,
332361
) -> Result<Cursor<FilesCollectionDocument>> {
333-
todo!()
362+
let find_options = options.into().map(FindOptions::from);
363+
self.files().find(filter, find_options).await
334364
}
335365

336-
/// Renames the stored file with the specified `id`.
337-
pub async fn rename(&self, id: Bson, new_filename: String) {
338-
todo!()
366+
/// Renames the file with the given 'id' to the provided `new_filename`.
367+
pub async fn rename(&self, id: Bson, new_filename: impl AsRef<str>) -> Result<()> {
368+
self.files()
369+
.update_one(
370+
doc! { "_id": id },
371+
doc! { "$set": { "filename": new_filename.as_ref() } },
372+
None,
373+
)
374+
.await?;
375+
376+
Ok(())
339377
}
340378

341-
/// Drops the files associated with this bucket.
342-
pub async fn drop(&self) {
343-
todo!()
379+
/// Drops all of the files and their associated chunks in this bucket.
380+
pub async fn drop(&self) -> Result<()> {
381+
self.files().drop(None).await?;
382+
self.chunks().drop(None).await?;
383+
384+
Ok(())
344385
}
345386
}

src/gridfs/options.rs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
use std::time::Duration;
22

3+
use serde::Deserialize;
4+
use typed_builder::TypedBuilder;
5+
36
use crate::{
47
bson::Document,
5-
concern::{ReadConcern, WriteConcern},
6-
selection_criteria::SelectionCriteria,
8+
options::{FindOptions, ReadConcern, SelectionCriteria, WriteConcern},
79
};
8-
use serde::Deserialize;
9-
use typed_builder::TypedBuilder;
1010

1111
/// Contains the options for creating a [`GridFsBucket`].
1212
#[derive(Clone, Debug, Default, Deserialize, TypedBuilder)]
@@ -88,3 +88,17 @@ pub struct GridFsFindOptions {
8888
/// The order by which to sort results. Defaults to not sorting.
8989
pub sort: Option<Document>,
9090
}
91+
92+
impl From<GridFsFindOptions> for FindOptions {
93+
fn from(options: GridFsFindOptions) -> Self {
94+
Self {
95+
allow_disk_use: options.allow_disk_use,
96+
batch_size: options.batch_size,
97+
limit: options.limit,
98+
max_time: options.max_time,
99+
skip: options.skip,
100+
sort: options.sort,
101+
..Default::default()
102+
}
103+
}
104+
}

src/test/spec/unified_runner/operation.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ impl<'de> Deserialize<'de> for Operation {
341341
"createEntities" => deserialize_op::<CreateEntities>(definition.arguments),
342342
"download" => deserialize_op::<Download>(definition.arguments),
343343
"downloadByName" => deserialize_op::<DownloadByName>(definition.arguments),
344+
"delete" => deserialize_op::<Delete>(definition.arguments),
344345
_ => Ok(Box::new(UnimplementedOperation) as Box<dyn TestOperation>),
345346
}
346347
.map_err(|e| serde::de::Error::custom(format!("{}", e)))?;
@@ -2699,6 +2700,27 @@ impl TestOperation for DownloadByName {
26992700
}
27002701
}
27012702

2703+
#[derive(Debug, Deserialize)]
2704+
#[serde(rename_all = "camelCase", deny_unknown_fields)]
2705+
pub(super) struct Delete {
2706+
id: Bson,
2707+
}
2708+
2709+
impl TestOperation for Delete {
2710+
fn execute_entity_operation<'a>(
2711+
&'a self,
2712+
id: &'a str,
2713+
test_runner: &'a TestRunner,
2714+
) -> BoxFuture<'a, Result<Option<Entity>>> {
2715+
async move {
2716+
let bucket = test_runner.get_bucket(id).await;
2717+
bucket.delete(self.id.clone()).await?;
2718+
Ok(None)
2719+
}
2720+
.boxed()
2721+
}
2722+
}
2723+
27022724
#[derive(Debug, Deserialize)]
27032725
pub(super) struct UnimplementedOperation;
27042726

src/test/spec/unified_runner/test_runner.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ use super::{
5757
const SKIPPED_OPERATIONS: &[&str] = &[
5858
"bulkWrite",
5959
"count",
60-
"delete",
6160
"listCollectionObjects",
6261
"listDatabaseObjects",
6362
"mapReduce",

0 commit comments

Comments
 (0)