use std::sync::Arc;
use async_trait::async_trait;
use super::{
backend::{Error, r#trait::Backend},
conn_pool::{ReusableConnectionPool as ReusableConnectionPoolInner, SingleUseConnectionPool},
object_pool::{ObjectPool, Reusable},
};
pub type ReusableConnectionPool<'a, B> = Reusable<'a, ReusableConnectionPoolInner<B>>;
pub struct DatabasePool<B: Backend> {
backend: Arc<B>,
object_pool: ObjectPool<ReusableConnectionPoolInner<B>>,
}
impl<B: Backend> DatabasePool<B> {
#[must_use]
pub async fn pull_immutable(&self) -> ReusableConnectionPool<B> {
self.object_pool.pull().await
}
pub async fn create_mutable(
&self,
) -> Result<
SingleUseConnectionPool<B>,
Error<B::BuildError, B::PoolError, B::ConnectionError, B::QueryError>,
> {
SingleUseConnectionPool::new(self.backend.clone()).await
}
}
#[async_trait]
pub trait DatabasePoolBuilder: Backend {
async fn create_database_pool(
self,
) -> Result<
DatabasePool<Self>,
Error<Self::BuildError, Self::PoolError, Self::ConnectionError, Self::QueryError>,
> {
self.init().await?;
let backend = Arc::new(self);
let object_pool = {
let backend = backend.clone();
ObjectPool::new(
move || {
let backend = backend.clone();
Box::pin(async {
ReusableConnectionPoolInner::new(backend)
.await
.expect("connection pool creation must succeed")
})
},
|mut conn_pool| {
Box::pin(async {
conn_pool
.clean()
.await
.expect("connection pool cleaning must succeed");
conn_pool
})
},
)
};
Ok(DatabasePool {
backend,
object_pool,
})
}
}
impl<AB: Backend> DatabasePoolBuilder for AB {}