wasi-pg-client 0.1.3

PostgreSQL client library for WASI Preview 2
Documentation
use crate::{Config, PgError};
use std::time::Duration;

#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct PoolConfig {
    pub(crate) connection: Config,
    pub(crate) min_idle: usize,
    pub(crate) max_size: usize,
    pub(crate) acquire_timeout: Option<Duration>,
    pub(crate) max_lifetime: Option<Duration>,
    pub(crate) idle_timeout: Option<Duration>,
    pub(crate) test_on_acquire: bool,
    pub(crate) after_connect: Option<String>,
    pub(crate) before_return: Option<String>,
}

impl Default for PoolConfig {
    fn default() -> Self {
        PoolConfig {
            connection: Config::default(),
            min_idle: 0,
            max_size: 10,
            acquire_timeout: Some(Duration::from_secs(30)),
            max_lifetime: Some(Duration::from_secs(1800)),
            idle_timeout: Some(Duration::from_secs(600)),
            test_on_acquire: true,
            after_connect: None,
            before_return: None,
        }
    }
}

impl PoolConfig {
    pub fn connection(mut self, connection: Config) -> Self {
        self.connection = connection;
        self
    }

    pub fn min_idle(mut self, min_idle: usize) -> Self {
        self.min_idle = min_idle;
        self
    }

    pub fn max_size(mut self, max_size: usize) -> Self {
        self.max_size = max_size;
        self
    }

    pub fn acquire_timeout(mut self, acquire_timeout: Option<Duration>) -> Self {
        self.acquire_timeout = acquire_timeout;
        self
    }

    pub fn max_lifetime(mut self, max_lifetime: Option<Duration>) -> Self {
        self.max_lifetime = max_lifetime;
        self
    }

    pub fn idle_timeout(mut self, idle_timeout: Option<Duration>) -> Self {
        self.idle_timeout = idle_timeout;
        self
    }

    pub fn test_on_acquire(mut self, test_on_acquire: bool) -> Self {
        self.test_on_acquire = test_on_acquire;
        self
    }

    pub fn after_connect(mut self, sql: impl Into<String>) -> Self {
        self.after_connect = Some(sql.into());
        self
    }

    pub fn before_return(mut self, sql: impl Into<String>) -> Self {
        self.before_return = Some(sql.into());
        self
    }

    pub fn validate(&self) -> Result<(), PgError> {
        if self.max_size == 0 {
            return Err(PgError::Config(
                "pool max_size must be greater than zero".to_string(),
            ));
        }

        if self.min_idle > self.max_size {
            return Err(PgError::Config(format!(
                "pool min_idle ({}) cannot exceed max_size ({})",
                self.min_idle, self.max_size
            )));
        }

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_default_config() {
        let config = PoolConfig::default();
        assert_eq!(config.max_size, 10);
        assert_eq!(config.min_idle, 0);
        assert_eq!(config.acquire_timeout, Some(Duration::from_secs(30)));
        assert_eq!(config.max_lifetime, Some(Duration::from_secs(1800)));
        assert_eq!(config.idle_timeout, Some(Duration::from_secs(600)));
        assert!(config.test_on_acquire);
        assert!(config.after_connect.is_none());
        assert!(config.before_return.is_none());
    }

    #[test]
    fn test_builder_methods() {
        let config = PoolConfig::default()
            .max_size(20)
            .min_idle(5)
            .acquire_timeout(Some(Duration::from_secs(10)))
            .max_lifetime(Some(Duration::from_secs(3600)))
            .idle_timeout(Some(Duration::from_secs(300)))
            .test_on_acquire(false)
            .after_connect("SET timezone = 'UTC'")
            .before_return("RESET ALL");

        assert_eq!(config.max_size, 20);
        assert_eq!(config.min_idle, 5);
        assert_eq!(config.acquire_timeout, Some(Duration::from_secs(10)));
        assert_eq!(config.max_lifetime, Some(Duration::from_secs(3600)));
        assert_eq!(config.idle_timeout, Some(Duration::from_secs(300)));
        assert!(!config.test_on_acquire);
        assert_eq!(
            config.after_connect.as_deref(),
            Some("SET timezone = 'UTC'")
        );
        assert_eq!(config.before_return.as_deref(), Some("RESET ALL"));
    }

    #[test]
    fn test_validate_rejects_zero_max_size() {
        let err = PoolConfig::default().max_size(0).validate().unwrap_err();
        assert!(matches!(err, PgError::Config(_)));
        assert_eq!(
            err.to_string(),
            "configuration error: pool max_size must be greater than zero"
        );
    }

    #[test]
    fn test_validate_rejects_min_idle_above_max_size() {
        let err = PoolConfig::default()
            .max_size(4)
            .min_idle(5)
            .validate()
            .unwrap_err();
        assert!(matches!(err, PgError::Config(_)));
        assert_eq!(
            err.to_string(),
            "configuration error: pool min_idle (5) cannot exceed max_size (4)"
        );
    }

    #[test]
    fn test_validate_accepts_equal_min_idle_and_max_size() {
        PoolConfig::default()
            .max_size(4)
            .min_idle(4)
            .validate()
            .unwrap();
    }
}