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