1use crate::prelude::*;
4use crate::{
5 sql::{ColumnRef, SQL, TableRef, Token},
6 traits::SQLParam,
7};
8
9#[cfg(feature = "uuid")]
10use uuid::Uuid;
11
12#[diagnostic::on_unimplemented(
18 message = "`{Self}` cannot be converted to SQL",
19 label = "this type does not implement ToSQL for the current dialect",
20 note = "tuples larger than the enabled arity need a larger `colN` feature (col16, col32, col64, col128, col200) on drizzle-core"
21)]
22pub trait ToSQL<'a, V: SQLParam> {
23 fn to_sql(&self) -> SQL<'a, V>;
24
25 fn into_sql(self) -> SQL<'a, V>
29 where
30 Self: Sized,
31 {
32 self.to_sql()
33 }
34}
35
36#[derive(Debug, Clone)]
48pub struct SQLBytes<'a>(pub Cow<'a, [u8]>);
49
50#[derive(Debug, Clone, Copy, Default)]
52pub struct SQLNull;
53
54impl<'a> SQLBytes<'a> {
55 #[inline]
56 pub fn new(bytes: impl Into<Cow<'a, [u8]>>) -> Self {
57 Self(bytes.into())
58 }
59}
60
61impl<'a, V: SQLParam + 'a> ToSQL<'a, V> for SQLNull {
62 fn to_sql(&self) -> SQL<'a, V> {
63 SQL::raw("NULL")
64 }
65}
66
67impl<'a, T, V> From<&T> for SQL<'a, V>
68where
69 T: ToSQL<'a, V>,
70 V: SQLParam,
71{
72 fn from(value: &T) -> Self {
73 value.to_sql()
74 }
75}
76
77impl<'a, V: SQLParam, T> ToSQL<'a, V> for &T
78where
79 T: ToSQL<'a, V>,
80{
81 fn to_sql(&self) -> SQL<'a, V> {
82 (**self).to_sql()
83 }
84}
85
86impl<'a, V: SQLParam + 'a> ToSQL<'a, V> for () {
87 fn to_sql(&self) -> SQL<'a, V> {
88 SQL::empty()
89 }
90}
91
92impl<'a, V, T> ToSQL<'a, V> for Vec<T>
93where
94 V: SQLParam + 'a,
95 T: ToSQL<'a, V>,
96{
97 fn to_sql(&self) -> SQL<'a, V> {
98 SQL::join(self.iter().map(ToSQL::to_sql), Token::COMMA)
99 }
100}
101
102impl<'a, V, T> ToSQL<'a, V> for &'a [T]
103where
104 V: SQLParam + 'a,
105 T: ToSQL<'a, V>,
106{
107 fn to_sql(&self) -> SQL<'a, V> {
108 SQL::join(self.iter().map(ToSQL::to_sql), Token::COMMA)
109 }
110}
111
112impl<'a, V, T, const N: usize> ToSQL<'a, V> for [T; N]
113where
114 V: SQLParam + 'a,
115 T: ToSQL<'a, V>,
116{
117 fn to_sql(&self) -> SQL<'a, V> {
118 SQL::join(self.iter().map(ToSQL::to_sql), Token::COMMA)
119 }
120}
121
122impl<'a, V: SQLParam + 'a> ToSQL<'a, V> for TableRef {
123 fn to_sql(&self) -> SQL<'a, V> {
124 SQL::table(*self)
125 }
126}
127
128impl<'a, V: SQLParam + 'a> ToSQL<'a, V> for ColumnRef {
129 fn to_sql(&self) -> SQL<'a, V> {
130 SQL::column(*self)
131 }
132}
133
134impl<'a, V> ToSQL<'a, V> for &'a str
136where
137 V: SQLParam + 'a + From<&'a str> + Into<Cow<'a, V>>,
138{
139 fn to_sql(&self) -> SQL<'a, V> {
140 SQL::param(V::from(self))
141 }
142}
143
144impl<'a, V> ToSQL<'a, V> for Box<str>
145where
146 V: SQLParam + 'a + From<String> + Into<Cow<'a, V>>,
147{
148 fn to_sql(&self) -> SQL<'a, V> {
149 SQL::param(V::from(self.to_string()))
150 }
151
152 fn into_sql(self) -> SQL<'a, V> {
153 SQL::param(V::from(self.into_string()))
154 }
155}
156
157#[cfg(any(feature = "std", feature = "alloc"))]
158impl<'a, V> ToSQL<'a, V> for Rc<str>
159where
160 V: SQLParam + 'a + From<String> + Into<Cow<'a, V>>,
161{
162 fn to_sql(&self) -> SQL<'a, V> {
163 SQL::param(V::from(self.as_ref().to_string()))
164 }
165}
166
167#[cfg(any(feature = "std", feature = "alloc"))]
168impl<'a, V> ToSQL<'a, V> for Arc<str>
169where
170 V: SQLParam + 'a + From<String> + Into<Cow<'a, V>>,
171{
172 fn to_sql(&self) -> SQL<'a, V> {
173 SQL::param(V::from(self.as_ref().to_string()))
174 }
175}
176
177impl<'a, V, T> ToSQL<'a, V> for Box<T>
178where
179 V: SQLParam + 'a,
180 T: ToSQL<'a, V>,
181{
182 fn to_sql(&self) -> SQL<'a, V> {
183 (**self).to_sql()
184 }
185}
186
187#[cfg(any(feature = "std", feature = "alloc"))]
188impl<'a, V, T> ToSQL<'a, V> for Rc<T>
189where
190 V: SQLParam + 'a,
191 T: ToSQL<'a, V>,
192{
193 fn to_sql(&self) -> SQL<'a, V> {
194 (**self).to_sql()
195 }
196}
197
198#[cfg(any(feature = "std", feature = "alloc"))]
199impl<'a, V, T> ToSQL<'a, V> for Arc<T>
200where
201 V: SQLParam + 'a,
202 T: ToSQL<'a, V>,
203{
204 fn to_sql(&self) -> SQL<'a, V> {
205 (**self).to_sql()
206 }
207}
208
209impl<'a, V> ToSQL<'a, V> for String
210where
211 V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
212{
213 fn to_sql(&self) -> SQL<'a, V> {
214 SQL::param(V::from(self.clone()))
215 }
216
217 fn into_sql(self) -> SQL<'a, V> {
218 SQL::param(V::from(self))
219 }
220}
221
222#[cfg(feature = "compact-str")]
223impl<'a, V> ToSQL<'a, V> for compact_str::CompactString
224where
225 V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
226{
227 fn to_sql(&self) -> SQL<'a, V> {
228 SQL::param(V::from(self.clone()))
229 }
230
231 fn into_sql(self) -> SQL<'a, V> {
232 SQL::param(V::from(self))
233 }
234}
235
236#[cfg(feature = "bytes")]
237impl<'a, V> ToSQL<'a, V> for bytes::Bytes
238where
239 V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
240{
241 fn to_sql(&self) -> SQL<'a, V> {
242 SQL::param(V::from(self.clone()))
243 }
244
245 fn into_sql(self) -> SQL<'a, V> {
246 SQL::param(V::from(self))
247 }
248}
249
250#[cfg(feature = "bytes")]
251impl<'a, V> ToSQL<'a, V> for bytes::BytesMut
252where
253 V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
254{
255 fn to_sql(&self) -> SQL<'a, V> {
256 SQL::param(V::from(self.clone()))
257 }
258
259 fn into_sql(self) -> SQL<'a, V> {
260 SQL::param(V::from(self))
261 }
262}
263
264#[cfg(feature = "arrayvec")]
265impl<'a, V, const N: usize> ToSQL<'a, V> for arrayvec::ArrayString<N>
266where
267 V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
268{
269 fn to_sql(&self) -> SQL<'a, V> {
270 SQL::param(V::from(*self))
271 }
272
273 fn into_sql(self) -> SQL<'a, V> {
274 SQL::param(V::from(self))
275 }
276}
277
278#[cfg(feature = "arrayvec")]
279impl<'a, V, const N: usize> ToSQL<'a, V> for arrayvec::ArrayVec<u8, N>
280where
281 V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
282{
283 fn to_sql(&self) -> SQL<'a, V> {
284 SQL::param(V::from(self.clone()))
285 }
286
287 fn into_sql(self) -> SQL<'a, V> {
288 SQL::param(V::from(self))
289 }
290}
291
292#[cfg(feature = "smallvec-types")]
293impl<'a, V, const N: usize> ToSQL<'a, V> for smallvec::SmallVec<[u8; N]>
294where
295 V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
296{
297 fn to_sql(&self) -> SQL<'a, V> {
298 SQL::param(V::from(self.clone()))
299 }
300
301 fn into_sql(self) -> SQL<'a, V> {
302 SQL::param(V::from(self))
303 }
304}
305
306impl<'a, V> ToSQL<'a, V> for Cow<'a, str>
307where
308 V: SQLParam + 'a + From<&'a str> + From<String> + Into<Cow<'a, V>>,
309{
310 fn to_sql(&self) -> SQL<'a, V> {
311 match self {
312 Cow::Borrowed(value) => SQL::param(V::from(*value)),
313 Cow::Owned(value) => SQL::param(V::from(value.clone())),
314 }
315 }
316
317 fn into_sql(self) -> SQL<'a, V> {
318 match self {
319 Cow::Borrowed(value) => SQL::param(V::from(value)),
320 Cow::Owned(value) => SQL::param(V::from(value)),
321 }
322 }
323}
324
325impl<'a, V> ToSQL<'a, V> for Cow<'a, [u8]>
326where
327 V: SQLParam + 'a + From<&'a [u8]> + From<Vec<u8>> + Into<Cow<'a, V>>,
328{
329 fn to_sql(&self) -> SQL<'a, V> {
330 match self {
331 Cow::Borrowed(value) => SQL::param(V::from(*value)),
332 Cow::Owned(value) => SQL::param(V::from(value.clone())),
333 }
334 }
335
336 fn into_sql(self) -> SQL<'a, V> {
337 match self {
338 Cow::Borrowed(value) => SQL::param(V::from(value)),
339 Cow::Owned(value) => SQL::param(V::from(value)),
340 }
341 }
342}
343
344impl<'a, V> ToSQL<'a, V> for SQLBytes<'a>
345where
346 V: SQLParam + 'a + From<&'a [u8]> + From<Vec<u8>> + Into<Cow<'a, V>>,
347{
348 fn to_sql(&self) -> SQL<'a, V> {
349 match &self.0 {
350 Cow::Borrowed(value) => SQL::param(V::from(*value)),
351 Cow::Owned(value) => SQL::param(V::from(value.clone())),
352 }
353 }
354
355 fn into_sql(self) -> SQL<'a, V> {
356 match self.0 {
357 Cow::Borrowed(value) => SQL::param(V::from(value)),
358 Cow::Owned(value) => SQL::param(V::from(value)),
359 }
360 }
361}
362
363macro_rules! impl_tosql_param_copy {
364 ($($ty:ty),+ $(,)?) => {
365 $(
366 impl<'a, V> ToSQL<'a, V> for $ty
367 where
368 V: SQLParam + 'a + From<$ty>,
369 V: Into<Cow<'a, V>>,
370 {
371 fn to_sql(&self) -> SQL<'a, V> {
372 SQL::param(V::from(*self))
373 }
374 }
375 )+
376 };
377}
378
379impl_tosql_param_copy!(
380 i8, i16, i32, i64, f32, f64, bool, char, u8, u16, u32, u64, isize, usize
381);
382
383impl<'a, V, T> ToSQL<'a, V> for Option<T>
384where
385 V: SQLParam + 'a,
386 T: ToSQL<'a, V>,
387{
388 fn to_sql(&self) -> SQL<'a, V> {
389 self.as_ref()
390 .map_or_else(|| SQLNull.to_sql(), ToSQL::to_sql)
391 }
392}
393
394#[cfg(feature = "uuid")]
395impl<'a, V> ToSQL<'a, V> for Uuid
396where
397 V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
398{
399 fn to_sql(&self) -> SQL<'a, V> {
400 SQL::param(V::from(*self))
401 }
402}
403
404#[cfg(feature = "chrono")]
406impl_tosql_param_copy!(
407 chrono::NaiveDate,
408 chrono::NaiveTime,
409 chrono::NaiveDateTime,
410 chrono::DateTime<chrono::Utc>,
411 chrono::DateTime<chrono::FixedOffset>,
412 chrono::Duration,
413);
414
415#[cfg(feature = "time")]
416impl_tosql_param_copy!(
417 time::Date,
418 time::Time,
419 time::PrimitiveDateTime,
420 time::OffsetDateTime,
421 time::Duration,
422);
423
424#[cfg(feature = "jiff")]
425impl_tosql_param_copy!(
426 jiff::civil::Date,
427 jiff::civil::Time,
428 jiff::civil::DateTime,
429 jiff::Timestamp,
430);
431
432#[cfg(feature = "rust-decimal")]
433impl<'a, V> ToSQL<'a, V> for rust_decimal::Decimal
434where
435 V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
436{
437 fn to_sql(&self) -> SQL<'a, V> {
438 SQL::param(V::from(*self))
439 }
440}