use serde::{Deserialize, Serialize};
use std::time::Duration;
#[cfg(feature = "mysql")]
use sqlx::mysql::MySqlPoolOptions;
#[cfg(feature = "postgres")]
use sqlx::postgres::PgPoolOptions;
#[cfg(feature = "sqlite")]
use sqlx::sqlite::SqlitePoolOptions;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum DatabaseType {
#[cfg(feature = "mysql")]
MySQL,
#[cfg(feature = "postgres")]
PostgreSQL,
#[cfg(feature = "sqlite")]
SQLite,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DatabaseConfig {
pub url: String,
#[serde(default = "default_max_connections")]
pub max_connections: u32,
#[serde(default = "default_min_connections")]
pub min_connections: u32,
#[serde(default = "default_connect_timeout")]
pub connect_timeout: u64,
#[serde(default = "default_max_lifetime")]
pub max_lifetime: u64,
#[serde(default = "default_idle_timeout")]
pub idle_timeout: u64,
#[serde(default = "default_acquire_timeout")]
pub acquire_timeout: u64,
}
impl DatabaseConfig {
pub fn new() -> Self {
Self {
url: String::new(),
max_connections: default_max_connections(),
min_connections: default_min_connections(),
connect_timeout: default_connect_timeout(),
max_lifetime: default_max_lifetime(),
idle_timeout: default_idle_timeout(),
acquire_timeout: default_acquire_timeout(),
}
}
pub fn url<S: Into<String>>(mut self, url: S) -> Self {
self.url = url.into();
self
}
pub fn max_connections(mut self, max: u32) -> Self {
self.max_connections = max;
self
}
pub fn min_connections(mut self, min: u32) -> Self {
self.min_connections = min;
self
}
pub fn connect_timeout(mut self, timeout: u64) -> Self {
self.connect_timeout = timeout;
self
}
pub fn max_lifetime(mut self, lifetime: u64) -> Self {
self.max_lifetime = lifetime;
self
}
pub fn idle_timeout(mut self, timeout: u64) -> Self {
self.idle_timeout = timeout;
self
}
pub fn acquire_timeout(mut self, timeout: u64) -> Self {
self.acquire_timeout = timeout;
self
}
pub fn into_pool_options(&self) -> PoolOptions {
let db_type = self.get_database_type();
match db_type {
#[cfg(feature = "mysql")]
DatabaseType::MySQL => PoolOptions::MySQL(
MySqlPoolOptions::new()
.max_connections(self.max_connections)
.min_connections(self.min_connections)
.acquire_timeout(Duration::from_secs(self.acquire_timeout))
.idle_timeout(Duration::from_secs(self.idle_timeout))
.max_lifetime(Some(Duration::from_secs(self.max_lifetime))),
),
#[cfg(feature = "postgres")]
DatabaseType::PostgreSQL => PoolOptions::PostgreSQL(
PgPoolOptions::new()
.max_connections(self.max_connections)
.min_connections(self.min_connections)
.acquire_timeout(Duration::from_secs(self.acquire_timeout))
.idle_timeout(Duration::from_secs(self.idle_timeout))
.max_lifetime(Some(Duration::from_secs(self.max_lifetime))),
),
#[cfg(feature = "sqlite")]
DatabaseType::SQLite => PoolOptions::SQLite(
SqlitePoolOptions::new()
.max_connections(self.max_connections)
.min_connections(self.min_connections)
.acquire_timeout(Duration::from_secs(self.acquire_timeout))
.idle_timeout(Duration::from_secs(self.idle_timeout))
.max_lifetime(Some(Duration::from_secs(self.max_lifetime))),
),
}
}
fn get_database_type(&self) -> DatabaseType {
if self.url.starts_with("mysql://") {
#[cfg(feature = "mysql")]
return DatabaseType::MySQL;
} else if self.url.starts_with("postgresql://") {
#[cfg(feature = "postgres")]
return DatabaseType::PostgreSQL;
} else if self.url.starts_with("sqlite://") {
#[cfg(feature = "sqlite")]
return DatabaseType::SQLite;
}
panic!("Unsupported database type or feature not enabled")
}
}
impl Default for DatabaseConfig {
fn default() -> Self {
Self::new()
}
}
fn default_max_connections() -> u32 {
(num_cpus::get() * 2) as u32
}
fn default_min_connections() -> u32 {
(num_cpus::get() as u32).max(1)
}
fn default_connect_timeout() -> u64 {
10
}
fn default_max_lifetime() -> u64 {
3600
}
fn default_idle_timeout() -> u64 {
600
}
fn default_acquire_timeout() -> u64 {
30
}
pub enum PoolOptions {
#[cfg(feature = "mysql")]
MySQL(MySqlPoolOptions),
#[cfg(feature = "postgres")]
PostgreSQL(PgPoolOptions),
#[cfg(feature = "sqlite")]
SQLite(SqlitePoolOptions),
}