fastnum/decimal/udec/extras/diesel/
mysql.rs

1use core::fmt::{Debug, Display, Write};
2
3use diesel::{
4    deserialize::{self, FromSql},
5    mysql::{Mysql, MysqlType, MysqlValue},
6    serialize::{self, IsNull, Output, ToSql},
7    sql_types::Numeric,
8};
9
10use crate::decimal::{Context, UnsignedDecimal};
11
12impl<const N: usize> ToSql<Numeric, Mysql> for UnsignedDecimal<N>
13where
14    for<'a, 'b> Output<'a, 'b, Mysql>: Write,
15    UnsignedDecimal<N>: Debug + Display,
16{
17    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> serialize::Result {
18        write!(out, "{}", *self)
19            .map(|_| IsNull::No)
20            .map_err(Into::into)
21    }
22}
23
24impl<const N: usize> FromSql<Numeric, Mysql> for UnsignedDecimal<N> {
25    fn from_sql(value: MysqlValue<'_>) -> deserialize::Result<Self> {
26        let raw = value.as_bytes();
27
28        match value.value_type() {
29            MysqlType::UnsignedTiny => {
30                let i = raw[0];
31                Ok(i.into())
32            }
33            MysqlType::Tiny => {
34                let i = raw[0] as i8;
35                i.try_into()
36                    .map_err(|_| format!("{i} is not valid decimal number").into())
37            }
38            MysqlType::UnsignedShort => {
39                let i = u16::from_ne_bytes((&raw[..2]).try_into()?);
40                Ok(i.into())
41            }
42            MysqlType::Short => {
43                let i = i16::from_ne_bytes((&raw[..2]).try_into()?);
44                i.try_into()
45                    .map_err(|_| format!("{i} is not valid decimal number").into())
46            }
47            MysqlType::UnsignedLong => {
48                let i = u32::from_ne_bytes((&raw[..4]).try_into()?);
49                Ok(i.into())
50            }
51            MysqlType::Long => {
52                let i = i32::from_ne_bytes((&raw[..4]).try_into()?);
53                i.try_into()
54                    .map_err(|_| format!("{i} is not valid decimal number").into())
55            }
56            MysqlType::UnsignedLongLong => {
57                let i = u64::from_ne_bytes(raw.try_into()?);
58                Ok(i.into())
59            }
60            MysqlType::LongLong => {
61                let i = i64::from_ne_bytes(raw.try_into()?);
62                i.try_into()
63                    .map_err(|_| format!("{i} is not valid decimal number").into())
64            }
65            MysqlType::Float => {
66                let i = f32::from_ne_bytes(raw.try_into()?);
67                i.try_into()
68                    .map_err(|_| format!("{i} is not valid decimal number").into())
69            }
70            MysqlType::Double => {
71                let i = f64::from_ne_bytes(raw.try_into()?);
72                i.try_into()
73                    .map_err(|_| format!("{i} is not valid decimal number").into())
74            }
75            MysqlType::Numeric => {
76                let s = core::str::from_utf8(raw)?;
77                UnsignedDecimal::from_str(s, Context::default())
78                    .map_err(|_| format!("{s} is not valid decimal number").into())
79            }
80            _ => Err(format!("{value:?} is not valid decimal number").into()),
81        }
82    }
83}