d_engine/client/
builder.rs

1use std::time::Duration;
2
3use super::Client;
4use super::ClientConfig;
5use super::ClusterClient;
6use super::ConnectionPool;
7use super::KvClient;
8use crate::Result;
9
10/// Configurable builder for [`Client`] instances
11///
12/// Implements the **builder pattern** for constructing clients with
13/// customized connection parameters and timeouts.
14///
15/// # Typical Usage Flow
16/// 1. Create with `ClientBuilder::new()`
17/// 2. Chain configuration methods
18/// 3. Finalize with `.build()`
19///
20/// # Default Configuration
21/// - Compression: Enabled
22/// - Connect Timeout: 1s
23/// - Request Timeout: 3s
24pub struct ClientBuilder {
25    config: ClientConfig,
26    endpoints: Vec<String>,
27}
28
29impl ClientBuilder {
30    /// Create a new builder with default config and specified endpoints
31    pub fn new(endpoints: Vec<String>) -> Self {
32        Self {
33            config: ClientConfig::default(),
34            endpoints,
35        }
36    }
37
38    /// Set connection timeout (default: 1s)
39    pub fn connect_timeout(
40        mut self,
41        timeout: Duration,
42    ) -> Self {
43        self.config.connect_timeout = timeout;
44        self
45    }
46
47    /// Set request timeout (default: 3s)
48    pub fn request_timeout(
49        mut self,
50        timeout: Duration,
51    ) -> Self {
52        self.config.request_timeout = timeout;
53        self
54    }
55
56    /// Enable/disable compression (default: enabled)
57    pub fn enable_compression(
58        mut self,
59        enable: bool,
60    ) -> Self {
61        self.config.enable_compression = enable;
62        self
63    }
64
65    /// Completely replaces the default configuration
66    ///
67    /// # Warning: Configuration Override
68    /// This will discard all previous settings configured through individual
69    /// methods like [`connect_timeout`](ClientBuilder::connect_timeout) or
70    /// [`enable_compression`](ClientBuilder::enable_compression).
71    ///
72    /// # Usage Guidance
73    /// Choose **either**:
74    /// - Use granular configuration methods (recommended for most cases)
75    /// - Use this method to provide a full configuration object
76    ///
77    /// # Example: Full Configuration
78    /// ```no_run
79    /// use d_engine::client::{ClientBuilder, ClientConfig};
80    /// use std::time::Duration;
81    ///
82    /// let custom_config = ClientConfig {
83    ///     connect_timeout: Duration::from_secs(2),
84    ///     request_timeout: Duration::from_secs(5),
85    ///     ..ClientConfig::default()
86    /// };
87    ///
88    /// let builder = ClientBuilder::new(vec!["http://node1:9081".into()])
89    ///     .set_config(custom_config);
90    /// ```
91    pub fn set_config(
92        mut self,
93        config: ClientConfig,
94    ) -> Self {
95        self.config = config;
96        self
97    }
98
99    /// Build the client with current configuration
100    pub async fn build(self) -> Result<Client> {
101        let connection_pool = ConnectionPool::new(self.endpoints, self.config.clone()).await?;
102        Ok(Client {
103            kv: KvClient::new(self.config.id, connection_pool.clone()),
104            cluster: ClusterClient::new(connection_pool),
105        })
106    }
107}