1use futures::stream::StreamExt;
2use log::trace;
3use mongodb::bson;
4use mongodb::bson::oid::ObjectId;
5use mongodb::bson::{doc, Bson::Document as BsonDocument, Document};
6use mongodb::error::Error;
7use mongodb::options::FindOptions;
8use mongodb::Database;
9use serde::{Deserialize, Serialize};
10
11use mongodb::{
12 options::{
13 DeleteOptions, FindOneAndReplaceOptions, FindOneAndUpdateOptions, ReplaceOptions,
14 UpdateModifications, UpdateOptions,
15 },
16 results::{DeleteResult, InsertOneResult, UpdateResult},
17};
18use std::fmt::Debug;
19
20pub async fn find_one<T>(
21 filter_document: Document,
22 collection_name: &str,
23 db: &Database,
24) -> Result<Option<T>, Error>
25where
26 for<'a> T: Serialize + Deserialize<'a>,
27{
28 trace!("find_one");
29 let coll = db.collection(collection_name);
30 let result = coll.find_one(filter_document, None).await?;
31 if let Some(document) = result {
32 let t = bson::from_bson::<T>(BsonDocument(document))?;
33 return Ok(Some(t));
34 } else {
35 return Ok(None);
36 }
37}
38
39pub async fn find_by_id<T>(
40 id: &ObjectId,
41 collection_name: &str,
42 db: &Database,
43) -> Result<Option<T>, Error>
44where
45 for<'a> T: Serialize + Deserialize<'a>,
46{
47 trace!("find_by_id");
48 let filter_document = doc! {"_id": id};
49 find_one(filter_document, &collection_name, &db).await
50}
51
52pub async fn find_by_string_id<T>(
53 id: &str,
54 collection_name: &str,
55 db: &Database,
56) -> Result<Option<T>, Error>
57where
58 for<'a> T: Serialize + Deserialize<'a>,
59{
60 trace!("find_by_string_id");
61 let filter_document = doc! {"_id": id};
62 find_one(filter_document, &collection_name, &db).await
63}
64
65pub async fn find_one_by_string_field<T>(
66 name: &str,
67 value: &str,
68 collection_name: &str,
69 db: &Database,
70) -> Result<Option<T>, Error>
71where
72 for<'a> T: Serialize + Deserialize<'a>,
73{
74 trace!("find_by_string_id");
75 let filter_document = doc! {name: value};
76 find_one(filter_document, &collection_name, &db).await
77}
78
79pub async fn find_by_string_field<T>(
80 name: &str,
81 value: &str,
82 collection_name: &str,
83 db: &Database,
84) -> Result<Vec<T>, Error>
85where
86 for<'a> T: Serialize + Deserialize<'a>,
87{
88 trace!("find_by_string_field");
89 let filter_document = doc! {name: value};
90 find(filter_document, &collection_name, &db).await
91}
92
93pub async fn find_all<T>(collection_name: &str, db: &Database) -> Result<Vec<T>, Error>
94where
95 for<'a> T: Serialize + Deserialize<'a>,
96{
97 trace!("find_all");
98 find_generic(None, None, collection_name, db).await
99}
100
101pub async fn find<T>(
102 filter_document: Document,
103 collection_name: &str,
104 db: &Database,
105) -> Result<Vec<T>, Error>
106where
107 for<'a> T: Serialize + Deserialize<'a>,
108{
109 trace!("find");
110 find_generic(filter_document, None, collection_name, db).await
111}
112
113pub async fn find_with_sort<T>(
114 filter_document: Document,
115 sort_document: Document,
116 collection_name: &str,
117 db: &Database,
118) -> Result<Vec<T>, Error>
119where
120 for<'a> T: Serialize + Deserialize<'a>,
121{
122 trace!("find_with_sort");
123 find_generic(filter_document, Some(sort_document), collection_name, db).await
124}
125
126async fn find_generic<T>(
127 filter_document: impl Into<Option<Document>>,
128 sort_document_option: Option<Document>,
129 collection_name: &str,
130 db: &Database,
131) -> Result<Vec<T>, Error>
132where
133 for<'a> T: Serialize + Deserialize<'a>,
134{
135 trace!("find_generic");
136 let coll = db.collection(collection_name);
137 let find_options = get_sort_find_option(sort_document_option);
138 let mut cursor = coll.find(filter_document, find_options).await?;
139 let mut items = Vec::<T>::new();
140 while let Some(result) = cursor.next().await {
141 match result {
142 Ok(document) => {
143 let item = bson::from_bson::<T>(BsonDocument(document))?;
144 items.push(item);
145 }
146 Err(err) => {
147 return Err(err);
148 }
149 }
150 }
151
152 Ok(items)
153}
154
155fn get_sort_find_option(sort_document_option: Option<Document>) -> Option<FindOptions> {
156 if let Some(sort_document) = sort_document_option {
157 Some(FindOptions::builder().sort(sort_document).build())
158 } else {
159 None
160 }
161}
162
163pub async fn _find_one_by_field<T>(
164 field_name: String,
165 value: String,
166 collection_name: &str,
167 db: &Database,
168) -> Result<Option<T>, Error>
169where
170 for<'a> T: Serialize + Deserialize<'a>,
171{
172 self::find_one(doc! {field_name: value}, collection_name, db).await
173}
174
175pub async fn add<T>(t: &T, collection_name: &str, db: &Database) -> Result<InsertOneResult, Error>
176where
177 for<'a> T: Debug + Serialize + Deserialize<'a>,
178{
179 let serialized_item = bson::to_bson(&t)?;
180
181 if let BsonDocument(document) = serialized_item {
182 let coll = db.collection(collection_name);
183 coll.insert_one(document, None).await
184 } else {
185 panic!("Error converting the BSON object into a MongoDB document");
186 }
187}
188
189pub async fn update_one(
190 query: Document,
191 update: impl Into<UpdateModifications>,
192 options: impl Into<Option<UpdateOptions>>,
193 collection_name: &str,
194 db: &Database,
195) -> Result<UpdateResult, Error> {
196 let coll = db.collection(collection_name);
197 coll.update_one(query, update, options).await
198}
199
200pub async fn find_one_and_update<T>(
201 filter: Document,
202 update: impl Into<UpdateModifications>,
203 options: impl Into<Option<FindOneAndUpdateOptions>>,
204 collection_name: &str,
205 db: &Database,
206) -> Result<Option<T>, Error>
207where
208 for<'a> T: Serialize + Deserialize<'a>,
209{
210 let coll = db.collection(collection_name);
211 let option = coll.find_one_and_update(filter, update, options).await?;
212 if let Some(document) = option {
213 let t = bson::from_bson::<T>(BsonDocument(document))?;
214 return Ok(Some(t));
215 } else {
216 return Ok(None);
217 }
218}
219
220pub async fn find_one_and_replace<T>(
221 filter: Document,
222 replacement: &T,
223 options: impl Into<Option<FindOneAndReplaceOptions>>,
224 collection_name: &str,
225 db: &Database,
226) -> Result<Option<T>, Error>
227where
228 for<'a> T: Serialize + Deserialize<'a>,
229{
230 let coll = db.collection(collection_name);
231 let serialized_item = bson::to_bson(&replacement)?;
232
233 if let BsonDocument(document) = serialized_item {
234 let option = coll.find_one_and_replace(filter, document, options).await?;
235 if let Some(document) = option {
236 let t = bson::from_bson::<T>(BsonDocument(document))?;
237 return Ok(Some(t));
238 } else {
239 return Ok(None);
240 }
241 } else {
242 panic!("Error converting the BSON object into a MongoDB document");
243 }
244}
245
246pub async fn replace_one<T>(
247 query: Document,
248 replacement: &T,
249 options: impl Into<Option<ReplaceOptions>>,
250 collection_name: &str,
251 db: &Database,
252) -> Result<UpdateResult, Error>
253where
254 for<'a> T: Serialize + Deserialize<'a>,
255{
256 let coll = db.collection(collection_name);
257 let serialized_item = bson::to_bson(&replacement)?;
258
259 if let BsonDocument(document) = serialized_item {
260 coll.replace_one(query, document, options).await
261 } else {
262 panic!("Error converting the BSON object into a MongoDB document");
263 }
264}
265
266pub async fn delete_one(
267 query: Document,
268 options: impl Into<Option<DeleteOptions>>,
269 collection_name: &str,
270 db: &Database,
271) -> Result<DeleteResult, Error> {
272 let coll = db.collection(collection_name);
273 coll.delete_one(query, options).await
274}