use crate::bson::{doc, Bson};
use crate::{
action::{action_impl, deeplink, export_doc, option_setters, options_doc},
error::{ErrorKind, GridFsErrorKind, GridFsFileIdentifier, Result},
gridfs::{
FilesCollectionDocument,
GridFsBucket,
GridFsDownloadByNameOptions,
GridFsDownloadStream,
},
};
impl GridFsBucket {
#[deeplink]
pub fn open_download_stream(&self, id: Bson) -> OpenDownloadStream {
OpenDownloadStream { bucket: self, id }
}
#[deeplink]
#[options_doc(download_by_name)]
pub fn open_download_stream_by_name(
&self,
filename: impl Into<String>,
) -> OpenDownloadStreamByName {
OpenDownloadStreamByName {
bucket: self,
filename: filename.into(),
options: None,
}
}
async fn find_file_by_id(&self, id: &Bson) -> Result<FilesCollectionDocument> {
match self.find_one(doc! { "_id": id }).await? {
Some(file) => Ok(file),
None => Err(ErrorKind::GridFs(GridFsErrorKind::FileNotFound {
identifier: GridFsFileIdentifier::Id(id.clone()),
})
.into()),
}
}
async fn find_file_by_name(
&self,
filename: &str,
options: Option<GridFsDownloadByNameOptions>,
) -> Result<FilesCollectionDocument> {
let revision = options.and_then(|opts| opts.revision).unwrap_or(-1);
let (sort, skip) = if revision >= 0 {
(1, revision)
} else {
(-1, -revision - 1)
};
match self
.files()
.find_one(doc! { "filename": filename })
.sort(doc! { "uploadDate": sort })
.skip(skip as u64)
.await?
{
Some(fcd) => Ok(fcd),
None => {
if self
.files()
.find_one(doc! { "filename": filename })
.await?
.is_some()
{
Err(ErrorKind::GridFs(GridFsErrorKind::RevisionNotFound { revision }).into())
} else {
Err(ErrorKind::GridFs(GridFsErrorKind::FileNotFound {
identifier: GridFsFileIdentifier::Filename(filename.into()),
})
.into())
}
}
}
}
}
#[cfg(feature = "sync")]
impl crate::sync::gridfs::GridFsBucket {
#[deeplink]
pub fn open_download_stream(&self, id: Bson) -> OpenDownloadStream {
self.async_bucket.open_download_stream(id)
}
#[deeplink]
#[options_doc(download_by_name, sync)]
pub fn open_download_stream_by_name(
&self,
filename: impl Into<String>,
) -> OpenDownloadStreamByName {
self.async_bucket.open_download_stream_by_name(filename)
}
}
#[must_use]
pub struct OpenDownloadStream<'a> {
bucket: &'a GridFsBucket,
id: Bson,
}
#[action_impl(sync = crate::sync::gridfs::GridFsDownloadStream)]
impl<'a> Action for OpenDownloadStream<'a> {
type Future = OpenDownloadStreamFuture;
async fn execute(self) -> Result<GridFsDownloadStream> {
let file = self.bucket.find_file_by_id(&self.id).await?;
GridFsDownloadStream::new(file, self.bucket.chunks()).await
}
}
#[must_use]
pub struct OpenDownloadStreamByName<'a> {
bucket: &'a GridFsBucket,
filename: String,
options: Option<GridFsDownloadByNameOptions>,
}
#[option_setters(crate::gridfs::GridFsDownloadByNameOptions)]
#[export_doc(download_by_name)]
impl OpenDownloadStreamByName<'_> {}
#[action_impl(sync = crate::sync::gridfs::GridFsDownloadStream)]
impl<'a> Action for OpenDownloadStreamByName<'a> {
type Future = OpenDownloadStreamByNameFuture;
async fn execute(self) -> Result<GridFsDownloadStream> {
let file = self
.bucket
.find_file_by_name(&self.filename, self.options)
.await?;
GridFsDownloadStream::new(file, self.bucket.chunks()).await
}
}