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(
49 message = "`{Self}` cannot be converted to SQL",
50 label = "this type does not implement ToSQL for the current dialect",
51 note = "tuples larger than the enabled arity need a larger `colN` feature (col16, col32, col64, col128, col200) on drizzle-core"
52)]
53pub trait ToSQL<'a, V: SQLParam> {
54 fn to_sql(&self) -> SQL<'a, V>;
56
57 fn into_sql(self) -> SQL<'a, V>
62 where
63 Self: Sized,
64 {
65 self.to_sql()
66 }
67}
68
69#[derive(Debug, Clone)]
103pub struct SQLBytes<'a>(pub Cow<'a, [u8]>);
104
105#[derive(Debug, Clone, Copy, Default)]
107pub struct SQLNull;
108
109impl<'a> SQLBytes<'a> {
110 #[inline]
112 pub fn new(bytes: impl Into<Cow<'a, [u8]>>) -> Self {
113 Self(bytes.into())
114 }
115}
116
117impl<'a, V: SQLParam + 'a> ToSQL<'a, V> for SQLNull {
118 fn to_sql(&self) -> SQL<'a, V> {
119 SQL::raw("NULL")
120 }
121}
122
123impl<'a, T, V> From<&T> for SQL<'a, V>
124where
125 T: ToSQL<'a, V>,
126 V: SQLParam,
127{
128 fn from(value: &T) -> Self {
129 value.to_sql()
130 }
131}
132
133impl<'a, V: SQLParam, T> ToSQL<'a, V> for &T
134where
135 T: ToSQL<'a, V>,
136{
137 fn to_sql(&self) -> SQL<'a, V> {
138 (**self).to_sql()
139 }
140}
141
142impl<'a, V: SQLParam + 'a> ToSQL<'a, V> for () {
143 fn to_sql(&self) -> SQL<'a, V> {
144 SQL::empty()
145 }
146}
147
148impl<'a, V, T> ToSQL<'a, V> for Vec<T>
149where
150 V: SQLParam + 'a,
151 T: ToSQL<'a, V>,
152{
153 fn to_sql(&self) -> SQL<'a, V> {
154 SQL::join(self.iter().map(ToSQL::to_sql), Token::COMMA)
155 }
156}
157
158impl<'a, V, T> ToSQL<'a, V> for &'a [T]
159where
160 V: SQLParam + 'a,
161 T: ToSQL<'a, V>,
162{
163 fn to_sql(&self) -> SQL<'a, V> {
164 SQL::join(self.iter().map(ToSQL::to_sql), Token::COMMA)
165 }
166}
167
168impl<'a, V, T, const N: usize> ToSQL<'a, V> for [T; N]
169where
170 V: SQLParam + 'a,
171 T: ToSQL<'a, V>,
172{
173 fn to_sql(&self) -> SQL<'a, V> {
174 SQL::join(self.iter().map(ToSQL::to_sql), Token::COMMA)
175 }
176}
177
178impl<'a, V: SQLParam + 'a> ToSQL<'a, V> for TableRef {
179 fn to_sql(&self) -> SQL<'a, V> {
180 SQL::table(*self)
181 }
182}
183
184impl<'a, V: SQLParam + 'a> ToSQL<'a, V> for ColumnRef {
185 fn to_sql(&self) -> SQL<'a, V> {
186 SQL::column(*self)
187 }
188}
189
190impl<'a, V> ToSQL<'a, V> for &'a str
192where
193 V: SQLParam + 'a + From<&'a str> + Into<Cow<'a, V>>,
194{
195 fn to_sql(&self) -> SQL<'a, V> {
196 SQL::param(V::from(self))
197 }
198}
199
200impl<'a, V> ToSQL<'a, V> for Box<str>
201where
202 V: SQLParam + 'a + From<String> + Into<Cow<'a, V>>,
203{
204 fn to_sql(&self) -> SQL<'a, V> {
205 SQL::param(V::from(self.to_string()))
206 }
207
208 fn into_sql(self) -> SQL<'a, V> {
209 SQL::param(V::from(self.into_string()))
210 }
211}
212
213#[cfg(any(feature = "std", feature = "alloc"))]
214impl<'a, V> ToSQL<'a, V> for Rc<str>
215where
216 V: SQLParam + 'a + From<String> + Into<Cow<'a, V>>,
217{
218 fn to_sql(&self) -> SQL<'a, V> {
219 SQL::param(V::from(self.as_ref().to_string()))
220 }
221}
222
223#[cfg(any(feature = "std", feature = "alloc"))]
224impl<'a, V> ToSQL<'a, V> for Arc<str>
225where
226 V: SQLParam + 'a + From<String> + Into<Cow<'a, V>>,
227{
228 fn to_sql(&self) -> SQL<'a, V> {
229 SQL::param(V::from(self.as_ref().to_string()))
230 }
231}
232
233impl<'a, V, T> ToSQL<'a, V> for Box<T>
234where
235 V: SQLParam + 'a,
236 T: ToSQL<'a, V>,
237{
238 fn to_sql(&self) -> SQL<'a, V> {
239 (**self).to_sql()
240 }
241}
242
243#[cfg(any(feature = "std", feature = "alloc"))]
244impl<'a, V, T> ToSQL<'a, V> for Rc<T>
245where
246 V: SQLParam + 'a,
247 T: ToSQL<'a, V>,
248{
249 fn to_sql(&self) -> SQL<'a, V> {
250 (**self).to_sql()
251 }
252}
253
254#[cfg(any(feature = "std", feature = "alloc"))]
255impl<'a, V, T> ToSQL<'a, V> for Arc<T>
256where
257 V: SQLParam + 'a,
258 T: ToSQL<'a, V>,
259{
260 fn to_sql(&self) -> SQL<'a, V> {
261 (**self).to_sql()
262 }
263}
264
265impl<'a, V> ToSQL<'a, V> for String
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.clone()))
271 }
272
273 fn into_sql(self) -> SQL<'a, V> {
274 SQL::param(V::from(self))
275 }
276}
277
278#[cfg(feature = "compact-str")]
279impl<'a, V> ToSQL<'a, V> for compact_str::CompactString
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 = "bytes")]
293impl<'a, V> ToSQL<'a, V> for bytes::Bytes
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
306#[cfg(feature = "bytes")]
307impl<'a, V> ToSQL<'a, V> for bytes::BytesMut
308where
309 V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
310{
311 fn to_sql(&self) -> SQL<'a, V> {
312 SQL::param(V::from(self.clone()))
313 }
314
315 fn into_sql(self) -> SQL<'a, V> {
316 SQL::param(V::from(self))
317 }
318}
319
320#[cfg(feature = "arrayvec")]
321impl<'a, V, const N: usize> ToSQL<'a, V> for arrayvec::ArrayString<N>
322where
323 V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
324{
325 fn to_sql(&self) -> SQL<'a, V> {
326 SQL::param(V::from(*self))
327 }
328
329 fn into_sql(self) -> SQL<'a, V> {
330 SQL::param(V::from(self))
331 }
332}
333
334#[cfg(feature = "arrayvec")]
335impl<'a, V, const N: usize> ToSQL<'a, V> for arrayvec::ArrayVec<u8, N>
336where
337 V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
338{
339 fn to_sql(&self) -> SQL<'a, V> {
340 SQL::param(V::from(self.clone()))
341 }
342
343 fn into_sql(self) -> SQL<'a, V> {
344 SQL::param(V::from(self))
345 }
346}
347
348#[cfg(feature = "smallvec-types")]
349impl<'a, V, const N: usize> ToSQL<'a, V> for smallvec::SmallVec<[u8; N]>
350where
351 V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
352{
353 fn to_sql(&self) -> SQL<'a, V> {
354 SQL::param(V::from(self.clone()))
355 }
356
357 fn into_sql(self) -> SQL<'a, V> {
358 SQL::param(V::from(self))
359 }
360}
361
362impl<'a, V> ToSQL<'a, V> for Cow<'a, str>
363where
364 V: SQLParam + 'a + From<&'a str> + From<String> + Into<Cow<'a, V>>,
365{
366 fn to_sql(&self) -> SQL<'a, V> {
367 match self {
368 Cow::Borrowed(value) => SQL::param(V::from(*value)),
369 Cow::Owned(value) => SQL::param(V::from(value.clone())),
370 }
371 }
372
373 fn into_sql(self) -> SQL<'a, V> {
374 match self {
375 Cow::Borrowed(value) => SQL::param(V::from(value)),
376 Cow::Owned(value) => SQL::param(V::from(value)),
377 }
378 }
379}
380
381impl<'a, V> ToSQL<'a, V> for Cow<'a, [u8]>
382where
383 V: SQLParam + 'a + From<&'a [u8]> + From<Vec<u8>> + Into<Cow<'a, V>>,
384{
385 fn to_sql(&self) -> SQL<'a, V> {
386 match self {
387 Cow::Borrowed(value) => SQL::param(V::from(*value)),
388 Cow::Owned(value) => SQL::param(V::from(value.clone())),
389 }
390 }
391
392 fn into_sql(self) -> SQL<'a, V> {
393 match self {
394 Cow::Borrowed(value) => SQL::param(V::from(value)),
395 Cow::Owned(value) => SQL::param(V::from(value)),
396 }
397 }
398}
399
400impl<'a, V> ToSQL<'a, V> for SQLBytes<'a>
401where
402 V: SQLParam + 'a + From<&'a [u8]> + From<Vec<u8>> + Into<Cow<'a, V>>,
403{
404 fn to_sql(&self) -> SQL<'a, V> {
405 match &self.0 {
406 Cow::Borrowed(value) => SQL::param(V::from(*value)),
407 Cow::Owned(value) => SQL::param(V::from(value.clone())),
408 }
409 }
410
411 fn into_sql(self) -> SQL<'a, V> {
412 match self.0 {
413 Cow::Borrowed(value) => SQL::param(V::from(value)),
414 Cow::Owned(value) => SQL::param(V::from(value)),
415 }
416 }
417}
418
419macro_rules! impl_tosql_param_copy {
420 ($($ty:ty),+ $(,)?) => {
421 $(
422 impl<'a, V> ToSQL<'a, V> for $ty
423 where
424 V: SQLParam + 'a + From<$ty>,
425 V: Into<Cow<'a, V>>,
426 {
427 fn to_sql(&self) -> SQL<'a, V> {
428 SQL::param(V::from(*self))
429 }
430 }
431 )+
432 };
433}
434
435impl_tosql_param_copy!(
436 i8, i16, i32, i64, f32, f64, bool, char, u8, u16, u32, u64, isize, usize
437);
438
439impl<'a, V, T> ToSQL<'a, V> for Option<T>
440where
441 V: SQLParam + 'a,
442 T: ToSQL<'a, V>,
443{
444 fn to_sql(&self) -> SQL<'a, V> {
445 self.as_ref()
446 .map_or_else(|| SQLNull.to_sql(), ToSQL::to_sql)
447 }
448}
449
450#[cfg(feature = "uuid")]
451impl<'a, V> ToSQL<'a, V> for Uuid
452where
453 V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
454{
455 fn to_sql(&self) -> SQL<'a, V> {
456 SQL::param(V::from(*self))
457 }
458}
459
460#[cfg(feature = "chrono")]
462impl_tosql_param_copy!(
463 chrono::NaiveDate,
464 chrono::NaiveTime,
465 chrono::NaiveDateTime,
466 chrono::DateTime<chrono::Utc>,
467 chrono::DateTime<chrono::FixedOffset>,
468 chrono::Duration,
469);
470
471#[cfg(feature = "time")]
472impl_tosql_param_copy!(
473 time::Date,
474 time::Time,
475 time::PrimitiveDateTime,
476 time::OffsetDateTime,
477 time::Duration,
478);
479
480#[cfg(feature = "jiff")]
481impl_tosql_param_copy!(
482 jiff::civil::Date,
483 jiff::civil::Time,
484 jiff::civil::DateTime,
485 jiff::Timestamp,
486);
487
488#[cfg(feature = "rust-decimal")]
489impl<'a, V> ToSQL<'a, V> for rust_decimal::Decimal
490where
491 V: SQLParam + 'a + From<Self> + Into<Cow<'a, V>>,
492{
493 fn to_sql(&self) -> SQL<'a, V> {
494 SQL::param(V::from(*self))
495 }
496}