use crate::error::Error;
use bb8::ManageConnection;
use mongodb::{Client, Database, bson::doc, options::ClientOptions};
#[derive(Clone, Debug)]
pub struct Mongodb {
client_options: ClientOptions,
db_name: String,
}
impl Mongodb {
pub fn new<T>(client_options: ClientOptions, db_name: T) -> Mongodb
where
T: Into<String>,
{
Mongodb {
client_options,
db_name: db_name.into(),
}
}
}
impl ManageConnection for Mongodb {
type Connection = Database;
type Error = Error;
fn has_broken(&self, _conn: &mut Self::Connection) -> bool {
false
}
async fn connect(&self) -> Result<Self::Connection, Self::Error> {
let client = Client::with_options(self.client_options.clone())?;
Ok(client.database(&self.db_name))
}
async fn is_valid(&self, conn: &mut Self::Connection) -> Result<(), Self::Error> {
let _doc = conn.run_command(doc! { "ping": 1 }).await?;
Ok(())
}
}
#[cfg(test)]
mod test {
use super::Mongodb;
use anyhow::Result;
use bb8::Pool;
use futures::pin_mut;
use mongodb::{
bson::doc,
options::{ClientOptions, Credential},
};
use std::{env, time::Duration};
use tokio::time::timeout;
#[tokio::test]
#[allow(clippy::needless_return)]
async fn new_works() -> Result<()> {
let mut client_options = ClientOptions::parse(env::var("BB8_MONGODB_URL")?).await?;
client_options.credential = Some(
Credential::builder()
.username(env::var("BB8_MONGODB_USER").ok())
.password(env::var("BB8_MONGODB_PASSWORD").ok())
.build(),
);
let connection_manager = Mongodb::new(client_options, "admin");
let pool = Pool::builder().build(connection_manager).await?;
let conn = pool.get().await?;
assert_eq!(conn.name(), "admin");
let doc = conn.run_command(doc! { "ping": 1 }).await?;
assert_eq!(doc! { "ok": 1 }, doc);
Ok(())
}
#[tokio::test]
#[allow(clippy::needless_return)]
async fn bad_connect_errors() -> Result<()> {
let mut client_options = ClientOptions::parse(env::var("BB8_MONGODB_URL")?).await?;
client_options.credential = Some(
Credential::builder()
.username(env::var("BB8_MONGODB_USER").ok())
.password(Some("not a password".to_string()))
.build(),
);
client_options.connect_timeout = Some(Duration::from_secs(3));
client_options.server_selection_timeout = Some(Duration::from_secs(3));
let connection_manager = Mongodb::new(client_options, "admin");
let pool = Pool::builder().build(connection_manager).await?;
let conn_fut = pool.get();
pin_mut!(conn_fut);
assert!(
timeout(Duration::from_secs(5), &mut conn_fut)
.await
.is_err()
);
Ok(())
}
}