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#[must_use = "call .build() to construct the final value"]
126#[derive(Debug, Clone)]
127pub struct ConnectionConfigBuilder {
128 pub(super) database: String,
129 pub(super) user: String,
130 pub(super) password: Option<Zeroizing<String>>,
131 pub(super) params: HashMap<String, String>,
132 pub(super) connect_timeout: Option<Duration>,
133 pub(super) statement_timeout: Option<Duration>,
134 pub(super) keepalive_idle: Option<Duration>,
135 pub(super) application_name: Option<String>,
136 pub(super) extra_float_digits: Option<i32>,
137}
138
139impl ConnectionConfigBuilder {
140 /// Set the password (automatically zeroed on drop)
141 pub fn password(mut self, password: impl Into<String>) -> Self {
142 self.password = Some(Zeroizing::new(password.into()));
143 self
144 }
145
146 /// Add a connection parameter
147 pub fn param(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
148 self.params.insert(key.into(), value.into());
149 self
150 }
151
152 /// Set TCP connection timeout
153 ///
154 /// Default: None (no timeout)
155 ///
156 /// # Arguments
157 ///
158 /// * `duration` - Timeout duration for establishing TCP connection
159 pub const fn connect_timeout(mut self, duration: Duration) -> Self {
160 self.connect_timeout = Some(duration);
161 self
162 }
163
164 /// Set statement (query) timeout
165 ///
166 /// Default: None (unlimited)
167 ///
168 /// # Arguments
169 ///
170 /// * `duration` - Timeout duration for query execution
171 pub const fn statement_timeout(mut self, duration: Duration) -> Self {
172 self.statement_timeout = Some(duration);
173 self
174 }
175
176 /// Set TCP keepalive idle interval
177 ///
178 /// Default: None (OS default)
179 ///
180 /// # Arguments
181 ///
182 /// * `duration` - Idle duration before sending keepalive probes
183 pub const fn keepalive_idle(mut self, duration: Duration) -> Self {
184 self.keepalive_idle = Some(duration);
185 self
186 }
187
188 /// Set application name for Postgres logs
189 ///
190 /// Default: None (Postgres will not set `application_name`)
191 ///
192 /// # Arguments
193 ///
194 /// * `name` - Application name to identify in Postgres logs
195 pub fn application_name(mut self, name: impl Into<String>) -> Self {
196 self.application_name = Some(name.into());
197 self
198 }
199
200 /// Set `extra_float_digits` for float precision
201 ///
202 /// Default: None (use Postgres default)
203 ///
204 /// # Arguments
205 ///
206 /// * `digits` - Number of extra digits (typically 0-2)
207 pub const fn extra_float_digits(mut self, digits: i32) -> Self {
208 self.extra_float_digits = Some(digits);
209 self
210 }
211
212 /// Build the configuration
213 pub fn build(self) -> ConnectionConfig {
214 ConnectionConfig {
215 database: self.database,
216 user: self.user,
217 password: self.password,
218 params: self.params,
219 connect_timeout: self.connect_timeout,
220 statement_timeout: self.statement_timeout,
221 keepalive_idle: self.keepalive_idle,
222 application_name: self.application_name,
223 extra_float_digits: self.extra_float_digits,
224 }
225 }
226}