1use crate::error::Error;
12use bb8::ManageConnection;
13use mongodb::{Client, Database, bson::doc, options::ClientOptions};
14
15#[derive(Clone, Debug)]
17pub struct Mongodb {
18 client_options: ClientOptions,
19 db_name: String,
20}
21
22impl Mongodb {
23 pub fn new<T>(client_options: ClientOptions, db_name: T) -> Mongodb
25 where
26 T: Into<String>,
27 {
28 Mongodb {
29 client_options,
30 db_name: db_name.into(),
31 }
32 }
33}
34
35impl ManageConnection for Mongodb {
36 type Connection = Database;
37 type Error = Error;
38
39 fn has_broken(&self, _conn: &mut Self::Connection) -> bool {
40 false
41 }
42
43 async fn connect(&self) -> Result<Self::Connection, Self::Error> {
44 let client = Client::with_options(self.client_options.clone())?;
45 Ok(client.database(&self.db_name))
46 }
47
48 async fn is_valid(&self, conn: &mut Self::Connection) -> Result<(), Self::Error> {
49 let _doc = conn.run_command(doc! { "ping": 1 }).await?;
50 Ok(())
51 }
52}
53
54#[cfg(test)]
55mod test {
56 use super::Mongodb;
57 use anyhow::Result;
58 use bb8::Pool;
59 use futures::pin_mut;
60 use mongodb::{
61 bson::doc,
62 options::{ClientOptions, Credential},
63 };
64 use std::{env, time::Duration};
65 use tokio::time::timeout;
66
67 #[tokio::test]
68 #[allow(clippy::needless_return)]
69 async fn new_works() -> Result<()> {
70 let mut client_options = ClientOptions::parse(env::var("BB8_MONGODB_URL")?).await?;
71 client_options.credential = Some(
72 Credential::builder()
73 .username(env::var("BB8_MONGODB_USER").ok())
74 .password(env::var("BB8_MONGODB_PASSWORD").ok())
75 .build(),
76 );
77
78 let connection_manager = Mongodb::new(client_options, "admin");
80 let pool = Pool::builder().build(connection_manager).await?;
82 let conn = pool.get().await?;
84 assert_eq!(conn.name(), "admin");
85 let doc = conn.run_command(doc! { "ping": 1 }).await?;
87 assert_eq!(doc! { "ok": 1 }, doc);
89 Ok(())
90 }
91
92 #[tokio::test]
93 #[allow(clippy::needless_return)]
94 async fn bad_connect_errors() -> Result<()> {
95 let mut client_options = ClientOptions::parse(env::var("BB8_MONGODB_URL")?).await?;
96 client_options.credential = Some(
97 Credential::builder()
98 .username(env::var("BB8_MONGODB_USER").ok())
99 .password(Some("not a password".to_string()))
100 .build(),
101 );
102 client_options.connect_timeout = Some(Duration::from_secs(3));
103 client_options.server_selection_timeout = Some(Duration::from_secs(3));
104
105 let connection_manager = Mongodb::new(client_options, "admin");
107 let pool = Pool::builder().build(connection_manager).await?;
109 let conn_fut = pool.get();
111 pin_mut!(conn_fut);
112 assert!(
113 timeout(Duration::from_secs(5), &mut conn_fut)
114 .await
115 .is_err()
116 );
117 Ok(())
118 }
119}