diesel/mysql/types/
mod.rs

1//! MySQL specific types
2
3pub(super) mod date_and_time;
4#[cfg(feature = "serde_json")]
5mod json;
6mod numeric;
7mod primitives;
8
9use crate::deserialize::{self, FromSql};
10use crate::mysql::{Mysql, MysqlType, MysqlValue};
11use crate::query_builder::QueryId;
12use crate::serialize::{self, IsNull, Output, ToSql};
13use crate::sql_types::*;
14use crate::sql_types::{self, ops::*};
15use byteorder::{NativeEndian, WriteBytesExt};
16
17#[cfg(feature = "mysql_backend")]
18impl ToSql<TinyInt, Mysql> for i8 {
19    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> serialize::Result {
20        out.write_i8(*self).map(|_| IsNull::No).map_err(Into::into)
21    }
22}
23
24#[cfg(feature = "mysql_backend")]
25impl FromSql<TinyInt, Mysql> for i8 {
26    fn from_sql(value: MysqlValue<'_>) -> deserialize::Result<Self> {
27        let bytes = value.as_bytes();
28        Ok(i8::from_be_bytes([bytes[0]]))
29    }
30}
31
32/// Represents the MySQL unsigned type.
33#[derive(Debug, Clone, Copy, Default, SqlType, QueryId)]
34#[cfg(feature = "mysql_backend")]
35pub struct Unsigned<ST: 'static>(ST);
36
37impl<T> Add for Unsigned<T>
38where
39    T: Add,
40{
41    type Rhs = Unsigned<T::Rhs>;
42    type Output = Unsigned<T::Output>;
43}
44
45impl<T> Sub for Unsigned<T>
46where
47    T: Sub,
48{
49    type Rhs = Unsigned<T::Rhs>;
50    type Output = Unsigned<T::Output>;
51}
52
53impl<T> Mul for Unsigned<T>
54where
55    T: Mul,
56{
57    type Rhs = Unsigned<T::Rhs>;
58    type Output = Unsigned<T::Output>;
59}
60
61impl<T> Div for Unsigned<T>
62where
63    T: Div,
64{
65    type Rhs = Unsigned<T::Rhs>;
66    type Output = Unsigned<T::Output>;
67}
68
69#[cfg(feature = "mysql_backend")]
70impl ToSql<Unsigned<TinyInt>, Mysql> for u8 {
71    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> serialize::Result {
72        out.write_u8(*self)?;
73        Ok(IsNull::No)
74    }
75}
76
77#[cfg(feature = "mysql_backend")]
78impl FromSql<Unsigned<TinyInt>, Mysql> for u8 {
79    #[allow(clippy::cast_possible_wrap, clippy::cast_sign_loss)] // that's what we want
80    fn from_sql(bytes: MysqlValue<'_>) -> deserialize::Result<Self> {
81        let signed: i8 = FromSql::<TinyInt, Mysql>::from_sql(bytes)?;
82        Ok(signed as u8)
83    }
84}
85
86#[cfg(feature = "mysql_backend")]
87impl ToSql<Unsigned<SmallInt>, Mysql> for u16 {
88    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> serialize::Result {
89        out.write_u16::<NativeEndian>(*self)?;
90        Ok(IsNull::No)
91    }
92}
93
94#[cfg(feature = "mysql_backend")]
95impl FromSql<Unsigned<SmallInt>, Mysql> for u16 {
96    #[allow(
97        clippy::cast_possible_wrap,
98        clippy::cast_sign_loss,
99        clippy::cast_possible_truncation
100    )] // that's what we want
101    fn from_sql(bytes: MysqlValue<'_>) -> deserialize::Result<Self> {
102        let signed: i32 = FromSql::<Integer, Mysql>::from_sql(bytes)?;
103        Ok(signed as u16)
104    }
105}
106
107#[cfg(feature = "mysql_backend")]
108impl ToSql<Unsigned<Integer>, Mysql> for u32 {
109    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> serialize::Result {
110        out.write_u32::<NativeEndian>(*self)?;
111        Ok(IsNull::No)
112    }
113}
114
115#[cfg(feature = "mysql_backend")]
116impl FromSql<Unsigned<Integer>, Mysql> for u32 {
117    #[allow(
118        clippy::cast_possible_wrap,
119        clippy::cast_sign_loss,
120        clippy::cast_possible_truncation
121    )] // that's what we want
122    fn from_sql(bytes: MysqlValue<'_>) -> deserialize::Result<Self> {
123        let signed: i64 = FromSql::<BigInt, Mysql>::from_sql(bytes)?;
124        Ok(signed as u32)
125    }
126}
127
128#[cfg(feature = "mysql_backend")]
129impl ToSql<Unsigned<BigInt>, Mysql> for u64 {
130    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> serialize::Result {
131        out.write_u64::<NativeEndian>(*self)?;
132        Ok(IsNull::No)
133    }
134}
135
136#[cfg(feature = "mysql_backend")]
137impl FromSql<Unsigned<BigInt>, Mysql> for u64 {
138    #[allow(
139        clippy::cast_possible_wrap,
140        clippy::cast_sign_loss,
141        clippy::cast_possible_truncation
142    )] // that's what we want
143    fn from_sql(bytes: MysqlValue<'_>) -> deserialize::Result<Self> {
144        let signed: i64 = FromSql::<BigInt, Mysql>::from_sql(bytes)?;
145        Ok(signed as u64)
146    }
147}
148
149#[cfg(feature = "mysql_backend")]
150impl ToSql<Bool, Mysql> for bool {
151    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> serialize::Result {
152        let int_value = i32::from(*self);
153        <i32 as ToSql<Integer, Mysql>>::to_sql(&int_value, &mut out.reborrow())
154    }
155}
156
157#[cfg(feature = "mysql_backend")]
158impl FromSql<Bool, Mysql> for bool {
159    fn from_sql(bytes: MysqlValue<'_>) -> deserialize::Result<Self> {
160        Ok(bytes.as_bytes().iter().any(|x| *x != 0))
161    }
162}
163
164#[cfg(feature = "mysql_backend")]
165impl ToSql<sql_types::SmallInt, Mysql> for i16 {
166    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> serialize::Result {
167        out.write_i16::<NativeEndian>(*self)
168            .map(|_| IsNull::No)
169            .map_err(|e| Box::new(e) as Box<_>)
170    }
171}
172
173#[cfg(feature = "mysql_backend")]
174impl ToSql<sql_types::Integer, Mysql> for i32 {
175    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> serialize::Result {
176        out.write_i32::<NativeEndian>(*self)
177            .map(|_| IsNull::No)
178            .map_err(|e| Box::new(e) as Box<_>)
179    }
180}
181
182#[cfg(feature = "mysql_backend")]
183impl ToSql<sql_types::BigInt, Mysql> for i64 {
184    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> serialize::Result {
185        out.write_i64::<NativeEndian>(*self)
186            .map(|_| IsNull::No)
187            .map_err(|e| Box::new(e) as Box<_>)
188    }
189}
190
191#[cfg(feature = "mysql_backend")]
192impl ToSql<sql_types::Double, Mysql> for f64 {
193    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> serialize::Result {
194        out.write_f64::<NativeEndian>(*self)
195            .map(|_| IsNull::No)
196            .map_err(|e| Box::new(e) as Box<_>)
197    }
198}
199
200#[cfg(feature = "mysql_backend")]
201impl ToSql<sql_types::Float, Mysql> for f32 {
202    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> serialize::Result {
203        out.write_f32::<NativeEndian>(*self)
204            .map(|_| IsNull::No)
205            .map_err(|e| Box::new(e) as Box<_>)
206    }
207}
208
209#[cfg(feature = "mysql_backend")]
210impl HasSqlType<Unsigned<TinyInt>> for Mysql {
211    fn metadata(_lookup: &mut ()) -> MysqlType {
212        MysqlType::UnsignedTiny
213    }
214}
215
216#[cfg(feature = "mysql_backend")]
217impl HasSqlType<Unsigned<SmallInt>> for Mysql {
218    fn metadata(_lookup: &mut ()) -> MysqlType {
219        MysqlType::UnsignedShort
220    }
221}
222
223#[cfg(feature = "mysql_backend")]
224impl HasSqlType<Unsigned<Integer>> for Mysql {
225    fn metadata(_lookup: &mut ()) -> MysqlType {
226        MysqlType::UnsignedLong
227    }
228}
229
230#[cfg(feature = "mysql_backend")]
231impl HasSqlType<Unsigned<BigInt>> for Mysql {
232    fn metadata(_lookup: &mut ()) -> MysqlType {
233        MysqlType::UnsignedLongLong
234    }
235}
236
237/// Represents the MySQL datetime type.
238///
239/// ### [`ToSql`] impls
240///
241/// - [`chrono::NaiveDateTime`] with `feature = "chrono"`
242/// - [`time::PrimitiveDateTime`] with `feature = "time"`
243/// - [`time::OffsetDateTime`] with `feature = "time"`
244///
245/// ### [`FromSql`] impls
246///
247/// - [`chrono::NaiveDateTime`] with `feature = "chrono"`
248/// - [`time::PrimitiveDateTime`] with `feature = "time"`
249/// - [`time::OffsetDateTime`] with `feature = "time"`
250///
251/// [`ToSql`]: crate::serialize::ToSql
252/// [`FromSql`]: crate::deserialize::FromSql
253#[cfg_attr(
254    feature = "chrono",
255    doc = " [`chrono::NaiveDateTime`]: chrono::naive::NaiveDateTime"
256)]
257#[cfg_attr(
258    not(feature = "chrono"),
259    doc = " [`chrono::NaiveDateTime`]: https://docs.rs/chrono/0.4.19/chrono/naive/struct.NaiveDateTime.html"
260)]
261#[cfg_attr(
262    feature = "time",
263    doc = " [`time::PrimitiveDateTime`]: time::PrimitiveDateTime"
264)]
265#[cfg_attr(
266    not(feature = "time"),
267    doc = " [`time::PrimitiveDateTime`]: https://docs.rs/time/0.3.9/time/struct.PrimitiveDateTime.html"
268)]
269#[cfg_attr(
270    feature = "time",
271    doc = " [`time::OffsetDateTime`]: time::OffsetDateTime"
272)]
273#[cfg_attr(
274    not(feature = "time"),
275    doc = " [`time::OffsetDateTime`]: https://docs.rs/time/0.3.9/time/struct.OffsetDateTime.html"
276)]
277#[derive(Debug, Clone, Copy, Default, QueryId, SqlType)]
278#[diesel(mysql_type(name = "DateTime"))]
279#[cfg(feature = "mysql_backend")]
280pub struct Datetime;