use crate::connection::Connection;
use crate::database::Database;
use crate::error::Error;
use crate::pool::inner::PoolInner;
use crate::pool::Pool;
use futures_core::future::BoxFuture;
use log::LevelFilter;
use std::fmt::{self, Debug, Formatter};
use std::sync::Arc;
use std::time::{Duration, Instant};
pub struct PoolOptions<DB: Database> {
pub(crate) test_before_acquire: bool,
pub(crate) after_connect: Option<
Arc<
dyn Fn(&mut DB::Connection, PoolConnectionMetadata) -> BoxFuture<'_, Result<(), Error>>
+ 'static
+ Send
+ Sync,
>,
>,
pub(crate) before_acquire: Option<
Arc<
dyn Fn(
&mut DB::Connection,
PoolConnectionMetadata,
) -> BoxFuture<'_, Result<bool, Error>>
+ 'static
+ Send
+ Sync,
>,
>,
pub(crate) after_release: Option<
Arc<
dyn Fn(
&mut DB::Connection,
PoolConnectionMetadata,
) -> BoxFuture<'_, Result<bool, Error>>
+ 'static
+ Send
+ Sync,
>,
>,
pub(crate) max_connections: u32,
pub(crate) acquire_time_level: LevelFilter,
pub(crate) acquire_slow_level: LevelFilter,
pub(crate) acquire_slow_threshold: Duration,
pub(crate) acquire_timeout: Duration,
pub(crate) min_connections: u32,
pub(crate) max_lifetime: Option<Duration>,
pub(crate) idle_timeout: Option<Duration>,
pub(crate) fair: bool,
pub(crate) parent_pool: Option<Pool<DB>>,
}
impl<DB: Database> Clone for PoolOptions<DB> {
fn clone(&self) -> Self {
PoolOptions {
test_before_acquire: self.test_before_acquire,
after_connect: self.after_connect.clone(),
before_acquire: self.before_acquire.clone(),
after_release: self.after_release.clone(),
max_connections: self.max_connections,
acquire_time_level: self.acquire_time_level,
acquire_slow_threshold: self.acquire_slow_threshold,
acquire_slow_level: self.acquire_slow_level,
acquire_timeout: self.acquire_timeout,
min_connections: self.min_connections,
max_lifetime: self.max_lifetime,
idle_timeout: self.idle_timeout,
fair: self.fair,
parent_pool: self.parent_pool.clone(),
}
}
}
#[derive(Debug)] #[non_exhaustive] pub struct PoolConnectionMetadata {
pub age: Duration,
pub idle_for: Duration,
}
impl<DB: Database> Default for PoolOptions<DB> {
fn default() -> Self {
Self::new()
}
}
impl<DB: Database> PoolOptions<DB> {
pub fn new() -> Self {
Self {
after_connect: None,
before_acquire: None,
after_release: None,
test_before_acquire: true,
max_connections: 10,
min_connections: 0,
acquire_time_level: LevelFilter::Off,
acquire_slow_level: LevelFilter::Warn,
acquire_slow_threshold: Duration::from_secs(2),
acquire_timeout: Duration::from_secs(30),
idle_timeout: Some(Duration::from_secs(10 * 60)),
max_lifetime: Some(Duration::from_secs(30 * 60)),
fair: true,
parent_pool: None,
}
}
pub fn max_connections(mut self, max: u32) -> Self {
self.max_connections = max;
self
}
pub fn get_max_connections(&self) -> u32 {
self.max_connections
}
pub fn min_connections(mut self, min: u32) -> Self {
self.min_connections = min;
self
}
pub fn get_min_connections(&self) -> u32 {
self.min_connections
}
pub fn acquire_time_level(mut self, level: LevelFilter) -> Self {
self.acquire_time_level = level;
self
}
pub fn acquire_slow_level(mut self, level: LevelFilter) -> Self {
self.acquire_slow_level = level;
self
}
pub fn acquire_slow_threshold(mut self, threshold: Duration) -> Self {
self.acquire_slow_threshold = threshold;
self
}
pub fn get_acquire_slow_threshold(&self) -> Duration {
self.acquire_slow_threshold
}
pub fn acquire_timeout(mut self, timeout: Duration) -> Self {
self.acquire_timeout = timeout;
self
}
pub fn get_acquire_timeout(&self) -> Duration {
self.acquire_timeout
}
pub fn max_lifetime(mut self, lifetime: impl Into<Option<Duration>>) -> Self {
self.max_lifetime = lifetime.into();
self
}
pub fn get_max_lifetime(&self) -> Option<Duration> {
self.max_lifetime
}
pub fn idle_timeout(mut self, timeout: impl Into<Option<Duration>>) -> Self {
self.idle_timeout = timeout.into();
self
}
pub fn get_idle_timeout(&self) -> Option<Duration> {
self.idle_timeout
}
pub fn test_before_acquire(mut self, test: bool) -> Self {
self.test_before_acquire = test;
self
}
pub fn get_test_before_acquire(&self) -> bool {
self.test_before_acquire
}
#[doc(hidden)]
pub fn __fair(mut self, fair: bool) -> Self {
self.fair = fair;
self
}
pub fn after_connect<F>(mut self, callback: F) -> Self
where
for<'c> F: Fn(&'c mut DB::Connection, PoolConnectionMetadata) -> BoxFuture<'c, Result<(), Error>>
+ 'static
+ Send
+ Sync,
{
self.after_connect = Some(Arc::new(callback));
self
}
pub fn before_acquire<F>(mut self, callback: F) -> Self
where
for<'c> F: Fn(&'c mut DB::Connection, PoolConnectionMetadata) -> BoxFuture<'c, Result<bool, Error>>
+ 'static
+ Send
+ Sync,
{
self.before_acquire = Some(Arc::new(callback));
self
}
pub fn after_release<F>(mut self, callback: F) -> Self
where
for<'c> F: Fn(&'c mut DB::Connection, PoolConnectionMetadata) -> BoxFuture<'c, Result<bool, Error>>
+ 'static
+ Send
+ Sync,
{
self.after_release = Some(Arc::new(callback));
self
}
#[doc(hidden)]
pub fn parent(mut self, pool: Pool<DB>) -> Self {
self.parent_pool = Some(pool);
self
}
pub async fn connect(self, url: &str) -> Result<Pool<DB>, Error> {
self.connect_with(url.parse()?).await
}
pub async fn connect_with(
self,
options: <DB::Connection as Connection>::Options,
) -> Result<Pool<DB>, Error> {
let deadline = Instant::now() + self.acquire_timeout;
let inner = PoolInner::new_arc(self, options);
if inner.options.min_connections > 0 {
inner.try_min_connections(deadline).await?;
}
let conn = inner.acquire().await?;
inner.release(conn);
Ok(Pool(inner))
}
pub fn connect_lazy(self, url: &str) -> Result<Pool<DB>, Error> {
Ok(self.connect_lazy_with(url.parse()?))
}
pub fn connect_lazy_with(self, options: <DB::Connection as Connection>::Options) -> Pool<DB> {
Pool(PoolInner::new_arc(self, options))
}
}
impl<DB: Database> Debug for PoolOptions<DB> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("PoolOptions")
.field("max_connections", &self.max_connections)
.field("min_connections", &self.min_connections)
.field("connect_timeout", &self.acquire_timeout)
.field("max_lifetime", &self.max_lifetime)
.field("idle_timeout", &self.idle_timeout)
.field("test_before_acquire", &self.test_before_acquire)
.finish()
}
}