Skip to main content

fraiseql_wire/connection/conn/
config.rs

1//! Connection configuration types
2
3use std::collections::HashMap;
4use std::time::Duration;
5use zeroize::Zeroizing;
6
7/// Connection configuration
8///
9/// Stores connection parameters including database, credentials, and optional timeouts.
10/// Use `ConnectionConfig::builder()` for advanced configuration with timeouts and keepalive.
11#[derive(Debug, Clone)]
12pub struct ConnectionConfig {
13    /// Database name
14    pub database: String,
15    /// Username
16    pub user: String,
17    /// Password (optional, zeroed on drop for security)
18    pub password: Option<Zeroizing<String>>,
19    /// Additional connection parameters
20    pub params: HashMap<String, String>,
21    /// TCP connection timeout (default: 10 seconds)
22    pub connect_timeout: Option<Duration>,
23    /// Query statement timeout
24    pub statement_timeout: Option<Duration>,
25    /// TCP keepalive idle interval (default: 5 minutes)
26    pub keepalive_idle: Option<Duration>,
27    /// Application name for Postgres logs (default: "fraiseql-wire")
28    pub application_name: Option<String>,
29    /// Postgres `extra_float_digits` setting
30    pub extra_float_digits: Option<i32>,
31}
32
33impl ConnectionConfig {
34    /// Create new configuration with defaults
35    ///
36    /// # Arguments
37    ///
38    /// * `database` - Database name
39    /// * `user` - Username
40    ///
41    /// # Defaults
42    ///
43    /// - `connect_timeout`: None
44    /// - `statement_timeout`: None
45    /// - `keepalive_idle`: None
46    /// - `application_name`: None
47    /// - `extra_float_digits`: None
48    ///
49    /// For configured timeouts and keepalive, use `builder()` instead.
50    pub fn new(database: impl Into<String>, user: impl Into<String>) -> Self {
51        Self {
52            database: database.into(),
53            user: user.into(),
54            password: None,
55            params: HashMap::new(),
56            connect_timeout: None,
57            statement_timeout: None,
58            keepalive_idle: None,
59            application_name: None,
60            extra_float_digits: None,
61        }
62    }
63
64    /// Create a builder for advanced configuration
65    ///
66    /// Use this to configure timeouts, keepalive, and application name.
67    ///
68    /// # Examples
69    ///
70    /// ```rust
71    /// use fraiseql_wire::connection::ConnectionConfig;
72    /// use std::time::Duration;
73    /// let config = ConnectionConfig::builder("mydb", "user")
74    ///     .connect_timeout(Duration::from_secs(10))
75    ///     .statement_timeout(Duration::from_secs(30))
76    ///     .build();
77    /// ```
78    pub fn builder(
79        database: impl Into<String>,
80        user: impl Into<String>,
81    ) -> ConnectionConfigBuilder {
82        ConnectionConfigBuilder {
83            database: database.into(),
84            user: user.into(),
85            password: None,
86            params: HashMap::new(),
87            connect_timeout: None,
88            statement_timeout: None,
89            keepalive_idle: None,
90            application_name: None,
91            extra_float_digits: None,
92        }
93    }
94
95    /// Set password (automatically zeroed on drop)
96    pub fn password(mut self, password: impl Into<String>) -> Self {
97        self.password = Some(Zeroizing::new(password.into()));
98        self
99    }
100
101    /// Add connection parameter
102    pub fn param(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
103        self.params.insert(key.into(), value.into());
104        self
105    }
106}
107
108/// Builder for creating `ConnectionConfig` with advanced options
109///
110/// Provides a fluent API for configuring timeouts, keepalive, and application name.
111///
112/// # Examples
113///
114/// ```rust
115/// use fraiseql_wire::connection::ConnectionConfig;
116/// use std::time::Duration;
117/// let config = ConnectionConfig::builder("mydb", "user")
118///     .password("secret")
119///     .connect_timeout(Duration::from_secs(10))
120///     .statement_timeout(Duration::from_secs(30))
121///     .keepalive_idle(Duration::from_secs(300))
122///     .application_name("my_app")
123///     .build();
124/// ```
125#[derive(Debug, Clone)]
126pub struct ConnectionConfigBuilder {
127    pub(super) database: String,
128    pub(super) user: String,
129    pub(super) password: Option<Zeroizing<String>>,
130    pub(super) params: HashMap<String, String>,
131    pub(super) connect_timeout: Option<Duration>,
132    pub(super) statement_timeout: Option<Duration>,
133    pub(super) keepalive_idle: Option<Duration>,
134    pub(super) application_name: Option<String>,
135    pub(super) extra_float_digits: Option<i32>,
136}
137
138impl ConnectionConfigBuilder {
139    /// Set the password (automatically zeroed on drop)
140    pub fn password(mut self, password: impl Into<String>) -> Self {
141        self.password = Some(Zeroizing::new(password.into()));
142        self
143    }
144
145    /// Add a connection parameter
146    pub fn param(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
147        self.params.insert(key.into(), value.into());
148        self
149    }
150
151    /// Set TCP connection timeout
152    ///
153    /// Default: None (no timeout)
154    ///
155    /// # Arguments
156    ///
157    /// * `duration` - Timeout duration for establishing TCP connection
158    pub const fn connect_timeout(mut self, duration: Duration) -> Self {
159        self.connect_timeout = Some(duration);
160        self
161    }
162
163    /// Set statement (query) timeout
164    ///
165    /// Default: None (unlimited)
166    ///
167    /// # Arguments
168    ///
169    /// * `duration` - Timeout duration for query execution
170    pub const fn statement_timeout(mut self, duration: Duration) -> Self {
171        self.statement_timeout = Some(duration);
172        self
173    }
174
175    /// Set TCP keepalive idle interval
176    ///
177    /// Default: None (OS default)
178    ///
179    /// # Arguments
180    ///
181    /// * `duration` - Idle duration before sending keepalive probes
182    pub const fn keepalive_idle(mut self, duration: Duration) -> Self {
183        self.keepalive_idle = Some(duration);
184        self
185    }
186
187    /// Set application name for Postgres logs
188    ///
189    /// Default: None (Postgres will not set `application_name`)
190    ///
191    /// # Arguments
192    ///
193    /// * `name` - Application name to identify in Postgres logs
194    pub fn application_name(mut self, name: impl Into<String>) -> Self {
195        self.application_name = Some(name.into());
196        self
197    }
198
199    /// Set `extra_float_digits` for float precision
200    ///
201    /// Default: None (use Postgres default)
202    ///
203    /// # Arguments
204    ///
205    /// * `digits` - Number of extra digits (typically 0-2)
206    pub const fn extra_float_digits(mut self, digits: i32) -> Self {
207        self.extra_float_digits = Some(digits);
208        self
209    }
210
211    /// Build the configuration
212    pub fn build(self) -> ConnectionConfig {
213        ConnectionConfig {
214            database: self.database,
215            user: self.user,
216            password: self.password,
217            params: self.params,
218            connect_timeout: self.connect_timeout,
219            statement_timeout: self.statement_timeout,
220            keepalive_idle: self.keepalive_idle,
221            application_name: self.application_name,
222            extra_float_digits: self.extra_float_digits,
223        }
224    }
225}