vespertide_core/schema/
str_or_bool.rs

1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
5#[serde(rename_all = "snake_case", untagged)]
6pub enum StrOrBoolOrArray {
7    Str(String),
8    Array(Vec<String>),
9    Bool(bool),
10}
11
12/// A value that can be a string, boolean, or number.
13/// This is used for default values where columns can use literal values directly.
14#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
15#[serde(untagged)]
16pub enum DefaultValue {
17    Bool(bool),
18    Integer(i64),
19    Float(f64),
20    String(String),
21}
22
23impl Eq for DefaultValue {}
24
25impl DefaultValue {
26    /// Convert to SQL string representation
27    /// Empty strings are converted to '' (SQL empty string literal)
28    pub fn to_sql(&self) -> String {
29        match self {
30            DefaultValue::Bool(b) => b.to_string(),
31            DefaultValue::Integer(n) => n.to_string(),
32            DefaultValue::Float(f) => f.to_string(),
33            DefaultValue::String(s) => {
34                if s.is_empty() {
35                    "''".to_string()
36                } else {
37                    s.clone()
38                }
39            }
40        }
41    }
42
43    /// Check if this is a string type (needs quoting for certain column types)
44    pub fn is_string(&self) -> bool {
45        matches!(self, DefaultValue::String(_))
46    }
47
48    /// Check if this is an empty string
49    pub fn is_empty_string(&self) -> bool {
50        matches!(self, DefaultValue::String(s) if s.is_empty())
51    }
52}
53
54impl From<bool> for DefaultValue {
55    fn from(b: bool) -> Self {
56        DefaultValue::Bool(b)
57    }
58}
59
60impl From<i64> for DefaultValue {
61    fn from(n: i64) -> Self {
62        DefaultValue::Integer(n)
63    }
64}
65
66impl From<i32> for DefaultValue {
67    fn from(n: i32) -> Self {
68        DefaultValue::Integer(n as i64)
69    }
70}
71
72impl From<f64> for DefaultValue {
73    fn from(f: f64) -> Self {
74        DefaultValue::Float(f)
75    }
76}
77
78impl From<String> for DefaultValue {
79    fn from(s: String) -> Self {
80        DefaultValue::String(s)
81    }
82}
83
84impl From<&str> for DefaultValue {
85    fn from(s: &str) -> Self {
86        DefaultValue::String(s.to_string())
87    }
88}
89
90/// Backwards compatibility alias
91pub type StringOrBool = DefaultValue;
92
93#[cfg(test)]
94mod tests {
95    use super::*;
96
97    #[test]
98    fn test_default_value_to_sql_bool() {
99        let val = DefaultValue::Bool(true);
100        assert_eq!(val.to_sql(), "true");
101
102        let val = DefaultValue::Bool(false);
103        assert_eq!(val.to_sql(), "false");
104    }
105
106    #[test]
107    fn test_default_value_to_sql_integer() {
108        let val = DefaultValue::Integer(42);
109        assert_eq!(val.to_sql(), "42");
110
111        let val = DefaultValue::Integer(-100);
112        assert_eq!(val.to_sql(), "-100");
113    }
114
115    #[test]
116    fn test_default_value_to_sql_float() {
117        let val = DefaultValue::Float(1.5);
118        assert_eq!(val.to_sql(), "1.5");
119    }
120
121    #[test]
122    fn test_default_value_to_sql_string() {
123        let val = DefaultValue::String("hello".into());
124        assert_eq!(val.to_sql(), "hello");
125    }
126
127    #[test]
128    fn test_default_value_to_sql_empty_string() {
129        let val = DefaultValue::String("".into());
130        assert_eq!(val.to_sql(), "''");
131    }
132
133    #[test]
134    fn test_default_value_is_empty_string() {
135        assert!(DefaultValue::String("".into()).is_empty_string());
136        assert!(!DefaultValue::String("hello".into()).is_empty_string());
137        assert!(!DefaultValue::Bool(true).is_empty_string());
138        assert!(!DefaultValue::Integer(0).is_empty_string());
139    }
140
141    #[test]
142    fn test_default_value_from_bool() {
143        let val: DefaultValue = true.into();
144        assert_eq!(val, DefaultValue::Bool(true));
145
146        let val: DefaultValue = false.into();
147        assert_eq!(val, DefaultValue::Bool(false));
148    }
149
150    #[test]
151    fn test_default_value_from_integer() {
152        let val: DefaultValue = 42i64.into();
153        assert_eq!(val, DefaultValue::Integer(42));
154
155        let val: DefaultValue = 100i32.into();
156        assert_eq!(val, DefaultValue::Integer(100));
157    }
158
159    #[test]
160    fn test_default_value_from_float() {
161        let val: DefaultValue = 1.5f64.into();
162        assert_eq!(val, DefaultValue::Float(1.5));
163    }
164
165    #[test]
166    fn test_default_value_from_string() {
167        let val: DefaultValue = String::from("test").into();
168        assert_eq!(val, DefaultValue::String("test".into()));
169    }
170
171    #[test]
172    fn test_default_value_from_str() {
173        let val: DefaultValue = "test".into();
174        assert_eq!(val, DefaultValue::String("test".into()));
175    }
176
177    #[test]
178    fn test_default_value_is_string() {
179        assert!(DefaultValue::String("test".into()).is_string());
180        assert!(!DefaultValue::Bool(true).is_string());
181        assert!(!DefaultValue::Integer(42).is_string());
182        assert!(!DefaultValue::Float(1.5).is_string());
183    }
184}