1use std::time::Duration;
4
5use crate::error::{Error, Result};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
9pub enum WireCrypt {
10 Disabled,
12 #[default]
15 Enabled,
16 Required,
18}
19
20#[derive(Debug, Clone)]
22pub struct ConnectConfig {
23 pub host: String,
25 pub port: u16,
27 pub database: String,
29 pub user: String,
31 pub password: String,
33 pub role: Option<String>,
35 pub charset: String,
37 pub dialect: i32,
39 pub wire_crypt: WireCrypt,
41 pub connect_timeout: Option<Duration>,
43 pub page_size: Option<i32>,
45 pub timezone: Option<String>,
47 pub parallel_workers: Option<i32>,
49 pub native_data_types: bool,
54}
55
56impl Default for ConnectConfig {
57 fn default() -> Self {
58 ConnectConfig {
59 host: "localhost".to_string(),
60 port: 3050,
61 database: String::new(),
62 user: "SYSDBA".to_string(),
63 password: String::new(),
64 role: None,
65 charset: "UTF8".to_string(),
66 dialect: 3,
67 wire_crypt: WireCrypt::default(),
68 connect_timeout: Some(Duration::from_secs(15)),
69 page_size: None,
70 timezone: None,
71 parallel_workers: None,
72 native_data_types: false,
73 }
74 }
75}
76
77impl ConnectConfig {
78 pub fn new() -> Self {
80 Self::default()
81 }
82
83 pub fn host(mut self, host: impl Into<String>) -> Self {
85 self.host = host.into();
86 self
87 }
88 pub fn port(mut self, port: u16) -> Self {
90 self.port = port;
91 self
92 }
93 pub fn database(mut self, db: impl Into<String>) -> Self {
95 self.database = db.into();
96 self
97 }
98 pub fn user(mut self, user: impl Into<String>) -> Self {
100 self.user = user.into();
101 self
102 }
103 pub fn password(mut self, password: impl Into<String>) -> Self {
105 self.password = password.into();
106 self
107 }
108 pub fn role(mut self, role: impl Into<String>) -> Self {
110 self.role = Some(role.into());
111 self
112 }
113 pub fn charset(mut self, charset: impl Into<String>) -> Self {
115 self.charset = charset.into();
116 self
117 }
118 pub fn dialect(mut self, dialect: i32) -> Self {
120 self.dialect = dialect;
121 self
122 }
123 pub fn wire_crypt(mut self, wc: WireCrypt) -> Self {
125 self.wire_crypt = wc;
126 self
127 }
128 pub fn connect_timeout(mut self, t: Duration) -> Self {
130 self.connect_timeout = Some(t);
131 self
132 }
133 pub fn page_size(mut self, size: i32) -> Self {
135 self.page_size = Some(size);
136 self
137 }
138 pub fn timezone(mut self, tz: impl Into<String>) -> Self {
140 self.timezone = Some(tz.into());
141 self
142 }
143 pub fn parallel_workers(mut self, n: i32) -> Self {
145 self.parallel_workers = Some(n);
146 self
147 }
148 pub fn native_data_types(mut self, on: bool) -> Self {
151 self.native_data_types = on;
152 self
153 }
154
155 pub(crate) fn normalized_user(&self) -> String {
158 self.user.to_uppercase()
159 }
160
161 pub(crate) fn validate(&self) -> Result<()> {
166 check_clumplet_len("user", &self.normalized_user())?;
168 check_clumplet_len("password", &self.password)?;
169 check_clumplet_len("charset", &self.charset)?;
170 if let Some(role) = &self.role {
171 check_clumplet_len("role", role)?;
172 }
173 if let Some(tz) = &self.timezone {
174 check_clumplet_len("timezone", tz)?;
175 }
176 Ok(())
177 }
178}
179
180fn check_clumplet_len(field: &str, value: &str) -> Result<()> {
182 if value.len() > u8::MAX as usize {
183 return Err(Error::conversion(format!(
184 "{field} excede 255 bytes ({}); não cabe num parâmetro de conexão",
185 value.len()
186 )));
187 }
188 Ok(())
189}
190
191#[cfg(test)]
192mod tests {
193 use super::*;
194
195 #[test]
196 fn default_config_is_valid() {
197 assert!(ConnectConfig::new().user("SYSDBA").validate().is_ok());
198 }
199
200 #[test]
201 fn over_long_password_is_rejected() {
202 let cfg = ConnectConfig::new().password("x".repeat(256));
203 let err = cfg.validate().unwrap_err();
204 assert!(
205 matches!(err, Error::Conversion(_)),
206 "esperava erro de conversão, veio {err:?}"
207 );
208 }
209
210 #[test]
211 fn max_length_fields_pass() {
212 let cfg = ConnectConfig::new()
213 .role("r".repeat(255))
214 .charset("c".repeat(255));
215 assert!(cfg.validate().is_ok());
216 }
217}