1use std::sync::Arc;
7use sqlx::{Pool, Postgres, postgres::PgPoolOptions};
8use elif_core::{ServiceProvider, Container, ContainerBuilder};
9use crate::{HttpError, HttpResult};
10
11pub 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 Ok(builder)
61 }
62
63 fn boot(&self, _container: &Container) -> Result<(), elif_core::ProviderError> {
64 println!("✅ Database service provider booted");
66 Ok(())
67 }
68}
69
70pub 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
83pub async fn get_database_pool(container: &Container) -> Result<Arc<Pool<Postgres>>, String> {
85 Err("Database pool not yet integrated with current Container implementation".to_string())
87}
88
89pub async fn get_named_database_pool(
91 container: &Container,
92 service_name: &str
93) -> Result<Arc<Pool<Postgres>>, String> {
94 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}