Skip to main content

drizzle_mysql/values/
conversions.rs

1//! Primitive conversions into MySQL parameter values.
2
3use super::MySQLValue;
4use crate::prelude::*;
5
6macro_rules! integer_values {
7    ($($variant:ident: [$($ty:ty),+ $(,)?]),+ $(,)?) => {
8        $(
9            $(
10                impl From<$ty> for MySQLValue<'_> {
11                    fn from(value: $ty) -> Self {
12                        Self::$variant(value as _)
13                    }
14                }
15
16                impl From<&$ty> for MySQLValue<'_> {
17                    fn from(value: &$ty) -> Self {
18                        Self::from(*value)
19                    }
20                }
21            )+
22        )+
23    };
24}
25
26integer_values!(
27    Int: [i8, i16, i32, i64, isize],
28    UInt: [u8, u16, u32, u64, usize],
29);
30
31impl From<bool> for MySQLValue<'_> {
32    fn from(value: bool) -> Self {
33        Self::Int(i64::from(value))
34    }
35}
36
37impl From<&bool> for MySQLValue<'_> {
38    fn from(value: &bool) -> Self {
39        Self::from(*value)
40    }
41}
42
43impl From<char> for MySQLValue<'_> {
44    fn from(value: char) -> Self {
45        Self::from(String::from(value))
46    }
47}
48
49impl From<f32> for MySQLValue<'_> {
50    fn from(value: f32) -> Self {
51        Self::Float(value)
52    }
53}
54
55impl From<&f32> for MySQLValue<'_> {
56    fn from(value: &f32) -> Self {
57        Self::Float(*value)
58    }
59}
60
61impl From<f64> for MySQLValue<'_> {
62    fn from(value: f64) -> Self {
63        Self::Double(value)
64    }
65}
66
67impl From<&f64> for MySQLValue<'_> {
68    fn from(value: &f64) -> Self {
69        Self::Double(*value)
70    }
71}
72
73impl<'a> From<&'a str> for MySQLValue<'a> {
74    fn from(value: &'a str) -> Self {
75        Self::Bytes(Cow::Borrowed(value.as_bytes()))
76    }
77}
78
79impl<'a> From<Cow<'a, str>> for MySQLValue<'a> {
80    fn from(value: Cow<'a, str>) -> Self {
81        match value {
82            Cow::Borrowed(value) => Self::Bytes(Cow::Borrowed(value.as_bytes())),
83            Cow::Owned(value) => Self::Bytes(Cow::Owned(value.into_bytes())),
84        }
85    }
86}
87
88impl From<String> for MySQLValue<'_> {
89    fn from(value: String) -> Self {
90        Self::Bytes(Cow::Owned(value.into_bytes()))
91    }
92}
93
94impl<'a> From<&'a String> for MySQLValue<'a> {
95    fn from(value: &'a String) -> Self {
96        Self::from(value.as_str())
97    }
98}
99
100macro_rules! owned_string_wrapper {
101    ($wrapper:ident) => {
102        impl From<$wrapper<String>> for MySQLValue<'_> {
103            fn from(value: $wrapper<String>) -> Self {
104                Self::Bytes(Cow::Owned(value.as_bytes().to_vec()))
105            }
106        }
107
108        impl<'a> From<&'a $wrapper<String>> for MySQLValue<'a> {
109            fn from(value: &'a $wrapper<String>) -> Self {
110                Self::Bytes(Cow::Borrowed(value.as_bytes()))
111            }
112        }
113
114        impl From<$wrapper<str>> for MySQLValue<'_> {
115            fn from(value: $wrapper<str>) -> Self {
116                Self::Bytes(Cow::Owned(value.as_bytes().to_vec()))
117            }
118        }
119
120        impl<'a> From<&'a $wrapper<str>> for MySQLValue<'a> {
121            fn from(value: &'a $wrapper<str>) -> Self {
122                Self::Bytes(Cow::Borrowed(value.as_bytes()))
123            }
124        }
125    };
126}
127
128owned_string_wrapper!(Box);
129owned_string_wrapper!(Rc);
130owned_string_wrapper!(Arc);
131
132#[cfg(feature = "compact-str")]
133impl From<compact_str::CompactString> for MySQLValue<'_> {
134    fn from(value: compact_str::CompactString) -> Self {
135        Self::Bytes(Cow::Owned(value.as_bytes().to_vec()))
136    }
137}
138
139#[cfg(feature = "compact-str")]
140impl<'a> From<&'a compact_str::CompactString> for MySQLValue<'a> {
141    fn from(value: &'a compact_str::CompactString) -> Self {
142        Self::Bytes(Cow::Borrowed(value.as_bytes()))
143    }
144}
145
146#[cfg(feature = "arrayvec")]
147impl<const N: usize> From<arrayvec::ArrayString<N>> for MySQLValue<'_> {
148    fn from(value: arrayvec::ArrayString<N>) -> Self {
149        Self::Bytes(Cow::Owned(value.as_bytes().to_vec()))
150    }
151}
152
153#[cfg(feature = "arrayvec")]
154impl<'a, const N: usize> From<&'a arrayvec::ArrayString<N>> for MySQLValue<'a> {
155    fn from(value: &'a arrayvec::ArrayString<N>) -> Self {
156        Self::Bytes(Cow::Borrowed(value.as_bytes()))
157    }
158}
159
160impl<'a> From<&'a [u8]> for MySQLValue<'a> {
161    fn from(value: &'a [u8]) -> Self {
162        Self::Bytes(Cow::Borrowed(value))
163    }
164}
165
166impl<'a> From<Cow<'a, [u8]>> for MySQLValue<'a> {
167    fn from(value: Cow<'a, [u8]>) -> Self {
168        Self::Bytes(value)
169    }
170}
171
172impl From<Vec<u8>> for MySQLValue<'_> {
173    fn from(value: Vec<u8>) -> Self {
174        Self::Bytes(Cow::Owned(value))
175    }
176}
177
178impl<const N: usize> From<[u8; N]> for MySQLValue<'_> {
179    fn from(value: [u8; N]) -> Self {
180        Self::Bytes(Cow::Owned(value.to_vec()))
181    }
182}
183
184impl<'a, const N: usize> From<&'a [u8; N]> for MySQLValue<'a> {
185    fn from(value: &'a [u8; N]) -> Self {
186        Self::Bytes(Cow::Borrowed(value))
187    }
188}
189
190impl<const N: usize> From<[char; N]> for MySQLValue<'_> {
191    fn from(value: [char; N]) -> Self {
192        Self::from(value.into_iter().collect::<String>())
193    }
194}
195
196impl<const N: usize> From<&[char; N]> for MySQLValue<'_> {
197    fn from(value: &[char; N]) -> Self {
198        Self::from(value.iter().collect::<String>())
199    }
200}
201
202macro_rules! owned_bytes_wrapper {
203    ($wrapper:ident) => {
204        impl From<$wrapper<Vec<u8>>> for MySQLValue<'_> {
205            fn from(value: $wrapper<Vec<u8>>) -> Self {
206                Self::Bytes(Cow::Owned(value.as_slice().to_vec()))
207            }
208        }
209
210        impl<'a> From<&'a $wrapper<Vec<u8>>> for MySQLValue<'a> {
211            fn from(value: &'a $wrapper<Vec<u8>>) -> Self {
212                Self::Bytes(Cow::Borrowed(value.as_slice()))
213            }
214        }
215    };
216}
217
218owned_bytes_wrapper!(Box);
219owned_bytes_wrapper!(Rc);
220owned_bytes_wrapper!(Arc);
221
222#[cfg(feature = "arrayvec")]
223impl<const N: usize> From<arrayvec::ArrayVec<u8, N>> for MySQLValue<'_> {
224    fn from(value: arrayvec::ArrayVec<u8, N>) -> Self {
225        Self::Bytes(Cow::Owned(value.into_iter().collect()))
226    }
227}
228
229#[cfg(feature = "arrayvec")]
230impl<'a, const N: usize> From<&'a arrayvec::ArrayVec<u8, N>> for MySQLValue<'a> {
231    fn from(value: &'a arrayvec::ArrayVec<u8, N>) -> Self {
232        Self::Bytes(Cow::Borrowed(value.as_slice()))
233    }
234}
235
236#[cfg(feature = "smallvec")]
237impl<const N: usize> From<smallvec::SmallVec<[u8; N]>> for MySQLValue<'_> {
238    fn from(value: smallvec::SmallVec<[u8; N]>) -> Self {
239        Self::Bytes(Cow::Owned(value.into_vec()))
240    }
241}
242
243#[cfg(feature = "smallvec")]
244impl<'a, const N: usize> From<&'a smallvec::SmallVec<[u8; N]>> for MySQLValue<'a> {
245    fn from(value: &'a smallvec::SmallVec<[u8; N]>) -> Self {
246        Self::Bytes(Cow::Borrowed(value.as_slice()))
247    }
248}
249
250#[cfg(feature = "bytes")]
251impl From<bytes::Bytes> for MySQLValue<'_> {
252    fn from(value: bytes::Bytes) -> Self {
253        Self::Bytes(Cow::Owned(value.to_vec()))
254    }
255}
256
257#[cfg(feature = "bytes")]
258impl From<bytes::BytesMut> for MySQLValue<'_> {
259    fn from(value: bytes::BytesMut) -> Self {
260        Self::Bytes(Cow::Owned(value.to_vec()))
261    }
262}
263
264#[cfg(feature = "bytes")]
265impl From<&bytes::Bytes> for MySQLValue<'_> {
266    fn from(value: &bytes::Bytes) -> Self {
267        Self::Bytes(Cow::Owned(value.to_vec()))
268    }
269}
270
271#[cfg(feature = "bytes")]
272impl From<&bytes::BytesMut> for MySQLValue<'_> {
273    fn from(value: &bytes::BytesMut) -> Self {
274        Self::Bytes(Cow::Owned(value.to_vec()))
275    }
276}
277
278#[cfg(feature = "uuid")]
279impl From<uuid::Uuid> for MySQLValue<'_> {
280    fn from(value: uuid::Uuid) -> Self {
281        Self::Bytes(Cow::Owned(value.into_bytes().to_vec()))
282    }
283}
284
285#[cfg(feature = "uuid")]
286impl<'a> From<&'a uuid::Uuid> for MySQLValue<'a> {
287    fn from(value: &'a uuid::Uuid) -> Self {
288        Self::Bytes(Cow::Borrowed(value.as_bytes()))
289    }
290}
291
292#[cfg(feature = "serde")]
293impl From<serde_json::Value> for MySQLValue<'_> {
294    fn from(value: serde_json::Value) -> Self {
295        Self::Bytes(Cow::Owned(value.to_string().into_bytes()))
296    }
297}
298
299#[cfg(feature = "serde")]
300impl From<&serde_json::Value> for MySQLValue<'_> {
301    fn from(value: &serde_json::Value) -> Self {
302        Self::Bytes(Cow::Owned(value.to_string().into_bytes()))
303    }
304}
305
306#[cfg(feature = "rust-decimal")]
307impl From<rust_decimal::Decimal> for MySQLValue<'_> {
308    fn from(value: rust_decimal::Decimal) -> Self {
309        Self::Bytes(Cow::Owned(value.to_string().into_bytes()))
310    }
311}
312
313#[cfg(feature = "rust-decimal")]
314impl From<&rust_decimal::Decimal> for MySQLValue<'_> {
315    fn from(value: &rust_decimal::Decimal) -> Self {
316        Self::Bytes(Cow::Owned(value.to_string().into_bytes()))
317    }
318}
319
320#[cfg(any(feature = "chrono", feature = "time", feature = "jiff"))]
321struct DateParts {
322    year: i32,
323    month: u8,
324    day: u8,
325    hour: u8,
326    minute: u8,
327    second: u8,
328    microseconds: u32,
329}
330
331#[cfg(any(feature = "chrono", feature = "time", feature = "jiff"))]
332fn date_value(parts: DateParts, fallback: String) -> MySQLValue<'static> {
333    match u16::try_from(parts.year) {
334        Ok(year) if (1000..=9999).contains(&year) => MySQLValue::Date {
335            year,
336            month: parts.month,
337            day: parts.day,
338            hour: parts.hour,
339            minute: parts.minute,
340            second: parts.second,
341            microseconds: parts.microseconds,
342        },
343        _ => MySQLValue::Bytes(Cow::Owned(fallback.into_bytes())),
344    }
345}
346
347#[cfg(feature = "chrono")]
348fn chrono_date(value: chrono::NaiveDate) -> MySQLValue<'static> {
349    use chrono::Datelike;
350
351    date_value(
352        DateParts {
353            year: value.year(),
354            month: value.month() as u8,
355            day: value.day() as u8,
356            hour: 0,
357            minute: 0,
358            second: 0,
359            microseconds: 0,
360        },
361        value.to_string(),
362    )
363}
364
365#[cfg(feature = "chrono")]
366fn chrono_datetime(value: chrono::NaiveDateTime) -> MySQLValue<'static> {
367    use chrono::{Datelike, Timelike};
368
369    date_value(
370        DateParts {
371            year: value.year(),
372            month: value.month() as u8,
373            day: value.day() as u8,
374            hour: value.hour() as u8,
375            minute: value.minute() as u8,
376            second: value.second() as u8,
377            microseconds: value.nanosecond() / 1_000,
378        },
379        value.to_string(),
380    )
381}
382
383#[cfg(feature = "chrono")]
384impl From<chrono::NaiveDate> for MySQLValue<'_> {
385    fn from(value: chrono::NaiveDate) -> Self {
386        chrono_date(value)
387    }
388}
389
390#[cfg(feature = "chrono")]
391impl From<&chrono::NaiveDate> for MySQLValue<'_> {
392    fn from(value: &chrono::NaiveDate) -> Self {
393        chrono_date(*value)
394    }
395}
396
397#[cfg(feature = "chrono")]
398impl From<chrono::NaiveTime> for MySQLValue<'_> {
399    fn from(value: chrono::NaiveTime) -> Self {
400        use chrono::Timelike;
401
402        Self::Time {
403            negative: false,
404            days: 0,
405            hours: value.hour() as u8,
406            minutes: value.minute() as u8,
407            seconds: value.second() as u8,
408            microseconds: value.nanosecond() / 1_000,
409        }
410    }
411}
412
413#[cfg(feature = "chrono")]
414impl From<&chrono::NaiveTime> for MySQLValue<'_> {
415    fn from(value: &chrono::NaiveTime) -> Self {
416        Self::from(*value)
417    }
418}
419
420#[cfg(feature = "chrono")]
421impl From<chrono::NaiveDateTime> for MySQLValue<'_> {
422    fn from(value: chrono::NaiveDateTime) -> Self {
423        chrono_datetime(value)
424    }
425}
426
427#[cfg(feature = "chrono")]
428impl From<&chrono::NaiveDateTime> for MySQLValue<'_> {
429    fn from(value: &chrono::NaiveDateTime) -> Self {
430        chrono_datetime(*value)
431    }
432}
433
434#[cfg(feature = "chrono")]
435impl From<chrono::DateTime<chrono::Utc>> for MySQLValue<'_> {
436    fn from(value: chrono::DateTime<chrono::Utc>) -> Self {
437        chrono_datetime(value.naive_utc())
438    }
439}
440
441#[cfg(feature = "chrono")]
442impl From<chrono::DateTime<chrono::FixedOffset>> for MySQLValue<'_> {
443    fn from(value: chrono::DateTime<chrono::FixedOffset>) -> Self {
444        chrono_datetime(value.with_timezone(&chrono::Utc).naive_utc())
445    }
446}
447
448#[cfg(feature = "time")]
449fn time_date(value: time::Date) -> MySQLValue<'static> {
450    date_value(
451        DateParts {
452            year: value.year(),
453            month: u8::from(value.month()),
454            day: value.day(),
455            hour: 0,
456            minute: 0,
457            second: 0,
458            microseconds: 0,
459        },
460        value.to_string(),
461    )
462}
463
464#[cfg(feature = "time")]
465fn time_datetime(value: time::PrimitiveDateTime) -> MySQLValue<'static> {
466    date_value(
467        DateParts {
468            year: value.year(),
469            month: u8::from(value.month()),
470            day: value.day(),
471            hour: value.hour(),
472            minute: value.minute(),
473            second: value.second(),
474            microseconds: value.microsecond(),
475        },
476        value.to_string(),
477    )
478}
479
480#[cfg(feature = "time")]
481impl From<time::Date> for MySQLValue<'_> {
482    fn from(value: time::Date) -> Self {
483        time_date(value)
484    }
485}
486
487#[cfg(feature = "time")]
488impl From<&time::Date> for MySQLValue<'_> {
489    fn from(value: &time::Date) -> Self {
490        time_date(*value)
491    }
492}
493
494#[cfg(feature = "time")]
495impl From<time::Time> for MySQLValue<'_> {
496    fn from(value: time::Time) -> Self {
497        Self::Time {
498            negative: false,
499            days: 0,
500            hours: value.hour(),
501            minutes: value.minute(),
502            seconds: value.second(),
503            microseconds: value.microsecond(),
504        }
505    }
506}
507
508#[cfg(feature = "time")]
509impl From<&time::Time> for MySQLValue<'_> {
510    fn from(value: &time::Time) -> Self {
511        Self::from(*value)
512    }
513}
514
515#[cfg(feature = "time")]
516impl From<time::PrimitiveDateTime> for MySQLValue<'_> {
517    fn from(value: time::PrimitiveDateTime) -> Self {
518        time_datetime(value)
519    }
520}
521
522#[cfg(feature = "time")]
523impl From<&time::PrimitiveDateTime> for MySQLValue<'_> {
524    fn from(value: &time::PrimitiveDateTime) -> Self {
525        time_datetime(*value)
526    }
527}
528
529#[cfg(feature = "time")]
530impl From<time::OffsetDateTime> for MySQLValue<'_> {
531    fn from(value: time::OffsetDateTime) -> Self {
532        let utc = value.to_offset(time::UtcOffset::UTC);
533        time_datetime(time::PrimitiveDateTime::new(utc.date(), utc.time()))
534    }
535}
536
537#[cfg(feature = "jiff")]
538fn jiff_date(value: jiff::civil::Date) -> MySQLValue<'static> {
539    date_value(
540        DateParts {
541            year: i32::from(value.year()),
542            month: value.month().unsigned_abs(),
543            day: value.day().unsigned_abs(),
544            hour: 0,
545            minute: 0,
546            second: 0,
547            microseconds: 0,
548        },
549        value.to_string(),
550    )
551}
552
553#[cfg(feature = "jiff")]
554fn jiff_datetime(value: jiff::civil::DateTime) -> MySQLValue<'static> {
555    date_value(
556        DateParts {
557            year: i32::from(value.year()),
558            month: value.month().unsigned_abs(),
559            day: value.day().unsigned_abs(),
560            hour: value.hour().unsigned_abs(),
561            minute: value.minute().unsigned_abs(),
562            second: value.second().unsigned_abs(),
563            microseconds: value.subsec_nanosecond().unsigned_abs() / 1_000,
564        },
565        value.to_string(),
566    )
567}
568
569#[cfg(feature = "jiff")]
570impl From<jiff::civil::Date> for MySQLValue<'_> {
571    fn from(value: jiff::civil::Date) -> Self {
572        jiff_date(value)
573    }
574}
575
576#[cfg(feature = "jiff")]
577impl From<&jiff::civil::Date> for MySQLValue<'_> {
578    fn from(value: &jiff::civil::Date) -> Self {
579        jiff_date(*value)
580    }
581}
582
583#[cfg(feature = "jiff")]
584impl From<jiff::civil::Time> for MySQLValue<'_> {
585    fn from(value: jiff::civil::Time) -> Self {
586        Self::Time {
587            negative: false,
588            days: 0,
589            hours: value.hour().unsigned_abs(),
590            minutes: value.minute().unsigned_abs(),
591            seconds: value.second().unsigned_abs(),
592            microseconds: value.subsec_nanosecond().unsigned_abs() / 1_000,
593        }
594    }
595}
596
597#[cfg(feature = "jiff")]
598impl From<&jiff::civil::Time> for MySQLValue<'_> {
599    fn from(value: &jiff::civil::Time) -> Self {
600        Self::from(*value)
601    }
602}
603
604#[cfg(feature = "jiff")]
605impl From<jiff::civil::DateTime> for MySQLValue<'_> {
606    fn from(value: jiff::civil::DateTime) -> Self {
607        jiff_datetime(value)
608    }
609}
610
611#[cfg(feature = "jiff")]
612impl From<&jiff::civil::DateTime> for MySQLValue<'_> {
613    fn from(value: &jiff::civil::DateTime) -> Self {
614        jiff_datetime(*value)
615    }
616}
617
618/// A timestamp binds as its UTC date and time: typed queries run in a UTC
619/// session, where MySQL reads a TIMESTAMP that way.
620#[cfg(feature = "jiff")]
621impl From<jiff::Timestamp> for MySQLValue<'_> {
622    fn from(value: jiff::Timestamp) -> Self {
623        jiff_datetime(jiff::tz::Offset::UTC.to_datetime(value))
624    }
625}
626
627#[cfg(feature = "jiff")]
628impl From<&jiff::Timestamp> for MySQLValue<'_> {
629    fn from(value: &jiff::Timestamp) -> Self {
630        Self::from(*value)
631    }
632}
633
634impl<'a, T> From<Option<T>> for MySQLValue<'a>
635where
636    MySQLValue<'a>: From<T>,
637{
638    fn from(value: Option<T>) -> Self {
639        value.map_or(Self::Null, MySQLValue::from)
640    }
641}
642
643impl<'a> From<MySQLValue<'a>> for Cow<'a, MySQLValue<'a>> {
644    fn from(value: MySQLValue<'a>) -> Self {
645        Cow::Owned(value)
646    }
647}
648
649impl<'a> From<&'a MySQLValue<'a>> for Cow<'a, MySQLValue<'a>> {
650    fn from(value: &'a MySQLValue<'a>) -> Self {
651        Cow::Borrowed(value)
652    }
653}