elif_http/
database.rs

1//! Database Integration - Service providers for database connectivity
2//! 
3//! Provides service providers for PostgreSQL connection pooling and ORM integration
4//! with the DI container system.
5
6use std::sync::Arc;
7use sqlx::{Pool, Postgres, postgres::PgPoolOptions};
8use elif_core::{ServiceProvider, Container, ContainerBuilder};
9use crate::{HttpError, HttpResult};
10
11/// Database service provider for PostgreSQL connection pool
12pub struct DatabaseServiceProvider {
13    database_url: String,
14    max_connections: u32,
15    min_connections: u32,
16    acquire_timeout: u64,
17    service_name: String,
18}
19
20impl DatabaseServiceProvider {
21    pub fn new(database_url: String) -> Self {
22        Self {
23            database_url,
24            max_connections: 10,
25            min_connections: 1,
26            acquire_timeout: 30,
27            service_name: "database_pool".to_string(),
28        }
29    }
30
31    pub fn with_max_connections(mut self, max_connections: u32) -> Self {
32        self.max_connections = max_connections;
33        self
34    }
35
36    pub fn with_min_connections(mut self, min_connections: u32) -> Self {
37        self.min_connections = min_connections;
38        self
39    }
40
41    pub fn with_acquire_timeout(mut self, timeout_seconds: u64) -> Self {
42        self.acquire_timeout = timeout_seconds;
43        self
44    }
45
46    pub fn with_service_name(mut self, service_name: String) -> Self {
47        self.service_name = service_name;
48        self
49    }
50}
51
52impl ServiceProvider for DatabaseServiceProvider {
53    fn name(&self) -> &'static str {
54        "DatabaseServiceProvider"
55    }
56    
57    fn register(&self, builder: ContainerBuilder) -> Result<ContainerBuilder, elif_core::ProviderError> {
58        // For now, return the builder unchanged
59        // In a real implementation, we would register the database pool here
60        Ok(builder)
61    }
62    
63    fn boot(&self, _container: &Container) -> Result<(), elif_core::ProviderError> {
64        // For now, just log that the database provider is booted
65        println!("✅ Database service provider booted");
66        Ok(())
67    }
68}
69
70/// Helper function to create a database pool directly
71pub async fn create_database_pool(database_url: &str) -> Result<Arc<Pool<Postgres>>, HttpError> {
72    let pool = PgPoolOptions::new()
73        .max_connections(10)
74        .min_connections(1)
75        .acquire_timeout(std::time::Duration::from_secs(30))
76        .connect(database_url)
77        .await
78        .map_err(|e| HttpError::database_error(format!("Failed to create database pool: {}", e)))?;
79    
80    Ok(Arc::new(pool))
81}
82
83/// Helper function to get database pool from container (for future implementation)
84pub async fn get_database_pool(container: &Container) -> Result<Arc<Pool<Postgres>>, String> {
85    // For now, return an error since the container doesn't have service registry yet
86    Err("Database pool not yet integrated with current Container implementation".to_string())
87}
88
89/// Helper function to get custom named database pool from container (for future implementation)  
90pub async fn get_named_database_pool(
91    container: &Container, 
92    service_name: &str
93) -> Result<Arc<Pool<Postgres>>, String> {
94    // For now, return an error since the container doesn't have service registry yet
95    Err(format!("Database pool '{}' not yet integrated with current Container implementation", service_name))
96}
97
98#[cfg(test)]
99mod tests {
100    use super::*;
101
102    #[test]
103    fn test_database_service_provider_creation() {
104        let provider = DatabaseServiceProvider::new("postgresql://test".to_string());
105        assert_eq!(provider.database_url, "postgresql://test");
106        assert_eq!(provider.max_connections, 10);
107        assert_eq!(provider.min_connections, 1);
108        assert_eq!(provider.acquire_timeout, 30);
109        assert_eq!(provider.service_name, "database_pool");
110    }
111
112    #[test]
113    fn test_database_service_provider_configuration() {
114        let provider = DatabaseServiceProvider::new("postgresql://test".to_string())
115            .with_max_connections(20)
116            .with_min_connections(5)
117            .with_acquire_timeout(60)
118            .with_service_name("custom_db".to_string());
119
120        assert_eq!(provider.max_connections, 20);
121        assert_eq!(provider.min_connections, 5);
122        assert_eq!(provider.acquire_timeout, 60);
123        assert_eq!(provider.service_name, "custom_db");
124    }
125
126    #[test]
127    fn test_provider_name() {
128        let provider = DatabaseServiceProvider::new("postgresql://test".to_string());
129        assert_eq!(provider.name(), "DatabaseServiceProvider");
130    }
131}