1use std::{borrow::Cow, num::NonZeroUsize, ops::Not};
2
3use serde::{Deserialize, Deserializer, Serialize};
4
5#[derive(Clone, Debug)]
14pub struct ExaAttributes {
15 read_write: ExaRwAttributes<'static>,
16 read_only: ExaRoAttributes,
17 driver: ExaDriverAttributes,
18}
19
20impl ExaAttributes {
21 pub(crate) fn new(
22 compression_enabled: bool,
23 fetch_size: usize,
24 encryption_enabled: bool,
25 statement_cache_capacity: NonZeroUsize,
26 ) -> Self {
27 Self {
28 read_write: ExaRwAttributes::default(),
29 read_only: ExaRoAttributes::new(compression_enabled),
30 driver: ExaDriverAttributes::new(
31 fetch_size,
32 encryption_enabled,
33 statement_cache_capacity,
34 ),
35 }
36 }
37
38 #[must_use]
39 pub fn autocommit(&self) -> bool {
40 self.read_write.autocommit
41 }
42
43 #[deprecated = "use Connection::begin() to start a transaction"]
44 pub fn set_autocommit(&mut self, autocommit: bool) -> &mut Self {
45 self.driver.needs_send = true;
46 self.read_write.autocommit = autocommit;
47 self.driver.open_transaction = !autocommit;
48 self
49 }
50
51 #[must_use]
52 pub fn current_schema(&self) -> Option<&str> {
53 self.read_write.current_schema.as_deref()
54 }
55
56 pub fn set_current_schema(&mut self, schema: String) -> &mut Self {
62 self.driver.needs_send = true;
63 self.read_write.current_schema = Some(schema.into());
64 self
65 }
66
67 #[must_use]
68 pub fn feedback_interval(&self) -> u64 {
69 self.read_write.feedback_interval
70 }
71
72 pub fn set_feedback_interval(&mut self, feedback_interval: u64) -> &mut Self {
73 self.driver.needs_send = true;
74 self.read_write.feedback_interval = feedback_interval;
75 self
76 }
77
78 #[must_use]
79 pub fn numeric_characters(&self) -> &str {
80 &self.read_write.numeric_characters
81 }
82
83 pub fn set_numeric_characters(&mut self, numeric_characters: String) -> &mut Self {
84 self.driver.needs_send = true;
85 self.read_write.numeric_characters = numeric_characters.into();
86 self
87 }
88
89 #[must_use]
90 pub fn query_timeout(&self) -> u64 {
91 self.read_write.query_timeout
92 }
93
94 #[must_use]
95 pub fn set_query_timeout(&mut self, query_timeout: u64) -> &mut Self {
96 self.driver.needs_send = true;
97 self.read_write.query_timeout = query_timeout;
98 self
99 }
100
101 #[must_use]
102 pub fn snapshot_transactions_enabled(&self) -> bool {
103 self.read_write.snapshot_transactions_enabled
104 }
105
106 pub fn set_snapshot_transactions_enabled(&mut self, enabled: bool) -> &mut Self {
107 self.driver.needs_send = true;
108 self.read_write.snapshot_transactions_enabled = enabled;
109 self
110 }
111
112 #[must_use]
113 pub fn timestamp_utc_enabled(&self) -> bool {
114 self.read_write.timestamp_utc_enabled
115 }
116
117 pub fn set_timestamp_utc_enabled(&mut self, enabled: bool) -> &mut Self {
118 self.driver.needs_send = true;
119 self.read_write.timestamp_utc_enabled = enabled;
120 self
121 }
122
123 #[must_use]
124 pub fn compression_enabled(&self) -> bool {
125 self.read_only.compression_enabled
126 }
127
128 #[must_use]
129 pub fn date_format(&self) -> &str {
130 &self.read_only.date_format
131 }
132
133 #[must_use]
134 pub fn date_language(&self) -> &str {
135 &self.read_only.date_language
136 }
137
138 #[must_use]
139 pub fn datetime_format(&self) -> &str {
140 &self.read_only.datetime_format
141 }
142
143 #[must_use]
144 pub fn default_like_escape_character(&self) -> &str {
145 &self.read_only.default_like_escape_character
146 }
147
148 #[must_use]
149 pub fn timezone(&self) -> &str {
150 &self.read_only.timezone
151 }
152
153 #[must_use]
154 pub fn timezone_behavior(&self) -> &str {
155 &self.read_only.timezone_behavior
156 }
157
158 #[must_use]
159 pub fn open_transaction(&self) -> bool {
160 self.driver.open_transaction
161 }
162
163 #[must_use]
164 pub fn fetch_size(&self) -> usize {
165 self.driver.fetch_size
166 }
167
168 pub fn set_fetch_size(&mut self, fetch_size: usize) -> &mut Self {
169 self.driver.fetch_size = fetch_size;
170 self
171 }
172
173 #[must_use]
174 pub fn encryption_enabled(&self) -> bool {
175 self.driver.encryption_enabled
176 }
177
178 #[must_use]
179 pub fn statement_cache_capacity(&self) -> NonZeroUsize {
180 self.driver.statement_cache_capacity
181 }
182
183 pub(crate) fn needs_send(&self) -> bool {
184 self.driver.needs_send
185 }
186
187 pub(crate) fn set_needs_send(&mut self, flag: bool) -> &mut Self {
188 self.driver.needs_send = flag;
189 self
190 }
191
192 pub(crate) fn read_write(&self) -> &ExaRwAttributes<'static> {
193 &self.read_write
194 }
195
196 pub(crate) fn update(&mut self, other: ExaAttributesOpt) {
197 macro_rules! other_or_prev {
198 ($kind:tt, $field:tt) => {
199 if let Some(new) = other.$field {
200 self.$kind.$field = new.into();
201 }
202 };
203 }
204
205 self.read_write.current_schema = other.current_schema.map(From::from);
206
207 other_or_prev!(read_write, autocommit);
208 other_or_prev!(read_write, feedback_interval);
209 other_or_prev!(read_write, numeric_characters);
210 other_or_prev!(read_write, query_timeout);
211 other_or_prev!(read_write, snapshot_transactions_enabled);
212 other_or_prev!(read_write, timestamp_utc_enabled);
213 other_or_prev!(read_only, compression_enabled);
214 other_or_prev!(read_only, date_format);
215 other_or_prev!(read_only, date_language);
216 other_or_prev!(read_only, datetime_format);
217 other_or_prev!(read_only, default_like_escape_character);
218 other_or_prev!(read_only, timezone);
219 other_or_prev!(read_only, timezone_behavior);
220 }
221}
222
223#[derive(Clone, Debug, Serialize)]
228#[serde(rename_all = "camelCase")]
229pub struct ExaRwAttributes<'a> {
230 #[serde(skip_serializing_if = "Option::is_none")]
233 current_schema: Option<Cow<'a, str>>,
234 autocommit: bool,
235 feedback_interval: u64,
236 numeric_characters: Cow<'a, str>,
237 query_timeout: u64,
238 snapshot_transactions_enabled: bool,
239 timestamp_utc_enabled: bool,
240}
241
242impl<'a> ExaRwAttributes<'a> {
243 pub(crate) fn new(
244 current_schema: Option<Cow<'a, str>>,
245 feedback_interval: u64,
246 query_timeout: u64,
247 ) -> Self {
248 Self {
249 current_schema,
250 feedback_interval,
251 query_timeout,
252 ..Default::default()
253 }
254 }
255}
256
257impl<'a> Default for ExaRwAttributes<'a> {
258 fn default() -> Self {
259 Self {
260 autocommit: true,
261 current_schema: None,
262 feedback_interval: 1,
263 numeric_characters: Cow::Owned(".,".into()),
264 query_timeout: 0,
265 snapshot_transactions_enabled: false,
266 timestamp_utc_enabled: false,
267 }
268 }
269}
270
271#[derive(Clone, Debug)]
272struct ExaRoAttributes {
273 compression_enabled: bool,
274 date_format: String,
275 date_language: String,
276 datetime_format: String,
277 default_like_escape_character: String,
278 timezone: String,
279 timezone_behavior: String,
280}
281
282impl ExaRoAttributes {
283 fn new(compression_enabled: bool) -> Self {
284 Self {
285 compression_enabled,
286 date_format: "YYYY-MM-DD".to_owned(),
287 date_language: "ENG".to_owned(),
288 datetime_format: "YYYY-MM-DD HH24:MI:SS.FF6".to_owned(),
289 default_like_escape_character: "\\".to_owned(),
290 timezone: "UNIVERSAL".to_owned(),
291 timezone_behavior: "INVALID SHIFT AMBIGUOUS ST".to_owned(),
292 }
293 }
294}
295
296#[derive(Clone, Debug)]
297struct ExaDriverAttributes {
298 open_transaction: bool,
301 needs_send: bool,
302 fetch_size: usize,
303 encryption_enabled: bool,
304 statement_cache_capacity: NonZeroUsize,
305}
306
307impl ExaDriverAttributes {
308 fn new(
309 fetch_size: usize,
310 encryption_enabled: bool,
311 statement_cache_capacity: NonZeroUsize,
312 ) -> Self {
313 Self {
314 open_transaction: false,
315 needs_send: false,
316 fetch_size,
317 encryption_enabled,
318 statement_cache_capacity,
319 }
320 }
321}
322
323#[derive(Debug, Default, Deserialize)]
330#[serde(rename_all = "camelCase")]
331pub struct ExaAttributesOpt {
332 autocommit: Option<bool>,
336 #[serde(default)]
337 #[serde(deserialize_with = "ExaAttributesOpt::deserialize_current_schema")]
338 current_schema: Option<String>,
339 feedback_interval: Option<u64>,
340 numeric_characters: Option<String>,
341 query_timeout: Option<u64>,
342 snapshot_transactions_enabled: Option<bool>,
343 timestamp_utc_enabled: Option<bool>,
344 compression_enabled: Option<bool>,
348 date_format: Option<String>,
349 date_language: Option<String>,
350 datetime_format: Option<String>,
351 default_like_escape_character: Option<String>,
352 timezone: Option<String>,
353 timezone_behavior: Option<String>,
354}
355
356impl ExaAttributesOpt {
357 fn deserialize_current_schema<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
359 where
360 D: Deserializer<'de>,
361 {
362 let Some(value) = Option::deserialize(deserializer)? else {
363 return Ok(None);
364 };
365
366 Ok(String::is_empty(&value).not().then_some(value))
367 }
368}