use async_trait::async_trait;
use serde::Serialize;
use shuttle_service::{
database, error::CustomError, DbInput, DbOutput, Error, Factory, ResourceBuilder, Type,
};
#[derive(Serialize)]
pub struct MongoDb {
config: DbInput,
}
#[async_trait]
impl ResourceBuilder<mongodb::Database> for MongoDb {
const TYPE: Type = Type::Database(database::Type::Shared(database::SharedEngine::MongoDb));
type Config = DbInput;
type Output = DbOutput;
fn new() -> Self {
Self {
config: Default::default(),
}
}
fn config(&self) -> &Self::Config {
&self.config
}
async fn output(self, factory: &mut dyn Factory) -> Result<Self::Output, Error> {
let info = match factory.get_environment() {
shuttle_service::Environment::Production => DbOutput::Info(
factory
.get_db_connection(database::Type::Shared(database::SharedEngine::MongoDb))
.await
.map_err(CustomError::new)?,
),
shuttle_service::Environment::Local => {
if let Some(local_uri) = self.config.local_uri {
DbOutput::Local(local_uri)
} else {
DbOutput::Info(
factory
.get_db_connection(database::Type::Shared(
database::SharedEngine::MongoDb,
))
.await
.map_err(CustomError::new)?,
)
}
}
};
Ok(info)
}
async fn build(build_data: &Self::Output) -> Result<mongodb::Database, Error> {
let connection_string = match build_data {
DbOutput::Local(local_uri) => local_uri.clone(),
DbOutput::Info(info) => info.connection_string_private(),
};
let mut client_options = mongodb::options::ClientOptions::parse(connection_string)
.await
.map_err(CustomError::new)?;
client_options.min_pool_size = Some(1);
client_options.max_pool_size = Some(5);
let client = mongodb::Client::with_options(client_options).map_err(CustomError::new)?;
let database = client.default_database();
match database {
Some(database) => Ok(database),
None => Err(Error::Database(
"mongodb connection string missing default database".into(),
)),
}
}
}
impl MongoDb {
pub fn local_uri(mut self, local_uri: &str) -> Self {
self.config.local_uri = Some(local_uri.to_string());
self
}
}