1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
//! This crate provides an implementation of Mongo GridFS on the top of mongodb's crate. //! This implementation only use the _async/await_ version of mongodb. //! //! From https://github.com/mongodb/specifications/blob/master/source/gridfs/gridfs-spec.rst //! > GridFS is a convention drivers use to store and retrieve BSON binary data (type “\x05”) that exceeds MongoDB’s BSON-document size limit of 16 MiB. When this data, called a user file, is written to the system, GridFS divides the file into chunks that are stored as distinct documents in a chunks collection. To retrieve a stored file, GridFS locates and returns all of its component chunks. Internally, GridFS creates a files collection document for each stored file. Files collection documents hold information about stored files, and they are stored in a files collection. //! # Examples //! Uploading a document: //! ```rust //! # use mongodb::Client; //! # use mongodb::{error::Error, Database}; //! use mongodb_gridfs::{options::GridFSBucketOptions, GridFSBucket}; //! # use uuid::Uuid; //! //! # fn db_name_new() -> String { //! # "test_".to_owned() //! # + Uuid::new_v4() //! # .to_hyphenated() //! # .encode_lower(&mut Uuid::encode_buffer()) //! # } //! # //! # #[tokio::main] //! # async fn main() -> Result<(), Error> { //! # let client = Client::with_uri_str(&std::env::var("MONGO_URI").unwrap_or("mongodb://localhost:27017/".to_string())).await?; //! # let dbname = db_name_new(); //! # let db: Database = client.database(&dbname); //! let bucket = GridFSBucket::new(db.clone(), Some(GridFSBucketOptions::default())); //! let id = bucket //! .upload_from_stream("test.txt", "stream your data here".as_bytes(), None) //! .await?; //! # println!("{}", id); //! # db.drop(None).await //! # } //! ``` //! Downloading a document: //! ```rust //! use futures::stream::StreamExt; //! # use mongodb::Client; //! # use mongodb::Database; //! use mongodb_gridfs::{options::GridFSBucketOptions, GridFSBucket, GridFSError}; //! # use uuid::Uuid; //! //! # fn db_name_new() -> String { //! # "test_".to_owned() //! # + Uuid::new_v4() //! # .to_hyphenated() //! # .encode_lower(&mut Uuid::encode_buffer()) //! # } //! # //! # #[tokio::main] //! # async fn main() -> Result<(), GridFSError> { //! # let client = Client::with_uri_str( //! # &std::env::var("MONGO_URI").unwrap_or("mongodb://localhost:27017/".to_string()), //! # ) //! # .await?; //! # let dbname = db_name_new(); //! # let db: Database = client.database(&dbname); //! let bucket = GridFSBucket::new(db.clone(), Some(GridFSBucketOptions::default())); //! # let id = bucket //! # .clone() //! # .upload_from_stream("test.txt", "test data".as_bytes(), None) //! # .await?; //! # println!("{}", id); //! # //! let mut cursor = bucket.open_download_stream(id).await?; //! let buffer = cursor.next().await.unwrap(); //! # println!("{:?}", buffer); //! # //! # db.drop(None).await?; //! # Ok(()) //! # } //! ``` //! # Features //! The following features are propagated to mongodb: //! - default //! - async-std-runtime //! - tokio-runtime //! # Code Status //! | Feature | Status | Notes | //! | ------------------------------------------- | ------- | ----------------------------------------------- | //! | GridFSUploadOptions | DONE | `contentType` and `aliases` are not implemented | //! | GridFSBucketOption | DONE | concerns not used when ensuring indexes | //! | GridFSFindOptions | DONE | | //! | GridFSDownloadByNameOptions | TODO | | //! | GridFSBucket | DONE | | //! | GridFSBucket . open_upload_stream | DONE | | //! | GridFSBucket . open_upload_stream_with_id | | | //! | GridFSBucket . upload_from_stream | NO | No Implementation planned | //! | GridFSBucket . upload_from_stream_with_id | NO | No Implementation planned | //! | GridFSBucket . open_download_stream | DONE | | //! | GridFSBucket . download_to_stream | NO | No Implementation planned | //! | GridFSBucket . delete | DONE | | //! | GridFSBucket . find | DONE | | //! | GridFSBucket . rename | DONE | | //! | GridFSBucket . drop | DONE | | //! | GridFSBucket . open_download_stream_by_name | | | //! | GridFSBucket . download_to_stream_by_name | | | //! | indexes | DONE | | pub mod bucket; pub mod options; use std::{ error::Error, fmt::{Display, Formatter, Result}, }; pub use bucket::GridFSBucket; #[derive(Debug)] pub enum GridFSError { MongoError(mongodb::error::Error), FileNotFound(), } impl From<mongodb::error::Error> for GridFSError { fn from(err: mongodb::error::Error) -> GridFSError { GridFSError::MongoError(err) } } impl Error for GridFSError { fn source(&self) -> Option<&(dyn Error + 'static)> { match self { GridFSError::MongoError(e) => Some(e), GridFSError::FileNotFound() => None, } } // fn backtrace(&self) -> Option<&std::backtrace::Backtrace> { // None // } fn description(&self) -> &str { "description() is deprecated; use Display" } fn cause(&self) -> Option<&dyn Error> { self.source() } } impl Display for GridFSError { fn fmt(&self, f: &mut Formatter<'_>) -> Result { match self { GridFSError::MongoError(me) => write!(f, "{}", me), GridFSError::FileNotFound() => write!(f, "File not found"), } } }