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"),
        }
    }
}