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}