Skip to content

Commit 3dcf919

Browse files
authored
RUST-1392 Add GridFS support: Implement public API with placeholder code (#688)
Create the public API for GridFS in the driver
1 parent 342c35f commit 3dcf919

File tree

4 files changed

+457
-8
lines changed

4 files changed

+457
-8
lines changed

src/db/mod.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ use crate::{
1919
concern::{ReadConcern, WriteConcern},
2020
cursor::Cursor,
2121
error::{Error, ErrorKind, Result},
22+
gridfs::{
23+
options::GridFsBucketOptions,
24+
GridFsBucket,
25+
DEFAULT_BUCKET_NAME,
26+
DEFAULT_CHUNK_SIZE_BYTES,
27+
},
2228
operation::{Aggregate, AggregateTarget, Create, DropDatabase, ListCollections, RunCommand},
2329
options::{
2430
AggregateOptions,
@@ -564,4 +570,26 @@ impl Database {
564570
.execute_watch_with_session(pipeline, options, target, None, session)
565571
.await
566572
}
573+
574+
/// Creates a new GridFsBucket in the database with the given options.
575+
pub fn gridfs_bucket(&self, options: impl Into<Option<GridFsBucketOptions>>) -> GridFsBucket {
576+
let mut options = options.into().unwrap_or_default();
577+
options.read_concern = options
578+
.read_concern
579+
.or_else(|| self.read_concern().cloned());
580+
options.write_concern = options
581+
.write_concern
582+
.or_else(|| self.write_concern().cloned());
583+
options.selection_criteria = options
584+
.selection_criteria
585+
.or_else(|| self.selection_criteria().cloned());
586+
options.bucket_name = options
587+
.bucket_name
588+
.or_else(|| Some(DEFAULT_BUCKET_NAME.to_string()));
589+
options.chunk_size_bytes = options.chunk_size_bytes.or(Some(DEFAULT_CHUNK_SIZE_BYTES));
590+
GridFsBucket {
591+
db: self.clone(),
592+
options,
593+
}
594+
}
567595
}

src/gridfs.rs

Lines changed: 331 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,331 @@
1+
pub mod options;
2+
3+
use core::task::{Context, Poll};
4+
use std::pin::Pin;
5+
6+
use crate::{
7+
concern::{ReadConcern, WriteConcern},
8+
cursor::Cursor,
9+
error::Result,
10+
selection_criteria::SelectionCriteria,
11+
Database,
12+
};
13+
use bson::{oid::ObjectId, Bson, DateTime, Document};
14+
use options::*;
15+
use serde::{Deserialize, Serialize};
16+
use tokio::io::ReadBuf;
17+
18+
pub const DEFAULT_BUCKET_NAME: &str = "fs";
19+
pub const DEFAULT_CHUNK_SIZE_BYTES: u32 = 255 * 1024;
20+
21+
// Contained in a "chunks" collection for each user file
22+
struct Chunk {
23+
id: ObjectId,
24+
files_id: Bson,
25+
n: u32,
26+
// default size is 255 KiB
27+
data: Vec<u8>,
28+
}
29+
30+
/// A collection in which information about stored files is stored. There will be one files
31+
/// collection document per stored file.
32+
#[derive(Serialize, Deserialize)]
33+
pub struct FilesCollectionDocument {
34+
id: Bson,
35+
length: i64,
36+
chunk_size: u32,
37+
upload_date: DateTime,
38+
filename: String,
39+
metadata: Document,
40+
}
41+
42+
/// Struct for storing GridFS managed files within a [`Database`].
43+
pub struct GridFsBucket {
44+
// Contains a "chunks" collection
45+
pub(crate) db: Database,
46+
pub(crate) options: GridFsBucketOptions,
47+
}
48+
49+
// TODO: RUST-1395 Add documentation and example code for this struct.
50+
pub struct GridFsUploadStream {
51+
files_id: Bson,
52+
}
53+
54+
impl GridFsUploadStream {
55+
/// Gets the file `id` for the stream.
56+
pub fn files_id(&self) -> &Bson {
57+
&self.files_id
58+
}
59+
60+
/// Consumes the stream and uploads data in the stream to the server.
61+
pub async fn finish(self) {
62+
todo!()
63+
}
64+
65+
/// Aborts the upload and discards the upload stream.
66+
pub async fn abort(self) {
67+
todo!()
68+
}
69+
}
70+
71+
impl tokio::io::AsyncWrite for GridFsUploadStream {
72+
fn poll_write(
73+
self: Pin<&mut Self>,
74+
cx: &mut Context<'_>,
75+
buf: &[u8],
76+
) -> Poll<tokio::io::Result<usize>> {
77+
todo!()
78+
}
79+
80+
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<tokio::io::Result<()>> {
81+
todo!()
82+
}
83+
84+
fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<tokio::io::Result<()>> {
85+
todo!()
86+
}
87+
}
88+
89+
impl futures_util::AsyncWrite for GridFsUploadStream {
90+
fn poll_write(
91+
self: Pin<&mut Self>,
92+
cx: &mut Context<'_>,
93+
buf: &[u8],
94+
) -> Poll<core::result::Result<usize, futures_util::io::Error>> {
95+
todo!()
96+
}
97+
98+
fn poll_flush(
99+
self: Pin<&mut Self>,
100+
cx: &mut Context<'_>,
101+
) -> Poll<core::result::Result<(), futures_util::io::Error>> {
102+
todo!()
103+
}
104+
105+
fn poll_close(
106+
self: Pin<&mut Self>,
107+
cx: &mut Context<'_>,
108+
) -> Poll<core::result::Result<(), futures_util::io::Error>> {
109+
todo!()
110+
}
111+
}
112+
113+
pub struct GridFsDownloadStream {
114+
files_id: Bson,
115+
}
116+
117+
impl GridFsDownloadStream {
118+
/// Gets the file `id` for the stream.
119+
pub fn files_id(&self) -> &Bson {
120+
&self.files_id
121+
}
122+
}
123+
124+
impl tokio::io::AsyncRead for GridFsDownloadStream {
125+
fn poll_read(
126+
self: Pin<&mut Self>,
127+
cx: &mut Context<'_>,
128+
buf: &mut ReadBuf<'_>,
129+
) -> Poll<tokio::io::Result<()>> {
130+
todo!()
131+
}
132+
}
133+
134+
impl futures_util::io::AsyncRead for GridFsDownloadStream {
135+
fn poll_read(
136+
self: Pin<&mut Self>,
137+
cx: &mut Context<'_>,
138+
buf: &mut [u8],
139+
) -> Poll<core::result::Result<usize, futures_util::io::Error>> {
140+
todo!()
141+
}
142+
}
143+
144+
impl GridFsBucket {
145+
/// Gets the read concern of the [`GridFsBucket`].
146+
pub fn read_concern(&self) -> Option<&ReadConcern> {
147+
self.options.read_concern.as_ref()
148+
}
149+
150+
/// Gets the write concern of the [`GridFsBucket`].
151+
pub fn write_concern(&self) -> Option<&WriteConcern> {
152+
self.options.write_concern.as_ref()
153+
}
154+
155+
/// Gets the selection criteria of the [`GridFsBucket`].
156+
pub fn selection_criteria(&self) -> Option<&SelectionCriteria> {
157+
self.options.selection_criteria.as_ref()
158+
}
159+
160+
/// Opens a [`GridFsUploadStream`] that the application can write the contents of the file to.
161+
/// The application provides a custom file id.
162+
///
163+
/// Returns a [`GridFsUploadStream`] to which the application will write the contents.
164+
pub async fn open_upload_stream_with_id(
165+
&self,
166+
id: Bson,
167+
filename: String,
168+
options: impl Into<Option<GridFsUploadOptions>>,
169+
) -> Result<GridFsUploadStream> {
170+
todo!()
171+
}
172+
173+
/// Opens a [`GridFsUploadStream`] that the application can write the contents of the file to.
174+
/// The driver generates a unique [`Bson::ObjectId`] for the file id.
175+
///
176+
/// Returns a [`GridFsUploadStream`] to which the application will write the contents.
177+
pub async fn open_upload_stream(
178+
&self,
179+
filename: String,
180+
options: impl Into<Option<GridFsUploadOptions>>,
181+
) -> Result<GridFsUploadStream> {
182+
self.open_upload_stream_with_id(Bson::ObjectId(ObjectId::new()), filename, options)
183+
.await
184+
}
185+
186+
/// Uploads a user file to a GridFS bucket. The application supplies a custom file id. Uses the
187+
/// `tokio` crate's `AsyncRead` trait for the `source`.
188+
pub async fn upload_from_tokio_reader_with_id(
189+
&self,
190+
id: Bson,
191+
filename: String,
192+
source: impl tokio::io::AsyncRead,
193+
options: impl Into<Option<GridFsUploadOptions>>,
194+
) {
195+
todo!()
196+
}
197+
198+
/// Uploads a user file to a GridFS bucket. The application supplies a custom file id. Uses the
199+
/// `futures-0.3` crate's `AsyncRead` trait for the `source`.
200+
pub async fn upload_from_futures_0_3_reader_with_id(
201+
&self,
202+
id: Bson,
203+
filename: String,
204+
source: impl futures_util::AsyncRead,
205+
options: impl Into<Option<GridFsUploadOptions>>,
206+
) {
207+
todo!()
208+
}
209+
210+
/// Uploads a user file to a GridFS bucket. The driver generates a unique [`Bson::ObjectId`] for
211+
/// the file id. Uses the `tokio` crate's `AsyncRead` trait for the `source`.
212+
pub async fn upload_from_tokio_reader(
213+
&self,
214+
filename: String,
215+
source: impl tokio::io::AsyncRead,
216+
options: impl Into<Option<GridFsUploadOptions>>,
217+
) {
218+
self.upload_from_tokio_reader_with_id(
219+
Bson::ObjectId(ObjectId::new()),
220+
filename,
221+
source,
222+
options,
223+
)
224+
.await
225+
}
226+
227+
/// Uploads a user file to a GridFS bucket. The driver generates a unique [`Bson::ObjectId`] for
228+
/// the file id. Uses the `futures-0.3` crate's `AsyncRead` trait for the `source`.
229+
pub async fn upload_from_futures_0_3_reader(
230+
&self,
231+
filename: String,
232+
source: impl futures_util::AsyncRead,
233+
options: impl Into<Option<GridFsUploadOptions>>,
234+
) {
235+
self.upload_from_futures_0_3_reader_with_id(
236+
Bson::ObjectId(ObjectId::new()),
237+
filename,
238+
source,
239+
options,
240+
)
241+
.await
242+
}
243+
244+
/// Opens and returns a [`GridFsDownloadStream`] from which the application can read
245+
/// the contents of the stored file specified by `id`.
246+
pub async fn open_download_stream(&self, id: Bson) -> Result<GridFsDownloadStream> {
247+
todo!()
248+
}
249+
250+
/// Opens and returns a [`GridFsDownloadStream`] from which the application can read
251+
/// the contents of the stored file specified by `filename` and the revision
252+
/// in `options`.
253+
pub async fn open_download_stream_by_name(
254+
&self,
255+
filename: String,
256+
options: impl Into<Option<GridFsDownloadByNameOptions>>,
257+
) -> Result<GridFsDownloadStream> {
258+
todo!()
259+
}
260+
261+
/// Downloads the contents of the stored file specified by `id` and writes
262+
/// the contents to the `destination`. Uses the `tokio` crate's `AsyncWrite`
263+
/// trait for the `destination`.
264+
pub async fn download_to_tokio_writer(
265+
&self,
266+
id: Bson,
267+
destination: impl tokio::io::AsyncWrite,
268+
) {
269+
todo!()
270+
}
271+
272+
/// Downloads the contents of the stored file specified by `id` and writes
273+
/// the contents to the `destination`. Uses the `futures-0.3` crate's `AsyncWrite`
274+
/// trait for the `destination`.
275+
pub async fn download_to_futures_0_3_writer(
276+
&self,
277+
id: Bson,
278+
destination: impl futures_util::AsyncWrite,
279+
) {
280+
todo!()
281+
}
282+
283+
/// Downloads the contents of the stored file specified by `filename` and by
284+
/// the revision in `options` and writes the contents to the `destination`. Uses the
285+
/// `tokio` crate's `AsyncWrite` trait for the `destination`.
286+
pub async fn download_to_tokio_writer_by_name(
287+
&self,
288+
filename: String,
289+
destination: impl tokio::io::AsyncWrite,
290+
options: impl Into<Option<GridFsDownloadByNameOptions>>,
291+
) {
292+
todo!()
293+
}
294+
295+
/// Downloads the contents of the stored file specified by `filename` and by
296+
/// the revision in `options` and writes the contents to the `destination`. Uses the
297+
/// `futures-0.3` crate's `AsyncWrite` trait for the `destination`.
298+
pub async fn download_to_futures_0_3_writer_by_name(
299+
&self,
300+
filename: String,
301+
destination: impl futures_util::AsyncWrite,
302+
options: impl Into<Option<GridFsDownloadByNameOptions>>,
303+
) {
304+
todo!()
305+
}
306+
307+
/// Given an `id`, deletes the stored file's files collection document and
308+
/// associated chunks from a [`GridFsBucket`].
309+
pub async fn delete(&self, id: Bson) {
310+
todo!()
311+
}
312+
313+
/// Finds and returns the files collection documents that match the filter.
314+
pub async fn find(
315+
&self,
316+
filter: Document,
317+
options: impl Into<Option<GridFsBucketOptions>>,
318+
) -> Result<Cursor<FilesCollectionDocument>> {
319+
todo!()
320+
}
321+
322+
/// Renames the stored file with the specified `id`.
323+
pub async fn rename(&self, id: Bson, new_filename: String) {
324+
todo!()
325+
}
326+
327+
/// Drops the files associated with this bucket.
328+
pub async fn drop(&self) {
329+
todo!()
330+
}
331+
}

0 commit comments

Comments
 (0)