1use crate::{DatabaseError, Result};
12use std::time::Duration;
13
14#[cfg(feature = "postgres")]
15use sqlx::{Pool, Postgres};
16
17#[derive(Clone, Debug)]
19pub struct PoolConfig {
20 pub max_connections: u32,
22 pub min_connections: u32,
24 pub acquire_timeout_secs: u64,
26 pub idle_timeout_secs: u64,
28 pub max_lifetime_secs: u64,
30 pub test_before_acquire: bool,
32}
33
34impl Default for PoolConfig {
35 fn default() -> Self {
36 Self {
37 max_connections: 20,
38 min_connections: 5,
39 acquire_timeout_secs: 30,
40 idle_timeout_secs: 600,
41 max_lifetime_secs: 1800,
42 test_before_acquire: true,
43 }
44 }
45}
46
47#[derive(Clone)]
49pub struct DatabasePool {
50 #[cfg(feature = "postgres")]
51 pool: Pool<Postgres>,
52}
53
54impl DatabasePool {
55 #[cfg(feature = "postgres")]
57 pub async fn connect(url: &str) -> Result<Self> {
58 Self::connect_with_config(url, PoolConfig::default()).await
59 }
60
61 #[cfg(feature = "postgres")]
69 pub async fn connect_with_config(url: &str, config: PoolConfig) -> Result<Self> {
70 let pool = sqlx::postgres::PgPoolOptions::new()
71 .max_connections(config.max_connections)
72 .min_connections(config.min_connections)
73 .acquire_timeout(Duration::from_secs(config.acquire_timeout_secs))
74 .idle_timeout(Some(Duration::from_secs(config.idle_timeout_secs)))
75 .max_lifetime(Some(Duration::from_secs(config.max_lifetime_secs)))
76 .test_before_acquire(config.test_before_acquire)
77 .connect(url)
78 .await
79 .map_err(|e| DatabaseError::ConnectionFailed(e.to_string()))?;
80
81 Ok(Self { pool })
82 }
83
84 #[cfg(feature = "postgres")]
86 pub fn inner(&self) -> &Pool<Postgres> {
87 &self.pool
88 }
89
90 #[cfg(feature = "postgres")]
92 pub async fn health_check(&self) -> Result<()> {
93 sqlx::query("SELECT 1")
94 .execute(&self.pool)
95 .await
96 .map_err(|e| DatabaseError::QueryFailed(e.to_string()))?;
97 Ok(())
98 }
99}
100
101#[cfg(all(test, feature = "postgres"))]
102mod tests {
103 use super::*;
104
105 #[tokio::test]
106 #[ignore] async fn test_connect() {
108 let pool = DatabasePool::connect("postgres://localhost/test").await;
109 assert!(pool.is_ok() || pool.is_err()); }
111}