mongodb/sync/gridfs.rs
1//! Contains the functionality for GridFS operations.
2
3use std::io::{Read, Write};
4
5use futures_util::{AsyncReadExt, AsyncWriteExt};
6
7use crate::{
8 bson::Bson,
9 error::Result,
10 gridfs::{
11 GridFsBucket as AsyncGridFsBucket,
12 GridFsDownloadStream as AsyncGridFsDownloadStream,
13 GridFsUploadStream as AsyncGridFsUploadStream,
14 },
15 options::{ReadConcern, SelectionCriteria, WriteConcern},
16};
17
18pub use crate::gridfs::FilesCollectionDocument;
19
20/// A `GridFsBucket` provides the functionality for storing and retrieving binary BSON data that
21/// exceeds the 16 MiB size limit of a MongoDB document. Users may upload and download large amounts
22/// of data, called files, to the bucket. When a file is uploaded, its contents are divided into
23/// chunks and stored in a chunks collection. A corresponding [`FilesCollectionDocument`] is also
24/// stored in a files collection. When a user downloads a file, the bucket finds and returns the
25/// data stored in its chunks.
26///
27/// `GridFsBucket` uses [`std::sync::Arc`] internally, so it can be shared safely across threads or
28/// async tasks.
29pub struct GridFsBucket {
30 pub(crate) async_bucket: AsyncGridFsBucket,
31}
32
33impl GridFsBucket {
34 pub(crate) fn new(async_bucket: AsyncGridFsBucket) -> Self {
35 Self { async_bucket }
36 }
37
38 /// Gets the read concern of the `GridFsBucket`.
39 pub fn read_concern(&self) -> Option<&ReadConcern> {
40 self.async_bucket.read_concern()
41 }
42
43 /// Gets the write concern of the `GridFsBucket`.
44 pub fn write_concern(&self) -> Option<&WriteConcern> {
45 self.async_bucket.write_concern()
46 }
47
48 /// Gets the read preference of the `GridFsBucket`.
49 pub fn selection_criteria(&self) -> Option<&SelectionCriteria> {
50 self.async_bucket.selection_criteria()
51 }
52}
53
54/// A stream from which a file stored in a GridFS bucket can be downloaded.
55///
56/// # Downloading from the Stream
57/// The `GridFsDownloadStream` type implements [`std::io::Read`].
58///
59/// ```rust
60/// # use mongodb::{bson::Bson, error::Result, sync::gridfs::{GridFsBucket, GridFsDownloadStream}};
61/// # fn download_example(bucket: GridFsBucket, id: Bson) -> Result<()> {
62/// use std::io::Read;
63///
64/// let mut buf = Vec::new();
65/// let mut download_stream = bucket.open_download_stream(id).run()?;
66/// download_stream.read_to_end(&mut buf)?;
67/// # Ok(())
68/// # }
69/// ```
70///
71/// If the destination is a local file (or other `Write` byte sink), the contents of the stream
72/// can be efficiently written to it with [`std::io::copy`].
73pub struct GridFsDownloadStream {
74 async_stream: AsyncGridFsDownloadStream,
75}
76
77impl Read for GridFsDownloadStream {
78 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
79 crate::sync::TOKIO_RUNTIME.block_on(self.async_stream.read(buf))
80 }
81}
82
83impl GridFsDownloadStream {
84 pub(crate) fn new(async_stream: AsyncGridFsDownloadStream) -> Self {
85 Self { async_stream }
86 }
87}
88
89/// A stream to which bytes can be written to be uploaded to a GridFS bucket.
90///
91/// # Uploading to the Stream
92/// The `GridFsUploadStream` type implements [`std::io::Write`].
93///
94/// Bytes can be written to the stream using the write methods in the `Write` trait. When
95/// `close` is invoked on the stream, any remaining bytes in the buffer are written to the chunks
96/// collection and a corresponding [`FilesCollectionDocument`] is written to the files collection.
97/// It is an error to write to, abort, or close the stream after `close` has been called.
98///
99/// ```rust
100/// # use mongodb::{error::Result, sync::gridfs::{GridFsBucket, GridFsUploadStream}};
101/// # fn upload_example(bucket: GridFsBucket) -> Result<()> {
102/// use std::io::Write;
103///
104/// let bytes = vec![0u8; 100];
105/// let mut upload_stream = bucket.open_upload_stream("example_file").run()?;
106/// upload_stream.write_all(&bytes[..])?;
107/// upload_stream.close()?;
108/// # Ok(())
109/// # }
110/// ```
111///
112/// If the data is a local file (or other `Read` byte source), its contents can be efficiently
113/// written to the stream with [`std::io::copy`].
114///
115/// # Aborting the Stream
116/// A stream can be aborted by calling the `abort` method. This will remove any chunks associated
117/// with the stream from the chunks collection. It is an error to write to, abort, or close the
118/// stream after `abort` has been called.
119///
120/// ```rust
121/// # use mongodb::{error::Result, sync::gridfs::{GridFsBucket, GridFsUploadStream}};
122/// # fn abort_example(bucket: GridFsBucket) -> Result<()> {
123/// use std::io::Write;
124///
125/// let bytes = vec![0u8; 100];
126/// let mut upload_stream = bucket.open_upload_stream("example_file").run()?;
127/// upload_stream.write_all(&bytes[..])?;
128/// upload_stream.abort()?;
129/// # Ok(())
130/// # }
131/// ```
132///
133/// In the event of an error during any operation on the `GridFsUploadStream`, any chunks associated
134/// with the stream will be removed from the chunks collection. Any subsequent attempts to write to,
135/// abort, or close the stream will return an error.
136///
137/// If a `GridFsUploadStream` is dropped prior to `abort` or `close` being called, its [`Drop`]
138/// implementation will remove any chunks associated with the stream from the chunks collection.
139/// Users should prefer calling `abort` explicitly to relying on the `Drop` implementation in order
140/// to inspect the result of the delete operation.
141///
142/// # Flushing the Stream
143/// Because all chunks besides the final chunk of a file must be exactly `chunk_size_bytes`, calling
144/// [`flush`](std::io::Write::flush) is not guaranteed to flush all bytes to the chunks collection.
145/// Any remaining buffered bytes will be written to the chunks collection upon a call to `close`.
146pub struct GridFsUploadStream {
147 async_stream: AsyncGridFsUploadStream,
148}
149
150impl GridFsUploadStream {
151 pub(crate) fn new(async_stream: AsyncGridFsUploadStream) -> Self {
152 Self { async_stream }
153 }
154
155 /// Gets the stream's unique [`Bson`] identifier. This value will be the `id` field for the
156 /// [`FilesCollectionDocument`] uploaded to the files collection when the stream is closed.
157 pub fn id(&self) -> &Bson {
158 self.async_stream.id()
159 }
160
161 /// Closes the stream, writing any buffered bytes to the chunks collection and a corresponding
162 /// [`FilesCollectionDocument`] to the files collection. If an error occurs during either of
163 /// these steps, the chunks associated with this stream are deleted. It is an error to write to,
164 /// abort, or close the stream after this method has been called.
165 pub fn close(&mut self) -> std::io::Result<()> {
166 crate::sync::TOKIO_RUNTIME.block_on(self.async_stream.close())
167 }
168
169 /// Aborts the stream, discarding any chunks that have already been written to the chunks
170 /// collection. Once this method has been called, it is an error to attempt to write to, abort,
171 /// or close the stream.
172 pub fn abort(&mut self) -> Result<()> {
173 crate::sync::TOKIO_RUNTIME.block_on(self.async_stream.abort())
174 }
175}
176
177impl Write for GridFsUploadStream {
178 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
179 crate::sync::TOKIO_RUNTIME.block_on(self.async_stream.write(buf))
180 }
181
182 fn flush(&mut self) -> std::io::Result<()> {
183 crate::sync::TOKIO_RUNTIME.block_on(self.async_stream.flush())
184 }
185}