Skip to main content

a3s_orm/
value.rs

1/// A bound SQL parameter. Values are never interpolated into generated SQL.
2#[derive(Clone, Debug, PartialEq)]
3pub enum Value {
4    Null,
5    Bool(bool),
6    I64(i64),
7    U64(u64),
8    F64(f64),
9    String(String),
10    Bytes(Vec<u8>),
11    Array(Vec<Value>),
12    #[cfg(feature = "uuid")]
13    Uuid(uuid::Uuid),
14    #[cfg(feature = "json")]
15    Json(serde_json::Value),
16    #[cfg(feature = "chrono")]
17    Date(chrono::NaiveDate),
18    #[cfg(feature = "chrono")]
19    Time(chrono::NaiveTime),
20    #[cfg(feature = "chrono")]
21    DateTime(chrono::NaiveDateTime),
22    #[cfg(feature = "chrono")]
23    DateTimeUtc(chrono::DateTime<chrono::Utc>),
24    #[cfg(feature = "decimal")]
25    Decimal(rust_decimal::Decimal),
26}
27
28impl Value {
29    pub const fn kind(&self) -> &'static str {
30        match self {
31            Self::Null => "null",
32            Self::Bool(_) => "boolean",
33            Self::I64(_) => "signed integer",
34            Self::U64(_) => "unsigned integer",
35            Self::F64(_) => "floating-point number",
36            Self::String(_) => "string",
37            Self::Bytes(_) => "bytes",
38            Self::Array(_) => "array",
39            #[cfg(feature = "uuid")]
40            Self::Uuid(_) => "uuid",
41            #[cfg(feature = "json")]
42            Self::Json(_) => "json",
43            #[cfg(feature = "chrono")]
44            Self::Date(_) => "date",
45            #[cfg(feature = "chrono")]
46            Self::Time(_) => "time",
47            #[cfg(feature = "chrono")]
48            Self::DateTime(_) => "timestamp",
49            #[cfg(feature = "chrono")]
50            Self::DateTimeUtc(_) => "timestamp with time zone",
51            #[cfg(feature = "decimal")]
52            Self::Decimal(_) => "decimal",
53        }
54    }
55}
56
57#[derive(Clone, Debug, PartialEq)]
58pub struct SqlArray<T>(pub Vec<T>);
59
60impl<T> From<Vec<T>> for SqlArray<T> {
61    fn from(values: Vec<T>) -> Self {
62        Self(values)
63    }
64}
65
66/// Converts a Rust value into a parameter for a specific typed column.
67pub trait IntoSqlValue<T> {
68    fn into_sql_value(self) -> Value;
69}
70
71impl<T> IntoSqlValue<T> for T
72where
73    T: Into<Value>,
74{
75    fn into_sql_value(self) -> Value {
76        self.into()
77    }
78}
79
80impl IntoSqlValue<String> for &str {
81    fn into_sql_value(self) -> Value {
82        Value::String(self.to_owned())
83    }
84}
85
86impl<T> IntoSqlValue<Option<T>> for T
87where
88    T: Into<Value>,
89{
90    fn into_sql_value(self) -> Value {
91        self.into()
92    }
93}
94
95impl From<bool> for Value {
96    fn from(value: bool) -> Self {
97        Self::Bool(value)
98    }
99}
100
101macro_rules! signed_values {
102    ($($type:ty),* $(,)?) => {
103        $(
104            impl From<$type> for Value {
105                fn from(value: $type) -> Self {
106                    Self::I64(value as i64)
107                }
108            }
109        )*
110    };
111}
112
113macro_rules! unsigned_values {
114    ($($type:ty),* $(,)?) => {
115        $(
116            impl From<$type> for Value {
117                fn from(value: $type) -> Self {
118                    Self::U64(value as u64)
119                }
120            }
121        )*
122    };
123}
124
125signed_values!(i8, i16, i32, i64, isize);
126unsigned_values!(u8, u16, u32, u64, usize);
127
128impl From<f32> for Value {
129    fn from(value: f32) -> Self {
130        Self::F64(value as f64)
131    }
132}
133
134impl From<f64> for Value {
135    fn from(value: f64) -> Self {
136        Self::F64(value)
137    }
138}
139
140impl From<String> for Value {
141    fn from(value: String) -> Self {
142        Self::String(value)
143    }
144}
145
146impl From<&str> for Value {
147    fn from(value: &str) -> Self {
148        Self::String(value.to_owned())
149    }
150}
151
152impl From<Vec<u8>> for Value {
153    fn from(value: Vec<u8>) -> Self {
154        Self::Bytes(value)
155    }
156}
157
158impl<T> From<SqlArray<T>> for Value
159where
160    T: Into<Value>,
161{
162    fn from(value: SqlArray<T>) -> Self {
163        Self::Array(value.0.into_iter().map(Into::into).collect())
164    }
165}
166
167#[cfg(feature = "uuid")]
168impl From<uuid::Uuid> for Value {
169    fn from(value: uuid::Uuid) -> Self {
170        Self::Uuid(value)
171    }
172}
173
174#[cfg(feature = "json")]
175impl From<serde_json::Value> for Value {
176    fn from(value: serde_json::Value) -> Self {
177        Self::Json(value)
178    }
179}
180
181#[cfg(feature = "chrono")]
182impl From<chrono::NaiveDate> for Value {
183    fn from(value: chrono::NaiveDate) -> Self {
184        Self::Date(value)
185    }
186}
187
188#[cfg(feature = "chrono")]
189impl From<chrono::NaiveTime> for Value {
190    fn from(value: chrono::NaiveTime) -> Self {
191        Self::Time(value)
192    }
193}
194
195#[cfg(feature = "chrono")]
196impl From<chrono::NaiveDateTime> for Value {
197    fn from(value: chrono::NaiveDateTime) -> Self {
198        Self::DateTime(value)
199    }
200}
201
202#[cfg(feature = "chrono")]
203impl From<chrono::DateTime<chrono::Utc>> for Value {
204    fn from(value: chrono::DateTime<chrono::Utc>) -> Self {
205        Self::DateTimeUtc(value)
206    }
207}
208
209#[cfg(feature = "decimal")]
210impl From<rust_decimal::Decimal> for Value {
211    fn from(value: rust_decimal::Decimal) -> Self {
212        Self::Decimal(value)
213    }
214}
215
216impl<T> From<Option<T>> for Value
217where
218    T: Into<Value>,
219{
220    fn from(value: Option<T>) -> Self {
221        value.map(Into::into).unwrap_or(Self::Null)
222    }
223}