1use crate::{
2 tds::{codec::ColumnData, Numeric},
3 xml::XmlData,
4};
5use std::borrow::Cow;
6use uuid::Uuid;
7
8pub trait ToSql: Send + Sync {
62 fn to_sql(&self) -> ColumnData<'_>;
65}
66
67pub trait IntoSql<'a>: Send + Sync {
69 fn into_sql(self) -> ColumnData<'a>;
71}
72
73impl<'a> IntoSql<'a> for &'a str {
74 fn into_sql(self) -> ColumnData<'a> {
75 ColumnData::String(Some(Cow::Borrowed(self)))
76 }
77}
78
79impl<'a> IntoSql<'a> for Option<&'a str> {
80 fn into_sql(self) -> ColumnData<'a> {
81 ColumnData::String(self.map(Cow::Borrowed))
82 }
83}
84
85impl<'a> IntoSql<'a> for &'a String {
86 fn into_sql(self) -> ColumnData<'a> {
87 ColumnData::String(Some(Cow::Borrowed(self)))
88 }
89}
90
91impl<'a> IntoSql<'a> for Option<&'a String> {
92 fn into_sql(self) -> ColumnData<'a> {
93 ColumnData::String(self.map(Cow::from))
94 }
95}
96
97impl<'a> IntoSql<'a> for &'a [u8] {
98 fn into_sql(self) -> ColumnData<'a> {
99 ColumnData::Binary(Some(Cow::Borrowed(self)))
100 }
101}
102
103impl<'a> IntoSql<'a> for Option<&'a [u8]> {
104 fn into_sql(self) -> ColumnData<'a> {
105 ColumnData::Binary(self.map(Cow::Borrowed))
106 }
107}
108
109impl<'a> IntoSql<'a> for &'a Vec<u8> {
110 fn into_sql(self) -> ColumnData<'a> {
111 ColumnData::Binary(Some(Cow::from(self)))
112 }
113}
114
115impl<'a> IntoSql<'a> for Option<&'a Vec<u8>> {
116 fn into_sql(self) -> ColumnData<'a> {
117 ColumnData::Binary(self.map(Cow::from))
118 }
119}
120
121impl<'a> IntoSql<'a> for Cow<'a, str> {
122 fn into_sql(self) -> ColumnData<'a> {
123 ColumnData::String(Some(self))
124 }
125}
126
127impl<'a> IntoSql<'a> for Option<Cow<'a, str>> {
128 fn into_sql(self) -> ColumnData<'a> {
129 ColumnData::String(self)
130 }
131}
132
133impl<'a> IntoSql<'a> for Cow<'a, [u8]> {
134 fn into_sql(self) -> ColumnData<'a> {
135 ColumnData::Binary(Some(self))
136 }
137}
138
139impl<'a> IntoSql<'a> for Option<Cow<'a, [u8]>> {
140 fn into_sql(self) -> ColumnData<'a> {
141 ColumnData::Binary(self)
142 }
143}
144
145impl<'a> IntoSql<'a> for &'a XmlData {
146 fn into_sql(self) -> ColumnData<'a> {
147 ColumnData::Xml(Some(Cow::Borrowed(self)))
148 }
149}
150
151impl<'a> IntoSql<'a> for Option<&'a XmlData> {
152 fn into_sql(self) -> ColumnData<'a> {
153 ColumnData::Xml(self.map(Cow::Borrowed))
154 }
155}
156
157impl<'a> IntoSql<'a> for &'a Uuid {
158 fn into_sql(self) -> ColumnData<'a> {
159 ColumnData::Guid(Some(*self))
160 }
161}
162
163impl<'a> IntoSql<'a> for Option<&'a Uuid> {
164 fn into_sql(self) -> ColumnData<'a> {
165 ColumnData::Guid(self.copied())
166 }
167}
168
169into_sql!(self_,
170 String: (ColumnData::String, Cow::from(self_));
171 Vec<u8>: (ColumnData::Binary, Cow::from(self_));
172 Numeric: (ColumnData::Numeric, self_);
173 XmlData: (ColumnData::Xml, Cow::Owned(self_));
174 Uuid: (ColumnData::Guid, self_);
175 bool: (ColumnData::Bit, self_);
176 u8: (ColumnData::U8, self_);
177 i16: (ColumnData::I16, self_);
178 i32: (ColumnData::I32, self_);
179 i64: (ColumnData::I64, self_);
180 f32: (ColumnData::F32, self_);
181 f64: (ColumnData::F64, self_);
182);
183
184to_sql!(self_,
185 bool: (ColumnData::Bit, *self_);
186 u8: (ColumnData::U8, *self_);
187 i16: (ColumnData::I16, *self_);
188 i32: (ColumnData::I32, *self_);
189 i64: (ColumnData::I64, *self_);
190 f32: (ColumnData::F32, *self_);
191 f64: (ColumnData::F64, *self_);
192 &str: (ColumnData::String, Cow::from(*self_));
193 String: (ColumnData::String, Cow::from(self_));
194 Cow<'_, str>: (ColumnData::String, self_.clone());
195 &[u8]: (ColumnData::Binary, Cow::from(*self_));
196 Cow<'_, [u8]>: (ColumnData::Binary, self_.clone());
197 Vec<u8>: (ColumnData::Binary, Cow::from(self_));
198 Numeric: (ColumnData::Numeric, *self_);
199 XmlData: (ColumnData::Xml, Cow::Borrowed(self_));
200 Uuid: (ColumnData::Guid, *self_);
201);
202
203#[cfg(test)]
204mod tests {
205 use super::*;
206 use crate::tds::Numeric;
207 use crate::{IntoSql, ToSql};
208
209 #[test]
210 fn to_sql_scalars() {
211 assert_eq!(true.to_sql(), ColumnData::Bit(Some(true)));
212 assert_eq!(8u8.to_sql(), ColumnData::U8(Some(8)));
213 assert_eq!(16i16.to_sql(), ColumnData::I16(Some(16)));
214 assert_eq!(32i32.to_sql(), ColumnData::I32(Some(32)));
215 assert_eq!(64i64.to_sql(), ColumnData::I64(Some(64)));
216 assert_eq!(1.5f32.to_sql(), ColumnData::F32(Some(1.5)));
217 assert_eq!(2.5f64.to_sql(), ColumnData::F64(Some(2.5)));
218 }
219
220 #[test]
221 #[allow(clippy::needless_borrow)]
224 fn to_sql_option_some_and_none() {
225 assert_eq!(Some(1i32).to_sql(), ColumnData::I32(Some(1)));
226 assert_eq!(None::<i32>.to_sql(), ColumnData::I32(None));
227 assert_eq!((&Some(1i32)).to_sql(), ColumnData::I32(Some(1)));
228 assert_eq!((&None::<i32>).to_sql(), ColumnData::I32(None));
229 }
230
231 #[test]
232 fn to_sql_strings_and_binary() {
233 assert_eq!("abc".to_sql(), ColumnData::String(Some(Cow::from("abc"))));
234 assert_eq!(
235 String::from("abc").to_sql(),
236 ColumnData::String(Some(Cow::from("abc")))
237 );
238 let v = vec![1u8, 2, 3];
239 assert_eq!(
240 v.to_sql(),
241 ColumnData::Binary(Some(Cow::from(vec![1, 2, 3])))
242 );
243 assert_eq!(
244 [1u8, 2, 3].as_slice().to_sql(),
245 ColumnData::Binary(Some(Cow::from(vec![1, 2, 3])))
246 );
247 }
248
249 #[test]
250 fn to_sql_numeric_and_uuid() {
251 let n = Numeric::new_with_scale(5, 1);
252 assert_eq!(n.to_sql(), ColumnData::Numeric(Some(n)));
253
254 let uuid = Uuid::nil();
255 assert_eq!(uuid.to_sql(), ColumnData::Guid(Some(uuid)));
256 }
257
258 #[test]
259 fn into_sql_borrowed_and_owned() {
260 assert_eq!(
261 "abc".into_sql(),
262 ColumnData::String(Some(Cow::Borrowed("abc")))
263 );
264 assert_eq!(
265 Some("abc").into_sql(),
266 ColumnData::String(Some(Cow::Borrowed("abc")))
267 );
268 assert_eq!(None::<&str>.into_sql(), ColumnData::String(None));
269
270 let bytes = vec![9u8, 8, 7];
271 assert_eq!(
272 bytes.as_slice().into_sql(),
273 ColumnData::Binary(Some(Cow::Borrowed(bytes.as_slice())))
274 );
275 assert_eq!(
276 (&bytes).into_sql(),
277 ColumnData::Binary(Some(Cow::from(&bytes)))
278 );
279
280 let uuid = Uuid::nil();
281 assert_eq!((&uuid).into_sql(), ColumnData::Guid(Some(uuid)));
282 assert_eq!(Some(&uuid).into_sql(), ColumnData::Guid(Some(uuid)));
283 assert_eq!(None::<&Uuid>.into_sql(), ColumnData::Guid(None));
284 }
285
286 #[test]
287 fn into_sql_scalars() {
288 assert_eq!(true.into_sql(), ColumnData::Bit(Some(true)));
289 assert_eq!(5i32.into_sql(), ColumnData::I32(Some(5)));
290 assert_eq!(None::<i32>.into_sql(), ColumnData::I32(None));
291 assert_eq!(
292 String::from("x").into_sql(),
293 ColumnData::String(Some(Cow::from("x")))
294 );
295 }
296
297 #[test]
298 fn into_sql_owned_string_and_ref() {
299 let owned = String::from("abc");
300 assert_eq!(
301 (&owned).into_sql(),
302 ColumnData::String(Some(Cow::from("abc")))
303 );
304 assert_eq!(
305 Some(&owned).into_sql(),
306 ColumnData::String(Some(Cow::from("abc")))
307 );
308 assert_eq!(None::<&String>.into_sql(), ColumnData::String(None));
309 }
310
311 #[test]
312 fn into_sql_binary_option_variants() {
313 assert_eq!(None::<&[u8]>.into_sql(), ColumnData::Binary(None));
314
315 let bytes = vec![1u8, 2, 3];
316 assert_eq!(
317 Some(bytes.as_slice()).into_sql(),
318 ColumnData::Binary(Some(Cow::from(bytes.as_slice())))
319 );
320 assert_eq!(None::<&Vec<u8>>.into_sql(), ColumnData::Binary(None));
321 assert_eq!(
322 bytes.into_sql(),
323 ColumnData::Binary(Some(Cow::from(vec![1, 2, 3])))
324 );
325 }
326
327 #[test]
328 fn into_sql_cow_variants() {
329 let cow_str: Cow<'_, str> = Cow::Borrowed("hi");
330 assert_eq!(
331 cow_str.into_sql(),
332 ColumnData::String(Some(Cow::from("hi")))
333 );
334 assert_eq!(
335 Some(Cow::Borrowed("hi")).into_sql(),
336 ColumnData::String(Some(Cow::from("hi")))
337 );
338 assert_eq!(None::<Cow<'_, str>>.into_sql(), ColumnData::String(None));
339
340 let cow_bin: Cow<'_, [u8]> = Cow::Borrowed(&[1u8, 2][..]);
341 assert_eq!(
342 cow_bin.into_sql(),
343 ColumnData::Binary(Some(Cow::from(vec![1u8, 2])))
344 );
345 assert_eq!(
346 Some(Cow::<[u8]>::Borrowed(&[1u8, 2][..])).into_sql(),
347 ColumnData::Binary(Some(Cow::from(vec![1u8, 2])))
348 );
349 assert_eq!(None::<Cow<'_, [u8]>>.into_sql(), ColumnData::Binary(None));
350 }
351
352 #[test]
353 fn into_sql_xml_and_numeric() {
354 let xml = XmlData::new("<a/>".to_string());
355 assert_eq!(
356 (&xml).into_sql(),
357 ColumnData::Xml(Some(Cow::Borrowed(&xml)))
358 );
359 assert_eq!(
360 Some(&xml).into_sql(),
361 ColumnData::Xml(Some(Cow::Borrowed(&xml)))
362 );
363 assert_eq!(None::<&XmlData>.into_sql(), ColumnData::Xml(None));
364
365 let xml_owned = XmlData::new("<b/>".to_string());
366 assert_eq!(
367 xml_owned.clone().into_sql(),
368 ColumnData::Xml(Some(Cow::Owned(xml_owned)))
369 );
370
371 let n = Numeric::new_with_scale(42, 0);
372 assert_eq!(n.into_sql(), ColumnData::Numeric(Some(n)));
373 }
374
375 #[test]
376 #[allow(clippy::needless_borrow)]
379 fn to_sql_by_reference_scalars() {
380 assert_eq!((&true).to_sql(), ColumnData::Bit(Some(true)));
382 assert_eq!((&8u8).to_sql(), ColumnData::U8(Some(8)));
383 assert_eq!((&16i16).to_sql(), ColumnData::I16(Some(16)));
384 assert_eq!((&64i64).to_sql(), ColumnData::I64(Some(64)));
385 assert_eq!((&1.5f32).to_sql(), ColumnData::F32(Some(1.5)));
386 assert_eq!((&2.5f64).to_sql(), ColumnData::F64(Some(2.5)));
387 }
388
389 #[test]
390 fn to_sql_cow_variants() {
391 let cow_str: Cow<'_, str> = Cow::Borrowed("hi");
392 assert_eq!(cow_str.to_sql(), ColumnData::String(Some(Cow::from("hi"))));
393
394 let cow_bin: Cow<'_, [u8]> = Cow::Borrowed(&[1u8, 2][..]);
395 assert_eq!(
396 cow_bin.to_sql(),
397 ColumnData::Binary(Some(Cow::from(vec![1u8, 2])))
398 );
399 }
400
401 #[test]
402 fn to_sql_xml() {
403 let xml = XmlData::new("<a/>".to_string());
404 assert_eq!(xml.to_sql(), ColumnData::Xml(Some(Cow::Borrowed(&xml))));
405 }
406}