1use crate::{tds::Numeric, xml::XmlData, ColumnData};
2use uuid::Uuid;
3
4pub trait FromSql<'a>
44where
45 Self: Sized + 'a,
46{
47 fn from_sql(value: &'a ColumnData<'static>) -> crate::Result<Option<Self>>;
49}
50
51pub trait FromSqlOwned
53where
54 Self: Sized,
55{
56 fn from_sql_owned(value: ColumnData<'static>) -> crate::Result<Option<Self>>;
58}
59
60from_sql!(bool: ColumnData::Bit(val) => (*val, val));
61from_sql!(u8: ColumnData::U8(val) => (*val, val), ColumnData::I32(None) => (None, None));
62from_sql!(i16: ColumnData::I16(val) => (*val, val), ColumnData::U8(None) => (None, None), ColumnData::I32(None) => (None, None));
63from_sql!(i32: ColumnData::I32(val) => (*val, val), ColumnData::I16(val) => (val.map(i32::from), val.map(i32::from)), ColumnData::U8(None) => (None, None));
64from_sql!(i64: ColumnData::I64(val) => (*val, val), ColumnData::U8(None) => (None, None), ColumnData::I32(None) => (None, None));
65from_sql!(f32: ColumnData::F32(val) => (*val, val), ColumnData::Numeric(n) => (n.map(Numeric::to_f32), n.map(Numeric::to_f32)));
67from_sql!(f64: ColumnData::F64(val) => (*val, val), ColumnData::Numeric(n) => (n.map(Numeric::to_f64), n.map(Numeric::to_f64)));
68from_sql!(Uuid: ColumnData::Guid(val) => (*val, val));
69from_sql!(Numeric: ColumnData::Numeric(n) => (*n, n));
70
71impl FromSqlOwned for XmlData {
72 fn from_sql_owned(value: ColumnData<'static>) -> crate::Result<Option<Self>> {
73 match value {
74 ColumnData::Xml(data) => Ok(data.map(|data| data.into_owned())),
75 v => Err(crate::Error::Conversion(
76 format!("cannot interpret {:?} as a String value", v).into(),
77 )),
78 }
79 }
80}
81
82impl<'a> FromSql<'a> for &'a XmlData {
83 fn from_sql(value: &'a ColumnData<'static>) -> crate::Result<Option<Self>> {
84 match value {
85 ColumnData::Xml(data) => Ok(data.as_ref().map(|s| s.as_ref())),
86 v => Err(crate::Error::Conversion(
87 format!("cannot interpret {:?} as a String value", v).into(),
88 )),
89 }
90 }
91}
92
93impl FromSqlOwned for String {
94 fn from_sql_owned(value: ColumnData<'static>) -> crate::Result<Option<Self>> {
95 match value {
96 ColumnData::String(s) | ColumnData::VarChar(s) => Ok(s.map(|s| s.into_owned())),
97 v => Err(crate::Error::Conversion(
98 format!("cannot interpret {:?} as a String value", v).into(),
99 )),
100 }
101 }
102}
103
104impl<'a> FromSql<'a> for &'a str {
105 fn from_sql(value: &'a ColumnData<'static>) -> crate::Result<Option<Self>> {
106 match value {
107 ColumnData::String(s) | ColumnData::VarChar(s) => Ok(s.as_ref().map(|s| s.as_ref())),
108 v => Err(crate::Error::Conversion(
109 format!("cannot interpret {:?} as a String value", v).into(),
110 )),
111 }
112 }
113}
114
115impl FromSqlOwned for Vec<u8> {
116 fn from_sql_owned(value: ColumnData<'static>) -> crate::Result<Option<Self>> {
117 match value {
118 ColumnData::Binary(b) => Ok(b.map(|s| s.into_owned())),
119 v => Err(crate::Error::Conversion(
120 format!("cannot interpret {:?} as a String value", v).into(),
121 )),
122 }
123 }
124}
125
126impl<'a> FromSql<'a> for &'a [u8] {
127 fn from_sql(value: &'a ColumnData<'static>) -> crate::Result<Option<Self>> {
128 match value {
129 ColumnData::Binary(b) => Ok(b.as_ref().map(|s| s.as_ref())),
130 v => Err(crate::Error::Conversion(
131 format!("cannot interpret {:?} as a &[u8] value", v).into(),
132 )),
133 }
134 }
135}
136
137#[cfg(test)]
138mod tests {
139 use super::*;
140
141 #[test]
142 fn i16_column_converts_to_i32() {
143 let data = ColumnData::I16(Some(8));
144 assert_eq!(Some(8i32), i32::from_sql(&data).unwrap());
145 assert_eq!(Some(8i32), i32::from_sql_owned(data).unwrap());
146 }
147
148 #[test]
149 fn null_i16_column_converts_to_i32() {
150 let data = ColumnData::I16(None);
151 assert_eq!(None, i32::from_sql(&data).unwrap());
152 assert_eq!(None, i32::from_sql_owned(ColumnData::I16(None)).unwrap());
153 }
154
155 #[test]
156 fn bool_from_bit() {
157 let data = ColumnData::Bit(Some(true));
158 assert_eq!(Some(true), bool::from_sql(&data).unwrap());
159 assert_eq!(Some(true), bool::from_sql_owned(data).unwrap());
160 }
161
162 #[test]
163 fn u8_from_u8_and_null_i32() {
164 let data = ColumnData::U8(Some(5));
165 assert_eq!(Some(5u8), u8::from_sql(&data).unwrap());
166 assert_eq!(Some(5u8), u8::from_sql_owned(data).unwrap());
167
168 let null = ColumnData::I32(None);
169 assert_eq!(None, u8::from_sql(&null).unwrap());
170 assert_eq!(None, u8::from_sql_owned(null).unwrap());
171 }
172
173 #[test]
174 fn i16_from_wrong_variant_errors() {
175 let data = ColumnData::F64(Some(1.0));
176 let err = i16::from_sql(&data).unwrap_err();
177 assert!(format!("{}", err).contains("cannot interpret"));
178 }
179
180 #[test]
181 fn i64_from_i64_and_null() {
182 let data = ColumnData::I64(Some(42));
183 assert_eq!(Some(42i64), i64::from_sql(&data).unwrap());
184 assert_eq!(Some(42i64), i64::from_sql_owned(data).unwrap());
185
186 let null = ColumnData::U8(None);
187 assert_eq!(None, i64::from_sql_owned(null).unwrap());
188 }
189
190 #[test]
191 fn f32_and_f64_from_sql() {
192 let f32_data = ColumnData::F32(Some(1.5));
193 assert_eq!(Some(1.5f32), f32::from_sql(&f32_data).unwrap());
194
195 let f64_data = ColumnData::F64(Some(2.5));
196 assert_eq!(Some(2.5f64), f64::from_sql(&f64_data).unwrap());
197 }
198
199 #[test]
200 fn floats_from_numeric() {
201 let money = ColumnData::Numeric(Some(Numeric::new_with_scale(12300, 4)));
202 assert_eq!(Some(1.23f64), f64::from_sql(&money).unwrap());
203 assert_eq!(Some(1.23f32), f32::from_sql(&money).unwrap());
204 assert_eq!(Some(1.23f64), f64::from_sql_owned(money.clone()).unwrap());
205 assert_eq!(Some(1.23f32), f32::from_sql_owned(money).unwrap());
206
207 let null = ColumnData::Numeric(None);
208 assert_eq!(None, f64::from_sql(&null).unwrap());
209 assert_eq!(None, f32::from_sql_owned(null).unwrap());
210 }
211
212 #[test]
213 fn uuid_from_guid() {
214 let uuid = Uuid::new_v4();
215 let data = ColumnData::Guid(Some(uuid));
216 assert_eq!(Some(uuid), Uuid::from_sql(&data).unwrap());
217 assert_eq!(Some(uuid), Uuid::from_sql_owned(data).unwrap());
218 }
219
220 #[test]
221 fn numeric_from_numeric() {
222 let numeric = crate::tds::Numeric::new_with_scale(1234, 2);
223 let data = ColumnData::Numeric(Some(numeric));
224 assert_eq!(Some(numeric), Numeric::from_sql(&data).unwrap());
225 assert_eq!(Some(numeric), Numeric::from_sql_owned(data).unwrap());
226 }
227
228 #[test]
229 fn xml_data_owned_and_borrowed() {
230 let xml = XmlData::new("<a/>".to_string());
231 let data = ColumnData::Xml(Some(std::borrow::Cow::Owned(xml.clone())));
232
233 let borrowed = <&XmlData as FromSql>::from_sql(&data).unwrap().unwrap();
234 assert_eq!(borrowed.to_string(), xml.to_string());
235
236 let owned = XmlData::from_sql_owned(data).unwrap().unwrap();
237 assert_eq!(owned.to_string(), xml.to_string());
238 }
239
240 #[test]
241 fn xml_data_wrong_variant_errors() {
242 let data = ColumnData::I32(Some(1));
243 let err = XmlData::from_sql_owned(data).unwrap_err();
244 assert!(format!("{}", err).contains("cannot interpret"));
245
246 let data = ColumnData::I32(Some(1));
247 let err = <&XmlData as FromSql>::from_sql(&data).unwrap_err();
248 assert!(format!("{}", err).contains("cannot interpret"));
249 }
250
251 #[test]
252 fn string_owned_and_borrowed_str() {
253 let data = ColumnData::String(Some(std::borrow::Cow::Borrowed("hello")));
254 let borrowed = <&str as FromSql>::from_sql(&data).unwrap();
255 assert_eq!(Some("hello"), borrowed);
256
257 let owned = String::from_sql_owned(data).unwrap();
258 assert_eq!(Some("hello".to_string()), owned);
259 }
260
261 #[test]
262 fn string_wrong_variant_errors() {
263 let data = ColumnData::I32(Some(1));
264 let err = String::from_sql_owned(data).unwrap_err();
265 assert!(format!("{}", err).contains("cannot interpret"));
266
267 let data = ColumnData::I32(Some(1));
268 let err = <&str as FromSql>::from_sql(&data).unwrap_err();
269 assert!(format!("{}", err).contains("cannot interpret"));
270 }
271
272 #[test]
273 fn binary_owned_and_borrowed_slice() {
274 let bytes = vec![1u8, 2, 3];
275 let data = ColumnData::Binary(Some(std::borrow::Cow::Owned(bytes.clone())));
276
277 let borrowed = <&[u8] as FromSql>::from_sql(&data).unwrap();
278 assert_eq!(Some(bytes.as_slice()), borrowed);
279
280 let owned = Vec::<u8>::from_sql_owned(data).unwrap();
281 assert_eq!(Some(bytes), owned);
282 }
283
284 #[test]
285 fn binary_wrong_variant_errors() {
286 let data = ColumnData::I32(Some(1));
287 let err = Vec::<u8>::from_sql_owned(data).unwrap_err();
288 assert!(format!("{}", err).contains("cannot interpret"));
289
290 let data = ColumnData::I32(Some(1));
291 let err = <&[u8] as FromSql>::from_sql(&data).unwrap_err();
292 assert!(format!("{}", err).contains("cannot interpret"));
293 }
294
295 #[test]
296 fn null_string_and_binary_values() {
297 let data = ColumnData::String(None);
298 assert_eq!(None, String::from_sql_owned(data).unwrap());
299
300 let data = ColumnData::Binary(None);
301 assert_eq!(None, Vec::<u8>::from_sql_owned(data).unwrap());
302
303 let data = ColumnData::Xml(None);
304 assert_eq!(None, XmlData::from_sql_owned(data).unwrap());
305 }
306}