use anyhow::Result;
use async_trait::async_trait;
use crate::config::DatabaseConfig;
use crate::db::{DatabaseError, MessageMapping, RoomMapping, UserMapping};
#[cfg(feature = "mysql")]
use super::mysql::MysqlBackend;
#[cfg(feature = "postgres")]
use super::postgres::PostgresBackend;
#[cfg(feature = "sqlite")]
use super::sqlite::SqliteBackend;
pub struct DatabaseManager {
inner: DatabaseBackend,
}
enum DatabaseBackend {
#[cfg(feature = "postgres")]
Postgres(PostgresBackend),
#[cfg(feature = "sqlite")]
Sqlite(SqliteBackend),
#[cfg(feature = "mysql")]
Mysql(MysqlBackend),
}
impl DatabaseManager {
pub async fn new(config: &DatabaseConfig) -> Result<Self> {
let url = config.url.as_ref().or(config.filename.as_ref())
.ok_or_else(|| anyhow::anyhow!("database url or filename required"))?;
let inner = if url.starts_with("postgres://") || url.starts_with("postgresql://") {
#[cfg(feature = "postgres")]
{
DatabaseBackend::Postgres(PostgresBackend::new(url).await?)
}
#[cfg(not(feature = "postgres"))]
{
anyhow::bail!("postgres feature not enabled");
}
} else if url.starts_with("sqlite://") {
#[cfg(feature = "sqlite")]
{
DatabaseBackend::Sqlite(SqliteBackend::new(url).await?)
}
#[cfg(not(feature = "sqlite"))]
{
anyhow::bail!("sqlite feature not enabled");
}
} else if url.starts_with("mysql://") || url.starts_with("mariadb://") {
#[cfg(feature = "mysql")]
{
DatabaseBackend::Mysql(MysqlBackend::new(url).await?)
}
#[cfg(not(feature = "mysql"))]
{
anyhow::bail!("mysql feature not enabled");
}
} else {
#[cfg(feature = "postgres")]
{
DatabaseBackend::Postgres(PostgresBackend::new(url).await?)
}
#[cfg(not(feature = "postgres"))]
{
anyhow::bail!("default postgres feature not enabled");
}
};
Ok(Self { inner })
}
pub async fn migrate(&self) -> Result<()> {
match &self.inner {
#[cfg(feature = "postgres")]
DatabaseBackend::Postgres(db) => db.migrate().await,
#[cfg(feature = "sqlite")]
DatabaseBackend::Sqlite(db) => db.migrate().await,
#[cfg(feature = "mysql")]
DatabaseBackend::Mysql(db) => db.migrate().await,
}
}
}
#[async_trait]
pub trait DatabaseBackendTrait: Send + Sync {
async fn migrate(&self) -> Result<()>;
async fn get_room_mapping(&self, channel_id: &str) -> Result<Option<RoomMapping>>;
async fn create_room_mapping(&self, mapping: &RoomMapping) -> Result<()>;
async fn get_user_mapping(&self, teams_user_id: &str) -> Result<Option<UserMapping>>;
async fn create_user_mapping(&self, mapping: &UserMapping) -> Result<()>;
async fn get_message_mapping(&self, teams_message_id: &str) -> Result<Option<MessageMapping>>;
async fn create_message_mapping(&self, mapping: &MessageMapping) -> Result<()>;
}