rust_ef/provider/
db_value.rs1use std::fmt;
4
5#[derive(Debug, Clone, PartialEq)]
15pub enum DbValue {
16 Null,
17 Bool(bool),
18 I16(i16),
19 I32(i32),
20 I64(i64),
21 F32(f32),
22 F64(f64),
23 String(String),
24 Bytes(Vec<u8>),
25 #[cfg(feature = "chrono")]
27 DateTime(chrono::DateTime<chrono::Utc>),
28 #[cfg(feature = "chrono")]
30 NaiveDateTime(chrono::NaiveDateTime),
31 #[cfg(feature = "chrono")]
33 NaiveDate(chrono::NaiveDate),
34 #[cfg(feature = "uuid")]
36 Uuid(uuid::Uuid),
37 #[cfg(feature = "decimal")]
41 Decimal(rust_decimal::Decimal),
42}
43
44impl fmt::Display for DbValue {
45 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46 match self {
47 DbValue::Null => write!(f, "NULL"),
48 DbValue::Bool(v) => write!(f, "{}", if *v { "TRUE" } else { "FALSE" }),
49 DbValue::I16(v) => write!(f, "{}", v),
50 DbValue::I32(v) => write!(f, "{}", v),
51 DbValue::I64(v) => write!(f, "{}", v),
52 DbValue::F32(v) => write!(f, "{}", v),
53 DbValue::F64(v) => write!(f, "{}", v),
54 DbValue::String(v) => write!(f, "'{}'", v.replace('\'', "''")),
55 DbValue::Bytes(v) => write!(f, "{}", hex::encode(v)),
56 #[cfg(feature = "chrono")]
57 DbValue::DateTime(v) => write!(f, "'{}'", v.to_rfc3339()),
58 #[cfg(feature = "chrono")]
59 DbValue::NaiveDateTime(v) => write!(f, "'{}'", v),
60 #[cfg(feature = "chrono")]
61 DbValue::NaiveDate(v) => write!(f, "'{}'", v),
62 #[cfg(feature = "uuid")]
63 DbValue::Uuid(v) => write!(f, "'{}'", v),
64 #[cfg(feature = "decimal")]
65 DbValue::Decimal(v) => write!(f, "'{}'", v),
66 }
67 }
68}
69
70mod hex {
71 const HEX_CHARS: &[u8; 16] = b"0123456789abcdef";
72
73 pub fn encode(bytes: &[u8]) -> String {
74 let mut s = String::with_capacity(bytes.len() * 2);
75 for &b in bytes {
76 s.push(HEX_CHARS[(b >> 4) as usize] as char);
77 s.push(HEX_CHARS[(b & 0x0f) as usize] as char);
78 }
79 s
80 }
81}
82
83#[cfg(test)]
84mod hex_tests {
85 use super::hex;
86
87 #[test]
88 fn empty_bytes() {
89 assert_eq!(hex::encode(&[]), "");
90 }
91
92 #[test]
93 fn single_byte() {
94 assert_eq!(hex::encode(&[0xff]), "ff");
95 assert_eq!(hex::encode(&[0x0a]), "0a");
96 }
97
98 #[test]
99 fn multi_byte() {
100 assert_eq!(hex::encode(&[0x00, 0x7f, 0xab, 0xcd]), "007fabcd");
101 }
102
103 #[test]
104 fn matches_format_based_output() {
105 let bytes: Vec<u8> = vec![0xde, 0xad, 0xbe, 0xef];
106 let expected: String = bytes.iter().map(|b| format!("{:02x}", b)).collect();
107 assert_eq!(hex::encode(&bytes), expected);
108 }
109}
110
111impl From<i32> for DbValue {
112 fn from(v: i32) -> Self {
113 DbValue::I32(v)
114 }
115}
116impl From<&i32> for DbValue {
117 fn from(v: &i32) -> Self {
118 DbValue::I32(*v)
119 }
120}
121impl From<i64> for DbValue {
122 fn from(v: i64) -> Self {
123 DbValue::I64(v)
124 }
125}
126impl From<&i64> for DbValue {
127 fn from(v: &i64) -> Self {
128 DbValue::I64(*v)
129 }
130}
131impl From<String> for DbValue {
132 fn from(v: String) -> Self {
133 DbValue::String(v)
134 }
135}
136impl From<&str> for DbValue {
137 fn from(v: &str) -> Self {
138 DbValue::String(v.to_string())
139 }
140}
141impl From<bool> for DbValue {
142 fn from(v: bool) -> Self {
143 DbValue::Bool(v)
144 }
145}
146impl From<f64> for DbValue {
147 fn from(v: f64) -> Self {
148 DbValue::F64(v)
149 }
150}
151impl From<f32> for DbValue {
152 fn from(v: f32) -> Self {
153 DbValue::F32(v)
154 }
155}
156impl From<i16> for DbValue {
157 fn from(v: i16) -> Self {
158 DbValue::I16(v)
159 }
160}
161impl From<Vec<u8>> for DbValue {
162 fn from(v: Vec<u8>) -> Self {
163 DbValue::Bytes(v)
164 }
165}
166
167#[cfg(feature = "chrono")]
175impl From<chrono::DateTime<chrono::Utc>> for DbValue {
176 fn from(dt: chrono::DateTime<chrono::Utc>) -> Self {
177 DbValue::DateTime(dt)
178 }
179}
180
181#[cfg(feature = "chrono")]
182impl From<chrono::NaiveDateTime> for DbValue {
183 fn from(ndt: chrono::NaiveDateTime) -> Self {
184 DbValue::NaiveDateTime(ndt)
185 }
186}
187
188#[cfg(feature = "chrono")]
189impl From<chrono::NaiveDate> for DbValue {
190 fn from(nd: chrono::NaiveDate) -> Self {
191 DbValue::NaiveDate(nd)
192 }
193}
194
195#[cfg(feature = "uuid")]
196impl From<uuid::Uuid> for DbValue {
197 fn from(u: uuid::Uuid) -> Self {
198 DbValue::Uuid(u)
199 }
200}
201
202#[cfg(feature = "decimal")]
203impl From<rust_decimal::Decimal> for DbValue {
204 fn from(d: rust_decimal::Decimal) -> Self {
205 DbValue::Decimal(d)
206 }
207}
208impl<T> From<Option<T>> for DbValue
209where
210 T: Into<DbValue>,
211{
212 fn from(v: Option<T>) -> Self {
213 match v {
214 Some(val) => val.into(),
215 None => DbValue::Null,
216 }
217 }
218}
219
220#[derive(Debug, Clone, PartialEq)]
226pub struct DbValueConvertError {
227 pub source: DbValue,
229 pub target_type: &'static str,
231}
232
233impl fmt::Display for DbValueConvertError {
234 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
235 write!(
236 f,
237 "cannot convert {:?} to {}",
238 self.source, self.target_type
239 )
240 }
241}
242
243impl std::error::Error for DbValueConvertError {}
244
245impl From<DbValueConvertError> for crate::error::EFError {
246 fn from(e: DbValueConvertError) -> Self {
247 crate::error::EFError::type_conversion(e.to_string())
248 }
249}