use crate::queries; use sqlx::{AnyPool, any::AnyPoolOptions}; use tracing::{debug, info}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum DatabaseKind { Sqlite, Postgres, MySql, } #[derive(Debug, Clone)] pub struct Database { pool: AnyPool, kind: DatabaseKind, } impl Database { pub async fn connect(url: &str, max_connections: u32) -> Result { sqlx::any::install_default_drivers(); let kind = DatabaseKind::from_url(url)?; debug!(?kind, max_connections, "initializing database pool"); let pool = AnyPoolOptions::new() .max_connections(max_connections) .connect(url) .await?; if kind == DatabaseKind::Sqlite { debug!("applying SQLite connection pragmas"); sqlx::query(queries::get(kind, queries::SQLITE_FOREIGN_KEYS_ON)) .execute(&pool) .await?; sqlx::query(queries::get(kind, queries::SQLITE_JOURNAL_WAL)) .execute(&pool) .await?; sqlx::query(queries::get(kind, queries::SQLITE_BUSY_TIMEOUT)) .execute(&pool) .await?; } info!(?kind, max_connections, "database pool ready"); Ok(Self { pool, kind }) } pub fn pool(&self) -> &AnyPool { &self.pool } pub fn kind(&self) -> DatabaseKind { self.kind } } impl DatabaseKind { fn from_url(url: &str) -> Result { if url.starts_with("sqlite:") { Ok(Self::Sqlite) } else if url.starts_with("postgres:") || url.starts_with("postgresql:") { Ok(Self::Postgres) } else if url.starts_with("mysql:") { Ok(Self::MySql) } else { Err(sqlx::Error::Configuration( "DATABASE_URL must use sqlite://, postgres:// or mysql://".into(), )) } } }