1use futures::TryStreamExt;
2use mongodb::{
3 self, Client, Collection, Database,
4 bson::{self, doc},
5 options::ClientOptions,
6};
7use serde::{Deserialize, Serialize};
8
9
10pub use mongodb::bson::oid::ObjectId;
11
12mod traits;
13pub use traits::MongoObject;
14
15mod structures;
16pub use structures::{options::Options, credentials::Credentials};
17
18
19
20pub struct SimpleMongo<T>
21where
22 T: for<'de> Deserialize<'de> + Sync + Send + Serialize + MongoObject + Clone,
23{
24 #[allow(dead_code)]
25 options: Options,
26 collection: Collection<T>,
27 #[allow(dead_code)]
28 database: Database,
29}
30
31impl<T> SimpleMongo<T>
32where
33 T: Send + Sync + for<'de> Deserialize<'de> + Serialize + MongoObject + Clone,
34{
35 pub fn parse_id(id: &str) -> String {
36 ObjectId::parse_str(id)
37 .expect(&format!("{id} is not a valid id"))
38 .to_string()
39 }
40
41 pub fn add_credentials_to_url(url:&str,user:&str,password:&str)->String{
42
43 let mut splitted = url.split("//");
44
45 let mongo =splitted.next().unwrap();
46
47 let rest = splitted.next().unwrap();
48
49 format!("{mongo}//{user}:{password}@{rest}")
50 }
51
52 pub async fn connect(options: Options) -> SimpleMongo<T> {
53
54 let mut parsed_options = options.clone();
55 if let Some(ref x) = parsed_options.credentials{
56 let new_uri = SimpleMongo::<T>::add_credentials_to_url(&parsed_options.uri, &x.username, &x.password);
57 parsed_options.uri = new_uri;
58 }
59
60 let client =
61 Client::with_options(ClientOptions::parse(&parsed_options.uri).await.unwrap()).map_err(|e| format!("Errore connecting to MongoDB: {}", e)).unwrap();
62 let database: Database = client.database(&options.database_name);
65 let collection = database.collection::<T>(&options.collection_path);
66 collection.find(doc! {}).await.unwrap();
67 return SimpleMongo {
68 options:parsed_options,
69 database,
70 collection,
71 };
72 }
73
74 pub async fn list_all(&self) -> Vec<T> {
75 let cursor = self.collection.find(doc! {}).await.ok().unwrap();
76
77 let res: Vec<T> = cursor.try_collect().await.unwrap();
78 res
79 }
80
81 pub async fn find_one_by_id(&self, id: &str) -> Option<T> {
82 let parsed_id: String = SimpleMongo::<T>::parse_id(id);
83 self.collection
84 .find_one(doc! {"id":parsed_id})
85 .await
86 .ok()
87 .unwrap()
88 }
89
90 pub async fn insert_one(&self, item: T) -> Option<T> {
91 if let Some(_) = self.collection.insert_one(&item).await.ok() {
92 return self.find_one_by_id(&item.id()).await;
93 } else {
94 return None;
95 }
96 }
97
98 pub async fn remove_one_by_id(&self, id: &str) -> Option<T> {
99 let parsed_id: String = SimpleMongo::<T>::parse_id(id);
100 if let Some(res) = self
101 .collection
102 .find_one_and_delete(doc! {"id":parsed_id})
103 .await
104 .ok()
105 {
106 return res;
107 } else {
108 return None;
109 }
110 }
111
112 pub async fn clear(&self) -> bool {
113 self.collection.delete_many(doc! {}).await.unwrap();
114 self.collection.count_documents(doc! {}).await.unwrap() == 0
115 }
116
117 pub async fn update_one_by_id(&self, id: &str, update: T) -> Option<T> {
118 let mut new_item: T = update.clone();
119 new_item.set_id(id);
120
121 let update_doc = bson::to_document(&new_item).unwrap(); let update_query = doc! { "$set": &update_doc }; let parsed_id: String = SimpleMongo::<T>::parse_id(id);
125 if let Some(res) = self
126 .collection
127 .update_one(doc! {"id":parsed_id}, update_query)
128 .await
129 .ok()
130 {
131 if res.modified_count == 0 {
132 return None;
133 } else {
134 return Some(new_item);
135 }
136 } else {
137 None
138 }
139 }
140}