pg-api 0.2.0

A high-performance PostgreSQL REST API driver with rate limiting, connection pooling, and observability
use deadpool_postgres::{Config, Pool, Runtime};
use tokio_postgres::NoTls;
use std::sync::Arc;
use tokio::sync::Semaphore;
use tracing::info;

use crate::config::PoolConfig;

/// Pool global de conexões PostgreSQL
#[derive(Clone)]
pub struct GlobalPool {
    /// Pool de conexões deadpool
    inner: Pool,
    /// Configuração do pool
    config: PoolConfig,
    /// Semáforo para controle de acesso ao pool
    semaphore: Arc<Semaphore>,
}

impl GlobalPool {
    /// Cria um novo GlobalPool com a configuração fornecida
    pub async fn new(config: PoolConfig) -> anyhow::Result<Self> {
        info!("Initializing GlobalPool with max_connections={}", config.max_connections);
        
        // Configuração do PostgreSQL
        let pg_host = std::env::var("PG__HOST").unwrap_or_else(|_| "localhost".to_string());
        let pg_port = std::env::var("PG__PORT")
            .ok()
            .and_then(|p| p.parse().ok())
            .unwrap_or(5432);
        let pg_db = std::env::var("PG__DB").unwrap_or_else(|_| "camera".to_string());
        let pg_user = std::env::var("PG__USER").unwrap_or_else(|_| "postgres".to_string());
        let pg_pass = std::env::var("PG__PASSWORD").unwrap_or_else(|_| "".to_string());
        
        let mut pg_config = Config::new();
        pg_config.host = Some(pg_host);
        pg_config.port = Some(pg_port);
        pg_config.dbname = Some(pg_db);
        pg_config.user = Some(pg_user);
        pg_config.password = Some(pg_pass);
        
        // Cria o pool com runtime explícito
        let inner = pg_config.create_pool(Some(Runtime::Tokio1), NoTls)
            .map_err(|e| anyhow::anyhow!("Failed to create pool: {}", e))?;
        
        let semaphore = Arc::new(Semaphore::new(config.max_connections));
        
        let pool = Self {
            inner,
            config,
            semaphore,
        };
        
        info!("GlobalPool initialized successfully");
        Ok(pool)
    }
    
    /// Obtém uma conexão do pool (bloqueante com timeout)
    pub async fn get_connection(&self) -> Result<deadpool_postgres::Client, deadpool_postgres::PoolError> {
        self.inner.get().await
    }
    
    /// Tenta adquirir uma conexão sem bloquear
    pub async fn try_get_connection(&self) -> Option<deadpool_postgres::Client> {
        (self.inner.get().await).ok()
    }
    
    /// Verifica se o pool está cheio
    pub fn is_full(&self) -> bool {
        self.inner.status().available == 0
    }
    
    /// Retorna estatísticas do pool
    pub fn stats(&self) -> deadpool_postgres::Status {
        self.inner.status()
    }
    
    /// Retorna a configuração
    pub fn config(&self) -> &PoolConfig {
        &self.config
    }
    
    /// Retorna o semáforo para controle de acesso
    pub fn semaphore(&self) -> &Arc<Semaphore> {
        &self.semaphore
    }
}