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