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