Skip to main content

solidb_client/client/
builder.rs

1use super::DriverError;
2use super::SoliDBClient;
3use super::HttpClient;
4
5pub struct SoliDBClientBuilder {
6    addr: String,
7    auth: Option<AuthMethod>,
8    timeout_ms: Option<u64>,
9    pool_size: Option<usize>,
10    transport: Transport,
11}
12
13pub enum AuthMethod {
14    UsernamePassword {
15        database: String,
16        username: String,
17        password: String,
18    },
19    ApiKey {
20        database: String,
21        api_key: String,
22    },
23}
24
25#[derive(Clone, Copy, Default)]
26pub enum Transport {
27    #[default]
28    Http,
29    Tcp,
30}
31
32impl SoliDBClientBuilder {
33    pub fn new(addr: &str) -> Self {
34        let addr = addr.to_string();
35        let is_http = addr.starts_with("http://") || addr.starts_with("https://");
36
37        Self {
38            addr,
39            auth: None,
40            timeout_ms: None,
41            pool_size: None,
42            transport: if is_http { Transport::Http } else { Transport::Tcp },
43        }
44    }
45
46    pub fn auth(mut self, database: &str, username: &str, password: &str) -> Self {
47        self.auth = Some(AuthMethod::UsernamePassword {
48            database: database.to_string(),
49            username: username.to_string(),
50            password: password.to_string(),
51        });
52        self
53    }
54
55    pub fn auth_with_api_key(mut self, database: &str, api_key: &str) -> Self {
56        self.auth = Some(AuthMethod::ApiKey {
57            database: database.to_string(),
58            api_key: api_key.to_string(),
59        });
60        self
61    }
62
63    pub fn timeout_ms(mut self, ms: u64) -> Self {
64        self.timeout_ms = Some(ms);
65        self
66    }
67
68    pub fn pool_size(mut self, size: usize) -> Self {
69        self.pool_size = Some(size);
70        self
71    }
72
73    pub fn use_http(mut self) -> Self {
74        self.transport = Transport::Http;
75        self
76    }
77
78    pub fn use_tcp(mut self) -> Self {
79        self.transport = Transport::Tcp;
80        self
81    }
82
83    pub async fn build_http(self) -> Result<HttpClient, DriverError> {
84        let mut client = HttpClient::new(&self.addr);
85
86        if let Some(database) = self.auth.as_ref().map(|a| match a {
87            AuthMethod::UsernamePassword { database, .. } => database.clone(),
88            AuthMethod::ApiKey { database, .. } => database.clone(),
89        }) {
90            client.set_database(&database);
91        }
92
93        if let Some(auth) = self.auth {
94            match auth {
95                AuthMethod::UsernamePassword {
96                    database,
97                    username,
98                    password,
99                } => {
100                    client.login(&database, &username, &password).await?;
101                }
102                AuthMethod::ApiKey { database, api_key } => {
103                    let mut http_client = HttpClient::new(&self.addr);
104                    http_client.set_database(&database);
105                    http_client.set_token(&api_key);
106                    return Ok(http_client);
107                }
108            }
109        }
110
111        Ok(client)
112    }
113
114    pub async fn build(self) -> Result<SoliDBClient, DriverError> {
115        match self.transport {
116            Transport::Http => {
117                let _ = self.build_http().await?;
118                Err(DriverError::ProtocolError(
119                    "Use build_http() for HTTP transport. For TCP, use .use_tcp() or a host:port address.".to_string(),
120                ))
121            }
122            Transport::Tcp => {
123                let pool_size = self.pool_size.unwrap_or(4);
124                let mut client = SoliDBClient::connect_with_pool(&self.addr, pool_size).await?;
125
126                if let Some(auth) = self.auth {
127                    match auth {
128                        AuthMethod::UsernamePassword {
129                            database,
130                            username,
131                            password,
132                        } => {
133                            client.auth(&database, &username, &password).await?;
134                        }
135                        AuthMethod::ApiKey { database, api_key } => {
136                            client.auth_with_api_key(&database, &api_key).await?;
137                        }
138                    }
139                }
140
141                Ok(client)
142            }
143        }
144    }
145
146    pub async fn build_with_transport(self) -> Result<SoliDBClient, DriverError> {
147        match self.transport {
148            Transport::Http => {
149                let _ = self.build_http().await?;
150                Err(DriverError::ProtocolError(
151                    "HTTP transport selected but build() was called. Use build_http() instead.".to_string(),
152                ))
153            }
154            Transport::Tcp => self.build().await,
155        }
156    }
157}