clickhouse_arrow/
settings.rs

1/// Manages `ClickHouse` query settings for the native protocol.
2///
3/// This module provides types and methods to define, manipulate, and serialize
4/// `ClickHouse` query settings, which are key-value pairs sent with queries to
5/// configure server behavior (e.g., `max_threads`, `allow_experimental_features`).
6/// The [`Settings`] struct holds a collection of [`Setting`]s, each representing
7/// a key, value, and optional flags (`important`, `custom`). The [`SettingValue`]
8/// enum supports various data types (integers, booleans, floats, strings) with
9/// conversions from Rust primitives.
10///
11/// # Features
12/// - Converts Rust primitives (e.g., `i32`, `&str`, `bool`) to [`SettingValue`] using the
13///   `From` trait.
14/// - Serializes settings to the `ClickHouse` native protocol, supporting both legacy
15///   (pre-revision 54429) and modern formats.
16/// - Optional `serde` integration for serialization/deserialization (enabled with the `serde`
17///   feature).
18///
19/// # `ClickHouse` Documentation
20/// - For a list of available query settings, see the [ClickHouse Settings Reference](https://clickhouse.com/docs/en/operations/settings).
21/// - For details on the native protocol’s settings serialization, see the [ClickHouse Native Protocol Documentation](https://clickhouse.com/docs/en/interfaces/tcp).
22///
23/// # Example
24/// ```rust,ignore
25/// use clickhouse_arrow::query::settings::Settings;
26///
27/// // Create settings with key-value pairs
28/// let mut settings = Settings::from([
29///     ("max_threads".to_string(), 8_i32),
30///     ("allow_experimental_features".to_string(), true),
31/// ]);
32///
33/// // Add a setting
34/// settings.add_setting("max_execution_time", 300_i64);
35///
36/// // Convert to key-value strings
37/// let kv_pairs = settings.encode_to_key_value_strings();
38/// assert_eq!(kv_pairs, vec![
39///     ("max_threads".to_string(), "8".to_string()),
40///     ("allow_experimental_features".to_string(), "true".to_string()),
41///     ("max_execution_time".to_string(), "300".to_string()),
42/// ]);
43/// ```
44///
45/// # Notes
46/// - Settings are serialized according to the `ClickHouse` server’s protocol revision. For
47///   revisions ≤ 54429, only integer and boolean settings are supported.
48/// - The `serde` feature enables serialization/deserialization of [`Setting`] and [`Settings`]
49///   with `serde::Serialize` and `serde::Deserialize`.
50use std::fmt;
51
52use crate::io::{ClickHouseRead, ClickHouseWrite};
53use crate::native::protocol::DBMS_MIN_REVISION_WITH_SETTINGS_SERIALIZED_AS_STRINGS;
54use crate::{Error, Result};
55
56const SETTING_FLAG_IMPORTANT: u64 = 0x01;
57pub(crate) const SETTING_FLAG_CUSTOM: u64 = 0x02;
58
59/// Supported value types for `ClickHouse` query settings.
60///
61/// This enum represents the possible data types for a [`Setting`]'s value, including
62/// integers, booleans, floats, and strings. It implements `From` for various Rust
63/// primitive types (e.g., `i32`, `&str`, `f64`) to simplify setting creation.
64///
65/// # Variants
66/// - `Int(i64)`: A 64-bit integer (e.g., for `max_threads`).
67/// - `Bool(bool)`: A boolean (e.g., for `allow_experimental_features`).
68/// - `Float(f64)`: A 64-bit float (e.g., for `quantile`).
69/// - `String(String)`: A string (e.g., for `default_format`).
70///
71/// # Example
72/// ```rust,ignore
73/// use clickhouse_arrow::query::settings::SettingValue;
74///
75/// let int_value: SettingValue = 8_i32.into();
76/// let bool_value: SettingValue = true.into();
77/// let string_value: SettingValue = "JSON".to_string().into();
78/// assert!(matches!(int_value, SettingValue::Int(8)));
79/// ```
80#[derive(Debug, Clone, PartialEq, PartialOrd)]
81pub enum SettingValue {
82    Int(i64),
83    Bool(bool),
84    Float(f64),
85    String(String),
86}
87
88impl SettingValue {
89    // Helper to extract f64 from Float variant for testing
90    #[allow(unused)]
91    pub(crate) fn unwrap_float(&self) -> f64 {
92        match self {
93            SettingValue::Float(f) => *f,
94            _ => panic!("Expected Float variant"),
95        }
96    }
97}
98
99impl Eq for SettingValue {}
100
101macro_rules! setting_value {
102    ($ty:ident, $inner:ty) => {
103        impl From<$inner> for SettingValue {
104            fn from(value: $inner) -> Self { SettingValue::$ty(value) }
105        }
106    };
107    ($ty:ident, $inner:ty, $override:ty) => {
108        impl From<$override> for SettingValue {
109            #[allow(clippy::cast_lossless)]
110            #[allow(clippy::cast_possible_wrap)]
111            fn from(value: $override) -> Self { SettingValue::$ty(value as $inner) }
112        }
113    };
114    ($ty:ident, $inner:ty, $v:tt =>  { $override:expr }) => {
115        impl From<$inner> for SettingValue {
116            fn from($v: $inner) -> Self { SettingValue::$ty($override) }
117        }
118    };
119}
120
121setting_value!(Int, i64, u8);
122setting_value!(Int, i64, u16);
123setting_value!(Int, i64, u32);
124setting_value!(Int, i64, u64);
125setting_value!(Int, i64, i8);
126setting_value!(Int, i64, i16);
127setting_value!(Int, i64, i32);
128setting_value!(Int, i64);
129setting_value!(Bool, bool);
130setting_value!(Float, f64, f32);
131setting_value!(Float, f64);
132setting_value!(String, &str, v => { v.to_string() });
133setting_value!(String, Box<str>, v => { v.to_string() });
134setting_value!(String, std::sync::Arc<str>, v => { v.to_string() });
135setting_value!(String, String);
136
137// Array conversions - serialize to field dump format for ClickHouse parameters
138macro_rules! setting_value_array {
139    ($ty:ty) => {
140        impl From<Vec<$ty>> for SettingValue {
141            fn from(value: Vec<$ty>) -> Self {
142                let formatted = value.iter().map(ToString::to_string).collect::<Vec<_>>().join(",");
143                SettingValue::String(format!("[{formatted}]"))
144            }
145        }
146
147        impl From<&[$ty]> for SettingValue {
148            fn from(value: &[$ty]) -> Self {
149                let formatted = value.iter().map(ToString::to_string).collect::<Vec<_>>().join(",");
150                SettingValue::String(format!("[{formatted}]"))
151            }
152        }
153    };
154}
155
156// Numeric array types
157setting_value_array!(i8);
158setting_value_array!(i16);
159setting_value_array!(i32);
160setting_value_array!(i64);
161setting_value_array!(u8);
162setting_value_array!(u16);
163setting_value_array!(u32);
164setting_value_array!(u64);
165setting_value_array!(f32);
166setting_value_array!(f64);
167
168// String array types - need special escaping
169impl From<Vec<String>> for SettingValue {
170    fn from(value: Vec<String>) -> Self {
171        let formatted = value
172            .iter()
173            .map(|s| format!("'{}'", s.replace('\'', "\\'")))
174            .collect::<Vec<_>>()
175            .join(",");
176        SettingValue::String(format!("[{formatted}]"))
177    }
178}
179
180impl From<&[String]> for SettingValue {
181    fn from(value: &[String]) -> Self {
182        let formatted = value
183            .iter()
184            .map(|s| format!("'{}'", s.replace('\'', "\\'")))
185            .collect::<Vec<_>>()
186            .join(",");
187        SettingValue::String(format!("[{formatted}]"))
188    }
189}
190
191impl From<Vec<&str>> for SettingValue {
192    fn from(value: Vec<&str>) -> Self {
193        let formatted = value
194            .iter()
195            .map(|s| format!("'{}'", s.replace('\'', "\\'")))
196            .collect::<Vec<_>>()
197            .join(",");
198        SettingValue::String(format!("[{formatted}]"))
199    }
200}
201
202impl From<&[&str]> for SettingValue {
203    fn from(value: &[&str]) -> Self {
204        let formatted = value
205            .iter()
206            .map(|s| format!("'{}'", s.replace('\'', "\\'")))
207            .collect::<Vec<_>>()
208            .join(",");
209        SettingValue::String(format!("[{formatted}]"))
210    }
211}
212
213impl fmt::Display for SettingValue {
214    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
215        match self {
216            SettingValue::Int(i) => write!(f, "{i}"),
217            SettingValue::Bool(b) => write!(f, "{b}"),
218            SettingValue::Float(fl) => write!(f, "{fl}"),
219            SettingValue::String(s) => write!(f, "{s}"),
220        }
221    }
222}
223
224/// A single `ClickHouse` query setting, consisting of a key, value, and flags.
225///
226/// A setting represents a key-value pair sent to the `ClickHouse` server to
227/// configure query execution. The `key` is a string (e.g., `max_threads`), and
228/// the `value` is a [`SettingValue`] (integer, boolean, float, or string). The
229/// `important` and `custom` flags control serialization behavior in the native
230/// protocol.
231///
232/// # Fields
233/// - `key`: The setting name (e.g., `max_threads`).
234/// - `value`: The setting value, stored as a [`SettingValue`].
235/// - `important`: If `true`, marks the setting as important (affects serialization).
236/// - `custom`: If `true`, serializes the value as a custom string (e.g., for complex types).
237///
238/// # `ClickHouse` Reference
239/// See the [ClickHouse Settings Reference](https://clickhouse.com/docs/en/operations/settings)
240/// for valid setting names and their types.
241#[derive(Debug, Clone, PartialEq, PartialOrd)]
242#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
243pub struct Setting {
244    key:       String,
245    value:     SettingValue,
246    important: bool,
247    custom:    bool,
248}
249
250impl Setting {
251    /// Encodes the setting to the `ClickHouse` native protocol.
252    ///
253    /// For legacy revisions (≤ 54429), only integer and boolean settings are supported,
254    /// and attempting to encode a string or float will return an error. For modern revisions,
255    /// all setting types are supported, with strings optionally encoded as custom fields if
256    /// `custom` is `true`.
257    ///
258    /// # Arguments
259    /// - `writer`: The writer to serialize the setting to.
260    /// - `revision`: The `ClickHouse` server protocol revision.
261    ///
262    /// # Errors
263    /// Returns `Err(Error::UnsupportedSettingType)` if the setting value is a
264    /// string or float in legacy revisions.
265    async fn encode<W: ClickHouseWrite>(&self, writer: &mut W, revision: u64) -> Result<()> {
266        tracing::trace!(setting = ?self, "Writing setting");
267
268        if revision <= DBMS_MIN_REVISION_WITH_SETTINGS_SERIALIZED_AS_STRINGS {
269            if !matches!(self.value, SettingValue::Int(_) | SettingValue::Bool(_)) {
270                return Err(Error::UnsupportedSettingType(self.key.clone()));
271            }
272
273            // Write key
274            writer.write_string(&self.key).await?;
275
276            // Write value
277            #[expect(clippy::cast_sign_loss)]
278            match &self.value {
279                SettingValue::Int(i) => writer.write_var_uint(*i as u64).await?,
280                SettingValue::Bool(b) => writer.write_var_uint(u64::from(*b)).await?,
281                _ => unreachable!("Checked above"),
282            }
283        } else {
284            // Write key
285            writer.write_string(&self.key).await?;
286
287            // Write flags
288            let mut flags = 0u64;
289            if self.important {
290                flags |= SETTING_FLAG_IMPORTANT;
291            }
292            if self.custom {
293                flags |= SETTING_FLAG_CUSTOM;
294            }
295            writer.write_var_uint(flags).await?;
296
297            // Write value
298            if self.custom {
299                let field_dump = self.encode_field_dump()?;
300                writer.write_string(&field_dump).await?;
301            } else {
302                writer.write_string(self.value.to_string()).await?;
303            }
304        }
305
306        Ok(())
307    }
308
309    /// Decodes a setting from the `ClickHouse` native protocol.
310    ///
311    /// For legacy revisions (≤ 54429), only integer and boolean settings are supported.
312    /// For modern revisions, all setting types are supported, with custom settings
313    /// decoded from field dumps when the custom flag is set.
314    ///
315    /// # Arguments
316    /// - `reader`: The reader to deserialize the setting from.
317    /// - `revision`: The `ClickHouse` server protocol revision.
318    ///
319    /// # Errors
320    /// Returns an error if the data cannot be read or parsed correctly.
321    async fn decode<R: ClickHouseRead>(reader: &mut R, key: String) -> Result<Self> {
322        // Read flags (for STRINGS_WITH_FLAGS format)
323        let flags = reader.read_var_uint().await?;
324        let is_important = (flags & SETTING_FLAG_IMPORTANT) != 0;
325        let is_custom = (flags & SETTING_FLAG_CUSTOM) != 0;
326
327        // Read value based on whether it's custom or not
328        let value = if is_custom {
329            // Custom setting: read as field dump
330            let field_dump = reader.read_string().await?;
331            SettingValue::String(String::from_utf8_lossy(&field_dump).to_string())
332        } else {
333            // Standard setting: read as string and parse
334            let value_str = reader.read_string().await?;
335            Self::parse_setting_value(&String::from_utf8_lossy(&value_str))
336        };
337
338        Ok(Setting { key, value, important: is_important, custom: is_custom })
339    }
340
341    /// Encodes the setting value as a string for custom settings.
342    ///
343    /// For string values, the result is the raw string without additional escaping
344    /// (e.g., `"val'ue"` remains `"val'ue"`). Non-string values return an error.
345    ///
346    /// # Errors
347    /// Returns `Err(Error::UnsupportedFieldType)` if the value is not a string.
348    fn encode_field_dump(&self) -> Result<String> {
349        match &self.value {
350            SettingValue::String(s) => Ok(s.clone()),
351            _ => Err(Error::UnsupportedFieldType(format!("{:?}", self.value))),
352        }
353    }
354
355    /// Parses a setting value from its string representation.
356    ///
357    /// Attempts to parse the string as different types in order:
358    /// 1. Boolean (true/false, 1/0)
359    /// 2. Integer
360    /// 3. Float
361    /// 4. String (fallback)
362    ///
363    /// # Arguments
364    /// - `value_str`: The string representation of the setting value.
365    fn parse_setting_value(value_str: &str) -> SettingValue {
366        // Try parsing as boolean first
367        match value_str.to_lowercase().as_str() {
368            "true" | "1" => return SettingValue::Bool(true),
369            "false" | "0" => return SettingValue::Bool(false),
370            _ => {}
371        }
372
373        // Try parsing as integer
374        if let Ok(int_val) = value_str.parse::<i64>() {
375            return SettingValue::Int(int_val);
376        }
377
378        // Try parsing as float
379        if let Ok(float_val) = value_str.parse::<f64>() {
380            return SettingValue::Float(float_val);
381        }
382
383        // Default to string
384        SettingValue::String(value_str.to_string())
385    }
386}
387
388impl<T: Into<String>, U: Into<SettingValue>> From<(T, U)> for Setting {
389    fn from(value: (T, U)) -> Self {
390        Setting {
391            key:       value.0.into(),
392            value:     value.1.into(),
393            important: false,
394            custom:    false,
395        }
396    }
397}
398
399/// A collection of `ClickHouse` query settings.
400///
401/// This struct holds a list of [`Setting`]s and provides methods to add settings,
402/// convert them to strings, and serialize them to the `ClickHouse` native protocol.
403/// It implements `From` for iterators of key-value pairs and `Deref` to access
404/// the underlying settings as a slice.
405///
406/// # Example
407/// ```rust,ignore
408/// use clickhouse_arrow::query::settings::Settings;
409///
410/// let mut settings = Settings::default();
411/// settings.add_setting("max_threads", 8_i32);
412/// settings.add_setting("default_format", "JSON");
413///
414/// let strings = settings.encode_to_strings();
415/// assert_eq!(strings, vec!["max_threads = 8", "default_format = JSON"]);
416/// ```
417///
418/// # Serialization
419/// Settings are serialized according to the `ClickHouse` native protocol. For
420/// revisions ≤ 54429, only integer and boolean settings are supported. For newer
421/// revisions, all setting types are serialized as strings with optional flags.
422///
423/// # `ClickHouse` Reference
424/// See the [ClickHouse Native Protocol Documentation](https://clickhouse.com/docs/en/interfaces/tcp)
425/// for details on settings serialization.
426#[derive(Debug, Clone, Default, PartialEq, PartialOrd)]
427#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
428pub struct Settings(pub Vec<Setting>);
429
430impl Settings {
431    /// Adds a new setting with the given name and value.
432    ///
433    /// The value is converted to a [`SettingValue`] using the `From` trait. The
434    /// setting is marked as neither `important` nor `custom`.
435    ///
436    /// # Arguments
437    /// - `name`: The setting name (e.g., `max_threads`).
438    /// - `setting`: The setting value (e.g., `8_i32`, `true`, `"JSON"`).
439    ///
440    /// # Example
441    /// ```rust,ignore
442    /// use clickhouse_arrow::query::settings::Settings;
443    ///
444    /// let mut settings = Settings::default();
445    /// settings.add_setting("max_threads", 8_i32);
446    /// assert_eq!(settings.0.len(), 1);
447    /// ```
448    pub fn add_setting<S>(&mut self, name: impl Into<String>, setting: S)
449    where
450        SettingValue: From<S>,
451    {
452        let key = name.into();
453        if let Some(current) = self.0.iter_mut().find(|s| s.key == key) {
454            current.value = setting.into();
455        } else {
456            self.0.push(Setting { key, value: setting.into(), important: false, custom: false });
457        }
458    }
459
460    /// Return new settings with the given name and value added.
461    ///
462    /// The value is converted to a [`SettingValue`] using the `From` trait. The
463    /// setting is marked as neither `important` nor `custom`.
464    ///
465    /// # Arguments
466    /// - `name`: The setting name (e.g., `max_threads`).
467    /// - `setting`: The setting value (e.g., `8_i32`, `true`, `"JSON"`).
468    ///
469    /// # Example
470    /// ```rust,ignore
471    /// use clickhouse_arrow::query::settings::Settings;
472    ///
473    /// let mut settings = Settings::default();
474    /// settings.add_setting("max_threads", 8_i32);
475    /// assert_eq!(settings.0.len(), 1);
476    /// ```
477    #[must_use]
478    pub fn with_setting<S>(mut self, name: impl Into<String>, setting: S) -> Self
479    where
480        SettingValue: From<S>,
481    {
482        let key = name.into();
483        if let Some(current) = self.0.iter_mut().find(|s| s.key == key) {
484            current.value = setting.into();
485        } else {
486            self.0.push(Setting { key, value: setting.into(), important: false, custom: false });
487        }
488        self
489    }
490
491    /// Converts settings to a vector of key-value string pairs.
492    ///
493    /// Each setting is represented as a tuple of `(key, value.to_string())`.
494    ///
495    /// # Example
496    /// ```rust,ignore
497    /// use clickhouse_arrow::query::settings::Settings;
498    ///
499    /// let settings = Settings::from([("max_threads".to_string(), 8_i32)]);
500    /// let kv_pairs = settings.encode_to_key_value_strings();
501    /// assert_eq!(kv_pairs, vec![("max_threads".to_string(), "8".to_string())]);
502    /// ```
503    pub fn encode_to_key_value_strings(&self) -> Vec<(String, String)> {
504        self.0.iter().map(|setting| (setting.key.clone(), setting.value.to_string())).collect()
505    }
506
507    /// Converts settings to a vector of formatted strings.
508    ///
509    /// Each setting is formatted as `key = value`.
510    ///
511    /// # Example
512    /// ```rust,ignore
513    /// use clickhouse_arrow::query::settings::Settings;
514    ///
515    /// let settings = Settings::from([("max_threads".to_string(), 8_i32)]);
516    /// let strings = settings.encode_to_strings();
517    /// assert_eq!(strings, vec!["max_threads = 8"]);
518    /// ```
519    pub fn encode_to_strings(&self) -> Vec<String> {
520        self.0.iter().map(|setting| format!("{} = {}", setting.key, setting.value)).collect()
521    }
522
523    // TODO: Remove - docs
524    pub(crate) async fn encode<W: ClickHouseWrite>(
525        &self,
526        writer: &mut W,
527        revision: u64,
528    ) -> Result<()> {
529        for setting in &self.0 {
530            setting.encode(writer, revision).await?;
531        }
532        Ok(())
533    }
534
535    // TODO: Remove - docs
536    pub(crate) async fn encode_with_ignore<W: ClickHouseWrite>(
537        &self,
538        writer: &mut W,
539        revision: u64,
540        ignore: &Settings,
541    ) -> Result<()> {
542        for setting in &self.0 {
543            if ignore.get(&setting.key).is_some_and(|s| s.value == setting.value) {
544                continue;
545            }
546
547            setting.encode(writer, revision).await?;
548        }
549        Ok(())
550    }
551
552    /// Decodes a collection of settings from the `ClickHouse` native protocol.
553    ///
554    /// Based on `BaseSettings<TTraits>::read()` from cpp source, the format is:
555    /// 1. Loop reading setting name strings
556    /// 2. Empty string marks end of settings
557    /// 3. For each setting: name -> flags (if `STRINGS_WITH_FLAGS`) -> value
558    ///
559    /// # Arguments
560    /// - `reader`: The reader to deserialize the settings from.
561    /// - `revision`: The `ClickHouse` server protocol revision.
562    ///
563    /// # Errors
564    /// Returns an error if the data cannot be read or parsed correctly.
565    pub(crate) async fn decode<R: ClickHouseRead>(reader: &mut R) -> Result<Self> {
566        let mut settings = Vec::new();
567        loop {
568            // Read setting name
569            let key = reader.read_string().await?;
570            // Empty string marks end of settings
571            if key.is_empty() {
572                break;
573            }
574            settings
575                .push(Setting::decode(reader, String::from_utf8_lossy(&key).to_string()).await?);
576        }
577        Ok(Settings(settings))
578    }
579
580    /// Internal helper to find a specific settings
581    pub(crate) fn get(&self, key: &str) -> Option<&Setting> { self.0.iter().find(|s| s.key == key) }
582}
583
584impl<T, K, S> From<T> for Settings
585where
586    T: IntoIterator<Item = (K, S)>,
587    K: Into<String>,
588    SettingValue: From<S>,
589{
590    fn from(value: T) -> Self {
591        Self(
592            value
593                .into_iter()
594                .map(|(k, v)| Setting {
595                    key:       k.into(),
596                    value:     v.into(),
597                    important: false,
598                    custom:    false,
599                })
600                .collect(),
601        )
602    }
603}
604
605impl<K, S> FromIterator<(K, S)> for Settings
606where
607    K: Into<String>,
608    SettingValue: From<S>,
609{
610    fn from_iter<T>(iter: T) -> Self
611    where
612        T: IntoIterator<Item = (K, S)>,
613    {
614        Self::from(iter)
615    }
616}
617
618impl std::ops::Deref for Settings {
619    type Target = [Setting];
620
621    fn deref(&self) -> &Self::Target { &self.0 }
622}
623
624#[cfg(feature = "serde")]
625pub mod deser {
626    use serde::{Deserialize, Serialize};
627
628    use super::*;
629
630    impl Serialize for SettingValue {
631        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
632        where
633            S: serde::Serializer,
634        {
635            match self {
636                SettingValue::Int(i) => ::serde::Serialize::serialize(i, serializer),
637                SettingValue::Bool(b) => ::serde::Serialize::serialize(b, serializer),
638                SettingValue::Float(f) => ::serde::Serialize::serialize(f, serializer),
639                SettingValue::String(s) => ::serde::Serialize::serialize(s, serializer),
640            }
641        }
642    }
643
644    impl<'de> Deserialize<'de> for SettingValue {
645        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
646        where
647            D: serde::Deserializer<'de>,
648        {
649            fn deserialize_setting<'d, De>(deserializer: De) -> Result<SettingValue, De::Error>
650            where
651                De: serde::Deserializer<'d>,
652            {
653                use serde::de::Visitor;
654
655                struct SettingVisitor;
656
657                type Result<E> = std::result::Result<SettingValue, E>;
658
659                impl Visitor<'_> for SettingVisitor {
660                    type Value = SettingValue;
661
662                    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
663                        formatter.write_str("a number, float or string")
664                    }
665
666                    fn visit_bool<E>(self, value: bool) -> Result<E>
667                    where
668                        E: serde::de::Error,
669                    {
670                        Ok(value.into())
671                    }
672
673                    fn visit_u8<E>(self, value: u8) -> Result<E>
674                    where
675                        E: serde::de::Error,
676                    {
677                        Ok(value.into())
678                    }
679
680                    fn visit_u16<E>(self, value: u16) -> Result<E>
681                    where
682                        E: serde::de::Error,
683                    {
684                        Ok(value.into())
685                    }
686
687                    fn visit_u32<E>(self, value: u32) -> Result<E>
688                    where
689                        E: serde::de::Error,
690                    {
691                        Ok(value.into())
692                    }
693
694                    fn visit_u64<E>(self, value: u64) -> Result<E>
695                    where
696                        E: serde::de::Error,
697                    {
698                        Ok(value.into())
699                    }
700
701                    fn visit_i8<E>(self, value: i8) -> Result<E>
702                    where
703                        E: serde::de::Error,
704                    {
705                        Ok(value.into())
706                    }
707
708                    fn visit_i16<E>(self, value: i16) -> Result<E>
709                    where
710                        E: serde::de::Error,
711                    {
712                        Ok(value.into())
713                    }
714
715                    fn visit_i32<E>(self, value: i32) -> Result<E>
716                    where
717                        E: serde::de::Error,
718                    {
719                        Ok(value.into())
720                    }
721
722                    fn visit_i64<E>(self, value: i64) -> Result<E>
723                    where
724                        E: serde::de::Error,
725                    {
726                        Ok(value.into())
727                    }
728
729                    fn visit_f32<E>(self, value: f32) -> Result<E>
730                    where
731                        E: serde::de::Error,
732                    {
733                        Ok(value.into())
734                    }
735
736                    fn visit_f64<E>(self, value: f64) -> Result<E>
737                    where
738                        E: serde::de::Error,
739                    {
740                        Ok(value.into())
741                    }
742
743                    fn visit_str<E>(self, value: &str) -> Result<E>
744                    where
745                        E: serde::de::Error,
746                    {
747                        Ok(value.into())
748                    }
749
750                    fn visit_string<E>(self, value: String) -> Result<E>
751                    where
752                        E: serde::de::Error,
753                    {
754                        self.visit_str(&value)
755                    }
756                }
757
758                deserializer.deserialize_any(SettingVisitor)
759            }
760            deserialize_setting(deserializer)
761        }
762    }
763
764    #[cfg(test)]
765    mod tests {
766        use super::*;
767
768        #[test]
769        fn test_setting_value_serialize_deserialize() {
770            // Test serialization and deserialization for all SettingValue variants
771            let values = vec![
772                SettingValue::Int(42),
773                SettingValue::Bool(true),
774                SettingValue::Float(3.15),
775                SettingValue::String("test".to_string()),
776            ];
777
778            for value in values {
779                // Serialize
780                let json = serde_json::to_string(&value).unwrap();
781
782                // Deserialize
783                let deserialized: SettingValue = serde_json::from_str(&json).unwrap();
784
785                // Verify round-trip
786                match (value, deserialized) {
787                    (SettingValue::Int(a), SettingValue::Int(b)) => assert_eq!(a, b),
788                    (SettingValue::Bool(a), SettingValue::Bool(b)) => assert_eq!(a, b),
789                    (SettingValue::Float(a), SettingValue::Float(b)) => {
790                        assert!((a - b).abs() < 1e-6);
791                    }
792                    (SettingValue::String(a), SettingValue::String(b)) => assert_eq!(a, b),
793                    _ => panic!("Mismatched variants"),
794                }
795            }
796        }
797
798        #[test]
799        fn test_setting_value_deserialize_variants() {
800            // Test deserialization from various JSON inputs
801            assert_eq!(serde_json::from_str::<SettingValue>("42").unwrap(), SettingValue::Int(42));
802            assert_eq!(
803                serde_json::from_str::<SettingValue>("true").unwrap(),
804                SettingValue::Bool(true)
805            );
806            assert!(
807                (serde_json::from_str::<SettingValue>("3.15").unwrap().unwrap_float() - 3.15).abs()
808                    < 1e-6
809            );
810            assert_eq!(
811                serde_json::from_str::<SettingValue>("\"test\"").unwrap(),
812                SettingValue::String("test".to_string())
813            );
814
815            // Test integer variants
816            assert_eq!(
817                serde_json::from_str::<SettingValue>("255").unwrap(),
818                SettingValue::Int(255)
819            ); // u8
820            assert_eq!(
821                serde_json::from_str::<SettingValue>("65535").unwrap(),
822                SettingValue::Int(65535)
823            ); // u16
824            assert_eq!(
825                serde_json::from_str::<SettingValue>("4294967295").unwrap(),
826                SettingValue::Int(4_294_967_295)
827            ); // u32
828            assert_eq!(
829                serde_json::from_str::<SettingValue>("-128").unwrap(),
830                SettingValue::Int(-128)
831            ); // i8
832            assert_eq!(
833                serde_json::from_str::<SettingValue>("-32768").unwrap(),
834                SettingValue::Int(-32768)
835            ); // i16
836            assert_eq!(
837                serde_json::from_str::<SettingValue>("-2147483648").unwrap(),
838                SettingValue::Int(-2_147_483_648)
839            ); // i32
840        }
841
842        #[test]
843        fn test_setting_value_deserialize_invalid() {
844            // Test deserialization of invalid JSON
845            assert!(serde_json::from_str::<SettingValue>("null").is_err());
846            assert!(serde_json::from_str::<SettingValue>("[]").is_err());
847            assert!(serde_json::from_str::<SettingValue>("{}").is_err());
848        }
849    }
850}
851
852#[cfg(test)]
853mod tests {
854    use std::io::Cursor;
855
856    use tokio::io::AsyncWriteExt;
857
858    use super::*;
859    use crate::io::ClickHouseRead;
860
861    type MockWriter = Cursor<Vec<u8>>;
862
863    // Helper to create a Setting
864    fn create_setting<S>(key: &str, value: S, important: bool, custom: bool) -> Setting
865    where
866        SettingValue: From<S>,
867    {
868        Setting { key: key.to_string(), value: value.into(), important, custom }
869    }
870
871    #[test]
872    fn test_setting_value_from_primitives() {
873        // Test all supported From implementations for SettingValue
874        assert_eq!(SettingValue::from(8_i8), SettingValue::Int(8));
875        assert_eq!(SettingValue::from(8_i16), SettingValue::Int(8));
876        assert_eq!(SettingValue::from(8_i32), SettingValue::Int(8));
877        assert_eq!(SettingValue::from(8_i64), SettingValue::Int(8));
878        assert_eq!(SettingValue::from(8_u8), SettingValue::Int(8));
879        assert_eq!(SettingValue::from(8_u16), SettingValue::Int(8));
880        assert_eq!(SettingValue::from(8_u32), SettingValue::Int(8));
881        assert_eq!(SettingValue::from(8_u64), SettingValue::Int(8));
882        assert_eq!(SettingValue::from(true), SettingValue::Bool(true));
883        assert!((SettingValue::from(3.15_f32).unwrap_float() - 3.15).abs() < 1e-6);
884        assert_eq!(SettingValue::from(3.15_f64), SettingValue::Float(3.15));
885        assert_eq!(SettingValue::from("test"), SettingValue::String("test".to_string()));
886        assert_eq!(
887            SettingValue::from("test".to_string()),
888            SettingValue::String("test".to_string())
889        );
890        assert_eq!(
891            SettingValue::from(Box::<str>::from("test")),
892            SettingValue::String("test".to_string())
893        );
894        assert_eq!(
895            SettingValue::from(std::sync::Arc::<str>::from("test")),
896            SettingValue::String("test".to_string())
897        );
898    }
899
900    #[test]
901    fn test_setting_value_display() {
902        // Test Display implementation for SettingValue
903        assert_eq!(SettingValue::Int(42).to_string(), "42");
904        assert_eq!(SettingValue::Bool(true).to_string(), "true");
905        assert_eq!(SettingValue::Float(3.15).to_string(), "3.15");
906        assert_eq!(SettingValue::String("test".to_string()).to_string(), "test");
907    }
908
909    #[test]
910    fn test_setting_encode_field_dump() {
911        // Test encode_field_dump for string values
912        let setting = create_setting("key", "value", false, true);
913        assert_eq!(setting.encode_field_dump().unwrap(), "value");
914
915        // Test string with quotes
916        let setting = create_setting("key", "val'ue", false, true);
917        assert_eq!(setting.encode_field_dump().unwrap(), "val'ue");
918
919        // Test non-string value (should error)
920        let setting = create_setting("key", 42_i32, false, true);
921        assert!(setting.encode_field_dump().is_err());
922    }
923
924    #[tokio::test]
925    async fn test_setting_encode_legacy_revision() {
926        // Test encode for legacy revision (≤ DBMS_MIN_REVISION_WITH_SETTINGS_SERIALIZED_AS_STRINGS)
927        let setting = create_setting("max_threads", 8_i32, false, false);
928        let mut writer = MockWriter::default();
929        setting
930            .encode(&mut writer, DBMS_MIN_REVISION_WITH_SETTINGS_SERIALIZED_AS_STRINGS)
931            .await
932            .unwrap();
933        writer.flush().await.unwrap();
934
935        // Decode and verify using ClickHouseRead
936        let mut reader = Cursor::new(writer.into_inner());
937        let key = reader.read_utf8_string().await.unwrap();
938        assert_eq!(key, "max_threads");
939        let value = reader.read_var_uint().await.unwrap();
940        assert_eq!(value, 8);
941
942        // Test boolean setting
943        let setting = create_setting("allow_experimental", true, false, false);
944        let mut writer = MockWriter::default();
945        setting
946            .encode(&mut writer, DBMS_MIN_REVISION_WITH_SETTINGS_SERIALIZED_AS_STRINGS)
947            .await
948            .unwrap();
949        writer.flush().await.unwrap();
950
951        let mut reader = Cursor::new(writer.into_inner());
952        let key = reader.read_utf8_string().await.unwrap();
953        assert_eq!(key, "allow_experimental");
954        let value = reader.read_var_uint().await.unwrap();
955        assert_eq!(value, 1);
956
957        // Test unsupported type (should error)
958        let setting = create_setting("default_format", "JSON", false, false);
959        let mut writer = MockWriter::default();
960        assert!(matches!(
961            setting
962                .encode(&mut writer, DBMS_MIN_REVISION_WITH_SETTINGS_SERIALIZED_AS_STRINGS)
963                .await,
964            Err(Error::UnsupportedSettingType(key)) if key == "default_format"
965        ));
966    }
967
968    #[tokio::test]
969    async fn test_setting_encode_modern_revision() {
970        // Test encode for modern revision (> DBMS_MIN_REVISION_WITH_SETTINGS_SERIALIZED_AS_STRINGS)
971        let setting = create_setting("max_threads", 8_i32, false, false);
972        let mut writer = MockWriter::default();
973        setting
974            .encode(&mut writer, DBMS_MIN_REVISION_WITH_SETTINGS_SERIALIZED_AS_STRINGS + 1)
975            .await
976            .unwrap();
977        writer.flush().await.unwrap();
978
979        // Decode and verify using ClickHouseRead
980        let mut reader = Cursor::new(writer.into_inner());
981        let key = reader.read_utf8_string().await.unwrap();
982        assert_eq!(key, "max_threads");
983        let flags = reader.read_var_uint().await.unwrap();
984        assert_eq!(flags, 0);
985        let value = reader.read_utf8_string().await.unwrap();
986        assert_eq!(value, "8");
987
988        // Test with important and custom flags
989        let setting = create_setting("custom_key", "value", true, true);
990        let mut writer = MockWriter::default();
991        setting
992            .encode(&mut writer, DBMS_MIN_REVISION_WITH_SETTINGS_SERIALIZED_AS_STRINGS + 1)
993            .await
994            .unwrap();
995        writer.flush().await.unwrap();
996
997        let mut reader = Cursor::new(writer.into_inner());
998        let key = reader.read_utf8_string().await.unwrap();
999        assert_eq!(key, "custom_key");
1000        let flags = reader.read_var_uint().await.unwrap();
1001        assert_eq!(flags, SETTING_FLAG_IMPORTANT | SETTING_FLAG_CUSTOM);
1002        let value = reader.read_utf8_string().await.unwrap();
1003        assert_eq!(value, "value");
1004    }
1005
1006    #[test]
1007    fn test_settings_add_setting() {
1008        let mut settings = Settings::default();
1009        settings.add_setting("max_threads", 8_i32);
1010        settings.add_setting("default_format", "JSON");
1011
1012        assert_eq!(settings.0.len(), 2);
1013        assert_eq!(settings.0[0].key, "max_threads");
1014        assert_eq!(settings.0[0].value, SettingValue::Int(8));
1015        assert_eq!(settings.0[1].key, "default_format");
1016        assert_eq!(settings.0[1].value, SettingValue::String("JSON".to_string()));
1017    }
1018
1019    #[test]
1020    fn test_settings_from_iterator() {
1021        let settings = Settings::from(vec![
1022            ("max_threads".to_string(), SettingValue::Int(8)),
1023            ("allow_experimental".to_string(), SettingValue::Bool(true)),
1024        ]);
1025
1026        assert_eq!(settings.0.len(), 2);
1027        assert_eq!(settings.0[0].key, "max_threads");
1028        assert_eq!(settings.0[0].value, SettingValue::Int(8));
1029        assert_eq!(settings.0[1].key, "allow_experimental");
1030        assert_eq!(settings.0[1].value, SettingValue::Bool(true));
1031    }
1032
1033    #[test]
1034    fn test_settings_encode_to_key_value_strings() {
1035        let settings = Settings::from(vec![
1036            ("max_threads".to_string(), SettingValue::Int(8)),
1037            ("default_format".to_string(), "JSON".into()),
1038        ]);
1039
1040        let kv_pairs = settings.encode_to_key_value_strings();
1041        assert_eq!(kv_pairs, vec![
1042            ("max_threads".to_string(), "8".to_string()),
1043            ("default_format".to_string(), "JSON".to_string()),
1044        ]);
1045    }
1046
1047    #[test]
1048    fn test_settings_encode_to_strings() {
1049        let settings = Settings::from(vec![
1050            ("max_threads".to_string(), SettingValue::Int(8)),
1051            ("default_format".to_string(), "JSON".into()),
1052        ]);
1053
1054        let strings = settings.encode_to_strings();
1055        assert_eq!(strings, vec!["max_threads = 8", "default_format = JSON"]);
1056    }
1057
1058    #[tokio::test]
1059    async fn test_settings_encode() {
1060        let settings = Settings::from(vec![
1061            ("max_threads".to_string(), SettingValue::Int(8)),
1062            ("allow_experimental".to_string(), SettingValue::Bool(true)),
1063        ]);
1064
1065        let mut writer = MockWriter::default();
1066        settings
1067            .encode(&mut writer, DBMS_MIN_REVISION_WITH_SETTINGS_SERIALIZED_AS_STRINGS + 1)
1068            .await
1069            .unwrap();
1070        writer.write_string("").await.unwrap();
1071        writer.flush().await.unwrap();
1072
1073        // Decode and verify using ClickHouseRead
1074        let mut reader = Cursor::new(writer.into_inner());
1075        let key1 = reader.read_utf8_string().await.unwrap();
1076        assert_eq!(key1, "max_threads");
1077        let flags1 = reader.read_var_uint().await.unwrap();
1078        assert_eq!(flags1, 0);
1079        let value1 = reader.read_utf8_string().await.unwrap();
1080        assert_eq!(value1, "8");
1081
1082        let key2 = reader.read_utf8_string().await.unwrap();
1083        assert_eq!(key2, "allow_experimental");
1084        let flags2 = reader.read_var_uint().await.unwrap();
1085        assert_eq!(flags2, 0);
1086        let value2 = reader.read_utf8_string().await.unwrap();
1087        assert_eq!(value2, "true");
1088    }
1089
1090    #[test]
1091    fn test_settings_deref() {
1092        let settings = Settings::from(vec![("max_threads".to_string(), 8_i32)]);
1093        let slice: &[Setting] = &settings;
1094        assert_eq!(slice.len(), 1);
1095        assert_eq!(slice[0].key, "max_threads");
1096    }
1097
1098    #[cfg(feature = "serde")]
1099    #[test]
1100    fn test_serde_serialization() {
1101        use serde_json;
1102
1103        let settings = Settings::from(vec![
1104            ("max_threads".to_string(), SettingValue::Int(8)),
1105            ("allow_experimental".to_string(), SettingValue::Bool(true)),
1106            ("default_format".to_string(), "JSON".into()),
1107        ]);
1108
1109        let json = serde_json::to_string(&settings).unwrap();
1110        let deserialized: Settings = serde_json::from_str(&json).unwrap();
1111        assert_eq!(settings, deserialized);
1112
1113        // Test single Setting
1114        let setting = create_setting("max_threads", 8_i32, true, false);
1115        let json = serde_json::to_string(&setting).unwrap();
1116        let deserialized: Setting = serde_json::from_str(&json).unwrap();
1117        assert_eq!(setting, deserialized);
1118    }
1119
1120    #[tokio::test]
1121    async fn test_settings_decode_empty() {
1122        // Test decoding empty settings (just end marker)
1123        let mut writer = Cursor::new(Vec::new());
1124
1125        // Write empty string as end marker
1126        writer.write_string("").await.unwrap();
1127        writer.flush().await.unwrap();
1128
1129        let mut reader = Cursor::new(writer.into_inner());
1130        let settings = Settings::decode(&mut reader).await.unwrap();
1131
1132        assert_eq!(settings.0.len(), 0);
1133    }
1134
1135    #[tokio::test]
1136    async fn test_settings_decode_single_standard_setting() {
1137        // Test decoding a single standard (non-custom) setting
1138        let mut writer = MockWriter::default();
1139
1140        // Write setting: name -> flags -> value -> end marker
1141        writer.write_string("max_threads").await.unwrap();
1142        writer.write_var_uint(0).await.unwrap(); // No flags
1143        writer.write_string("8").await.unwrap();
1144        writer.write_string("").await.unwrap(); // End marker
1145        writer.flush().await.unwrap();
1146
1147        let mut reader = Cursor::new(writer.into_inner());
1148        let settings = Settings::decode(&mut reader).await.unwrap();
1149
1150        assert_eq!(settings.0.len(), 1);
1151        assert_eq!(settings.0[0].key, "max_threads");
1152        assert_eq!(settings.0[0].value, SettingValue::Int(8));
1153        assert!(!settings.0[0].important);
1154        assert!(!settings.0[0].custom);
1155    }
1156
1157    #[tokio::test]
1158    async fn test_settings_decode_custom_setting() {
1159        // Test decoding a custom setting
1160        let mut writer = MockWriter::default();
1161
1162        // Write custom setting: name -> custom flag -> field dump -> end marker
1163        writer.write_string("custom_setting").await.unwrap();
1164        writer.write_var_uint(SETTING_FLAG_CUSTOM).await.unwrap();
1165        writer.write_string("custom_value").await.unwrap();
1166        writer.write_string("").await.unwrap(); // End marker
1167        writer.flush().await.unwrap();
1168
1169        let mut reader = Cursor::new(writer.into_inner());
1170        let settings = Settings::decode(&mut reader).await.unwrap();
1171
1172        assert_eq!(settings.0.len(), 1);
1173        assert_eq!(settings.0[0].key, "custom_setting");
1174        assert_eq!(settings.0[0].value, SettingValue::String("custom_value".to_string()));
1175        assert!(!settings.0[0].important);
1176        assert!(settings.0[0].custom);
1177    }
1178
1179    #[tokio::test]
1180    async fn test_settings_decode_important_setting() {
1181        // Test decoding an important setting
1182        let mut writer = MockWriter::default();
1183
1184        // Write important setting
1185        writer.write_string("critical_setting").await.unwrap();
1186        writer.write_var_uint(SETTING_FLAG_IMPORTANT).await.unwrap();
1187        writer.write_string("true").await.unwrap();
1188        writer.write_string("").await.unwrap(); // End marker
1189        writer.flush().await.unwrap();
1190
1191        let mut reader = Cursor::new(writer.into_inner());
1192        let settings = Settings::decode(&mut reader).await.unwrap();
1193
1194        assert_eq!(settings.0.len(), 1);
1195        assert_eq!(settings.0[0].key, "critical_setting");
1196        assert_eq!(settings.0[0].value, SettingValue::Bool(true));
1197        assert!(settings.0[0].important);
1198        assert!(!settings.0[0].custom);
1199    }
1200
1201    #[tokio::test]
1202    async fn test_settings_decode_multiple_settings() {
1203        // Test decoding multiple settings with different types and flags
1204        let mut writer = MockWriter::default();
1205
1206        // Setting 1: Standard integer
1207        writer.write_string("max_threads").await.unwrap();
1208        writer.write_var_uint(0).await.unwrap();
1209        writer.write_string("4").await.unwrap();
1210
1211        // Setting 2: Important boolean
1212        writer.write_string("allow_experimental").await.unwrap();
1213        writer.write_var_uint(SETTING_FLAG_IMPORTANT).await.unwrap();
1214        writer.write_string("false").await.unwrap();
1215
1216        // Setting 3: Custom setting
1217        writer.write_string("custom_config").await.unwrap();
1218        writer.write_var_uint(SETTING_FLAG_CUSTOM).await.unwrap();
1219        writer.write_string("custom_data").await.unwrap();
1220
1221        // Setting 4: Important + Custom
1222        writer.write_string("important_custom").await.unwrap();
1223        writer.write_var_uint(SETTING_FLAG_IMPORTANT | SETTING_FLAG_CUSTOM).await.unwrap();
1224        writer.write_string("special_value").await.unwrap();
1225
1226        // Setting 5: Float value
1227        writer.write_string("timeout_ratio").await.unwrap();
1228        writer.write_var_uint(0).await.unwrap();
1229        writer.write_string("1.5").await.unwrap();
1230
1231        // End marker
1232        writer.write_string("").await.unwrap();
1233        writer.flush().await.unwrap();
1234
1235        let mut reader = Cursor::new(writer.into_inner());
1236        let settings = Settings::decode(&mut reader).await.unwrap();
1237
1238        assert_eq!(settings.0.len(), 5);
1239
1240        // Verify Setting 1
1241        assert_eq!(settings.0[0].key, "max_threads");
1242        assert_eq!(settings.0[0].value, SettingValue::Int(4));
1243        assert!(!settings.0[0].important);
1244        assert!(!settings.0[0].custom);
1245
1246        // Verify Setting 2
1247        assert_eq!(settings.0[1].key, "allow_experimental");
1248        assert_eq!(settings.0[1].value, SettingValue::Bool(false));
1249        assert!(settings.0[1].important);
1250        assert!(!settings.0[1].custom);
1251
1252        // Verify Setting 3
1253        assert_eq!(settings.0[2].key, "custom_config");
1254        assert_eq!(settings.0[2].value, SettingValue::String("custom_data".to_string()));
1255        assert!(!settings.0[2].important);
1256        assert!(settings.0[2].custom);
1257
1258        // Verify Setting 4
1259        assert_eq!(settings.0[3].key, "important_custom");
1260        assert_eq!(settings.0[3].value, SettingValue::String("special_value".to_string()));
1261        assert!(settings.0[3].important);
1262        assert!(settings.0[3].custom);
1263
1264        // Verify Setting 5
1265        assert_eq!(settings.0[4].key, "timeout_ratio");
1266        assert_eq!(settings.0[4].value, SettingValue::Float(1.5));
1267        assert!(!settings.0[4].important);
1268        assert!(!settings.0[4].custom);
1269    }
1270
1271    #[tokio::test]
1272    async fn test_settings_decode_parse_setting_value_edge_cases() {
1273        // Test various edge cases for value parsing
1274        let mut writer = MockWriter::default();
1275
1276        // Test "0" as boolean false
1277        writer.write_string("bool_zero").await.unwrap();
1278        writer.write_var_uint(0).await.unwrap();
1279        writer.write_string("0").await.unwrap();
1280
1281        // Test "1" as boolean true
1282        writer.write_string("bool_one").await.unwrap();
1283        writer.write_var_uint(0).await.unwrap();
1284        writer.write_string("1").await.unwrap();
1285
1286        // Test negative integer
1287        writer.write_string("negative_int").await.unwrap();
1288        writer.write_var_uint(0).await.unwrap();
1289        writer.write_string("-42").await.unwrap();
1290
1291        // Test string that looks like number but isn't parseable as int/float
1292        writer.write_string("string_val").await.unwrap();
1293        writer.write_var_uint(0).await.unwrap();
1294        writer.write_string("not_a_number").await.unwrap();
1295
1296        // Test empty string value
1297        writer.write_string("empty_val").await.unwrap();
1298        writer.write_var_uint(0).await.unwrap();
1299        writer.write_string("").await.unwrap();
1300
1301        // End marker
1302        writer.write_string("").await.unwrap();
1303        writer.flush().await.unwrap();
1304
1305        let mut reader = Cursor::new(writer.into_inner());
1306        let settings = Settings::decode(&mut reader).await.unwrap();
1307
1308        assert_eq!(settings.0.len(), 5);
1309        assert_eq!(settings.0[0].value, SettingValue::Bool(false)); // "0" -> false
1310        assert_eq!(settings.0[1].value, SettingValue::Bool(true)); // "1" -> true
1311        assert_eq!(settings.0[2].value, SettingValue::Int(-42)); // "-42" -> int
1312        assert_eq!(settings.0[3].value, SettingValue::String("not_a_number".to_string())); // fallback to string
1313        assert_eq!(settings.0[4].value, SettingValue::String(String::new())); // empty string
1314    }
1315
1316    #[tokio::test]
1317    async fn test_settings_decode_roundtrip() {
1318        // Test that encode -> decode produces the same data
1319        let original_settings = Settings::from(vec![
1320            ("max_threads".to_string(), SettingValue::Int(8)),
1321            ("allow_experimental".to_string(), SettingValue::Bool(true)),
1322            ("custom_setting".to_string(), SettingValue::String("custom_value".to_string())),
1323        ]);
1324
1325        // Mark one as custom for testing
1326        let mut settings_with_custom = original_settings.clone();
1327        settings_with_custom.0[2].custom = true;
1328        settings_with_custom.0[1].important = true;
1329
1330        // Encode
1331        let mut writer = MockWriter::default();
1332        settings_with_custom
1333            .encode(&mut writer, DBMS_MIN_REVISION_WITH_SETTINGS_SERIALIZED_AS_STRINGS + 1)
1334            .await
1335            .unwrap();
1336        writer.write_string("").await.unwrap();
1337        writer.flush().await.unwrap();
1338
1339        // Decode
1340        let mut reader = Cursor::new(writer.into_inner());
1341
1342        let decoded_settings = Settings::decode(&mut reader).await.unwrap();
1343
1344        // Compare (note: encode doesn't write end marker, so we need to account for that)
1345        assert_eq!(decoded_settings.0.len(), 3);
1346        assert_eq!(decoded_settings.0[0].key, "max_threads");
1347        assert_eq!(decoded_settings.0[0].value, SettingValue::Int(8));
1348        assert!(!decoded_settings.0[0].important);
1349        assert!(!decoded_settings.0[0].custom);
1350
1351        assert_eq!(decoded_settings.0[1].key, "allow_experimental");
1352        assert_eq!(decoded_settings.0[1].value, SettingValue::Bool(true));
1353        assert!(decoded_settings.0[1].important);
1354        assert!(!decoded_settings.0[1].custom);
1355
1356        assert_eq!(decoded_settings.0[2].key, "custom_setting");
1357        assert_eq!(decoded_settings.0[2].value, SettingValue::String("custom_value".to_string()));
1358        assert!(!decoded_settings.0[2].important);
1359        assert!(decoded_settings.0[2].custom);
1360    }
1361
1362    #[test]
1363    fn test_from_iterator_no_stack_overflow() {
1364        // This test verifies the fix for issue #52 - FromIterator was causing stack overflow
1365        // by calling .collect() which called from_iter which called .collect() again
1366
1367        let data = vec![
1368            ("param1", SettingValue::from("value1")),
1369            ("param2", SettingValue::from(42_i32)),
1370            ("param3", SettingValue::from(true)),
1371        ];
1372
1373        // This used to cause stack overflow before the fix
1374        let settings: Settings = data.into_iter().collect();
1375
1376        assert_eq!(settings.0.len(), 3);
1377        assert_eq!(settings.0[0].key, "param1");
1378        assert_eq!(settings.0[0].value, SettingValue::String("value1".to_string()));
1379        assert_eq!(settings.0[1].key, "param2");
1380        assert_eq!(settings.0[1].value, SettingValue::Int(42));
1381        assert_eq!(settings.0[2].key, "param3");
1382        assert_eq!(settings.0[2].value, SettingValue::Bool(true));
1383    }
1384
1385    #[test]
1386    fn test_setting_value_from_integer_arrays() {
1387        // Test Vec<T> conversions
1388        assert_eq!(
1389            SettingValue::from(vec![1_i32, 2_i32, 3_i32]),
1390            SettingValue::String("[1,2,3]".to_string())
1391        );
1392        assert_eq!(
1393            SettingValue::from(vec![1_i64, 2_i64, 3_i64]),
1394            SettingValue::String("[1,2,3]".to_string())
1395        );
1396        assert_eq!(
1397            SettingValue::from(vec![1_u32, 2_u32, 3_u32]),
1398            SettingValue::String("[1,2,3]".to_string())
1399        );
1400
1401        // Test &[T] conversions
1402        let arr = [1_i32, 2_i32, 3_i32];
1403        assert_eq!(SettingValue::from(&arr[..]), SettingValue::String("[1,2,3]".to_string()));
1404
1405        // Test empty array
1406        assert_eq!(SettingValue::from(Vec::<i32>::new()), SettingValue::String("[]".to_string()));
1407    }
1408
1409    #[test]
1410    fn test_setting_value_from_float_arrays() {
1411        assert_eq!(
1412            SettingValue::from(vec![1.5_f64, 2.5_f64, 3.15_f64]),
1413            SettingValue::String("[1.5,2.5,3.15]".to_string())
1414        );
1415        assert_eq!(
1416            SettingValue::from(vec![1.5_f32, 2.5_f32]),
1417            SettingValue::String("[1.5,2.5]".to_string())
1418        );
1419
1420        // Test &[T] conversion
1421        let arr = [1.5_f64, 2.5_f64];
1422        assert_eq!(SettingValue::from(&arr[..]), SettingValue::String("[1.5,2.5]".to_string()));
1423    }
1424
1425    #[test]
1426    fn test_setting_value_from_string_arrays() {
1427        // Test Vec<String>
1428        assert_eq!(
1429            SettingValue::from(vec!["a".to_string(), "b".to_string(), "c".to_string()]),
1430            SettingValue::String("['a','b','c']".to_string())
1431        );
1432
1433        // Test Vec<&str>
1434        assert_eq!(
1435            SettingValue::from(vec!["a", "b", "c"]),
1436            SettingValue::String("['a','b','c']".to_string())
1437        );
1438
1439        // Test &[&str]
1440        let arr = ["a", "b", "c"];
1441        assert_eq!(SettingValue::from(&arr[..]), SettingValue::String("['a','b','c']".to_string()));
1442
1443        // Test string with quotes (should be escaped)
1444        assert_eq!(
1445            SettingValue::from(vec!["it's", "a", "test"]),
1446            SettingValue::String("['it\\'s','a','test']".to_string())
1447        );
1448
1449        // Test empty array
1450        assert_eq!(
1451            SettingValue::from(Vec::<String>::new()),
1452            SettingValue::String("[]".to_string())
1453        );
1454    }
1455
1456    #[test]
1457    fn test_setting_value_array_edge_cases() {
1458        // Single element
1459        assert_eq!(SettingValue::from(vec![42_i32]), SettingValue::String("[42]".to_string()));
1460
1461        // Large numbers
1462        assert_eq!(
1463            SettingValue::from(vec![i64::MAX, i64::MIN]),
1464            SettingValue::String(format!("[{},{}]", i64::MAX, i64::MIN))
1465        );
1466
1467        // Multiple quotes in strings
1468        assert_eq!(
1469            SettingValue::from(vec!["'quoted'", "normal"]),
1470            SettingValue::String("['\\'quoted\\'','normal']".to_string())
1471        );
1472    }
1473}