athena_rs 3.26.2

Hyper performant polyglot Database driver
Documentation
//! Configuration models shared across Athena client pipelines.
use crate::client::backend::BackendType;
use std::fmt::{Debug, Formatter, Result as FmtResult};
use std::time::Duration;

const REDACTED_SECRET: &str = "<redacted>";

fn debug_secret_option(value: &Option<String>) -> Option<&'static str> {
    value.as_ref().map(|_| REDACTED_SECRET)
}

#[derive(Clone, Default)]
pub struct D1SessionConfig {
    pub default_session_mode: Option<String>,
    pub bookmark: Option<String>,
    pub retry_writes: bool,
}

impl Debug for D1SessionConfig {
    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
        f.debug_struct("D1SessionConfig")
            .field("default_session_mode", &self.default_session_mode)
            .field("bookmark", &self.bookmark)
            .field("retry_writes", &self.retry_writes)
            .finish()
    }
}

/// ## `ClientConfig`
/// High level configuration for Athena clients.
///
/// # Arguments
///
/// * `backend_type` - The backend type.
/// * `client_name` - The client name.
/// * `connection` - The connection configuration.
/// * `pool` - The pool configuration.
/// * `health` - The health configuration.
///
/// # Returns
///
/// A `ClientConfig` containing the client configuration.
///
#[derive(Clone)]
pub struct ClientConfig {
    pub backend_type: BackendType,
    pub client_name: Option<String>,
    pub connection: ConnectionConfig,
    pub pool: PoolConfig,
    pub health: HealthConfig,
    pub d1: D1SessionConfig,
}

impl ClientConfig {
    /// ## `new`
    /// Create a new client configuration.
    ///
    /// # Arguments
    ///
    /// * `backend_type` - The backend type.
    /// * `client_name` - The client name.
    /// * `connection` - The connection configuration.
    /// * `pool` - The pool configuration.
    /// * `health` - The health configuration.
    ///
    /// # Returns
    ///
    /// A `ClientConfig` containing the client configuration.
    ///
    pub fn new(
        backend_type: BackendType,
        client_name: Option<String>,
        connection: ConnectionConfig,
        pool: PoolConfig,
        health: HealthConfig,
        d1: D1SessionConfig,
    ) -> Self {
        Self {
            backend_type,
            client_name,
            connection,
            pool,
            health,
            d1,
        }
    }
}

impl Debug for ClientConfig {
    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
        f.debug_struct("ClientConfig")
            .field("backend_type", &self.backend_type)
            .field("client_name", &self.client_name)
            .field("connection", &self.connection)
            .field("pool", &self.pool)
            .field("health", &self.health)
            .field("d1", &self.d1)
            .finish()
    }
}

/// ## `ConnectionConfig`
/// Connection-specific options.
///
/// # Arguments
///
/// * `url` - The connection URL.
/// * `key` - The connection key.
/// * `ssl` - Whether to use SSL.
/// * `port` - The port.
/// * `database` - The database.
///
/// # Returns
///
/// A `ConnectionConfig` containing the connection configuration.
///
#[derive(Clone)]
pub struct ConnectionConfig {
    pub url: String,
    pub key: Option<String>,
    pub ssl: bool,
    pub port: Option<u16>,
    pub database: Option<String>,
}

impl ConnectionConfig {
    /// ## `new`
    /// Create a new connection configuration.
    ///
    /// # Arguments
    ///
    /// * `url` - The connection URL.
    ///
    /// # Returns
    ///
    /// A `ConnectionConfig` containing the connection configuration.
    ///
    pub fn new(url: impl Into<String>) -> Self {
        Self {
            url: url.into(),
            key: None,
            ssl: true,
            port: None,
            database: None,
        }
    }

    /// ## `with_key`
    /// Set the connection key.
    ///
    /// # Arguments
    ///
    /// * `key` - The connection key.
    ///
    /// # Returns
    ///
    /// A `ConnectionConfig` containing the connection configuration.
    ///
    pub fn with_key(mut self, key: impl Into<String>) -> Self {
        self.key = Some(key.into());
        self
    }
}

impl Debug for ConnectionConfig {
    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
        f.debug_struct("ConnectionConfig")
            .field("url", &self.url)
            .field("key", &debug_secret_option(&self.key))
            .field("ssl", &self.ssl)
            .field("port", &self.port)
            .field("database", &self.database)
            .finish()
    }
}

/// ## `PoolConfig`
/// Pool configuration shared by JDBC/Postgres backends.
///
/// # Arguments
///
/// * `max_connections` - The maximum number of connections.
/// * `min_connections` - The minimum number of connections.
/// * `connection_timeout` - The connection timeout.
/// * `idle_timeout` - The idle timeout.
///
/// # Returns
///
/// A `PoolConfig` containing the pool configuration.
///
#[derive(Clone, Debug)]
pub struct PoolConfig {
    pub max_connections: u32,
    pub min_connections: u32,
    pub connection_timeout: Duration,
    pub idle_timeout: Duration,
}

impl Default for PoolConfig {
    /// ## `default`
    /// Create a new pool configuration.
    ///
    /// # Arguments
    ///
    /// # Returns
    ///
    /// A `PoolConfig` containing the pool configuration.
    ///
    fn default() -> Self {
        Self {
            max_connections: 50,
            min_connections: 0,
            connection_timeout: Duration::from_secs(5),
            idle_timeout: Duration::from_secs(300),
        }
    }
}

/// ## `HealthConfig`
/// Health tracking configuration (circuit breaker, probes).
///
/// # Arguments
///
/// * `enabled` - Whether to enable health tracking.
/// * `check_interval` - The health check interval.
/// * `circuit_breaker_threshold` - The circuit breaker threshold.
/// * `circuit_breaker_timeout` - The circuit breaker timeout.
///
/// # Returns
///
/// A `HealthConfig` containing the health configuration.
///
#[derive(Clone, Debug)]
pub struct HealthConfig {
    pub enabled: bool,
    pub check_interval: Duration,
    pub circuit_breaker_threshold: u32,
    pub circuit_breaker_timeout: Duration,
}

impl Default for HealthConfig {
    /// ## `default`
    /// Create a new health configuration.
    ///
    /// # Arguments
    ///
    /// # Returns
    ///
    /// A `HealthConfig` containing the health configuration.
    ///
    fn default() -> Self {
        Self {
            enabled: true,
            check_interval: Duration::from_secs(30),
            circuit_breaker_threshold: 5,
            circuit_breaker_timeout: Duration::from_secs(60),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::{ClientConfig, ConnectionConfig, D1SessionConfig, HealthConfig, PoolConfig};
    use crate::client::backend::BackendType;

    #[test]
    fn connection_config_debug_redacts_key() {
        let debug = format!(
            "{:?}",
            ConnectionConfig::new("http://localhost:8080").with_key("super-secret")
        );

        assert!(debug.contains("<redacted>"));
        assert!(!debug.contains("super-secret"));
    }

    #[test]
    fn client_config_debug_redacts_nested_key() {
        let debug = format!(
            "{:?}",
            ClientConfig::new(
                BackendType::Native,
                Some("reporting".to_string()),
                ConnectionConfig::new("http://localhost:8080").with_key("super-secret"),
                PoolConfig::default(),
                HealthConfig::default(),
                D1SessionConfig::default(),
            )
        );

        assert!(debug.contains("<redacted>"));
        assert!(!debug.contains("super-secret"));
    }
}