Skip to main content

sqlx_repo/
decimal.rs

1use std::{
2    fmt,
3    ops::{Deref, DerefMut},
4    str::FromStr,
5};
6
7use sqlx::{
8    Decode, Encode,
9    encode::IsNull,
10    mysql::{MySql, MySqlTypeInfo, MySqlValueRef},
11    postgres::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueRef, Postgres},
12    sqlite::{Sqlite, SqliteArgumentsBuffer, SqliteTypeInfo, SqliteValueRef},
13    types::{Decimal as Inner, Type},
14};
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
17#[repr(transparent)]
18pub struct Decimal(pub Inner);
19
20impl Deref for Decimal {
21    type Target = Inner;
22
23    fn deref(&self) -> &Self::Target {
24        &self.0
25    }
26}
27
28impl DerefMut for Decimal {
29    fn deref_mut(&mut self) -> &mut Self::Target {
30        &mut self.0
31    }
32}
33
34impl From<Inner> for Decimal {
35    fn from(v: Inner) -> Self {
36        Self(v)
37    }
38}
39
40impl From<Decimal> for Inner {
41    fn from(v: Decimal) -> Self {
42        v.0
43    }
44}
45
46impl fmt::Display for Decimal {
47    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48        fmt::Display::fmt(&self.0, f)
49    }
50}
51
52impl FromStr for Decimal {
53    type Err = <Inner as FromStr>::Err;
54
55    fn from_str(s: &str) -> Result<Self, Self::Err> {
56        Inner::from_str(s).map(Self)
57    }
58}
59
60// SQLite: stored as TEXT (SQLite has no native decimal type)
61
62impl Type<Sqlite> for Decimal {
63    fn type_info() -> SqliteTypeInfo {
64        <String as Type<Sqlite>>::type_info()
65    }
66
67    fn compatible(ty: &SqliteTypeInfo) -> bool {
68        <String as Type<Sqlite>>::compatible(ty)
69    }
70}
71
72impl Encode<'_, Sqlite> for Decimal {
73    fn encode_by_ref(
74        &self,
75        buf: &mut SqliteArgumentsBuffer,
76    ) -> Result<IsNull, Box<dyn std::error::Error + Send + Sync>> {
77        <String as Encode<Sqlite>>::encode(self.0.to_string(), buf)
78    }
79}
80
81impl<'r> Decode<'r, Sqlite> for Decimal {
82    fn decode(value: SqliteValueRef<'r>) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
83        let s = <String as Decode<Sqlite>>::decode(value)?;
84        Inner::from_str(&s).map(Self).map_err(Into::into)
85    }
86}
87
88// Postgres: delegates to the inner Decimal impl (NUMERIC type)
89
90impl Type<Postgres> for Decimal {
91    fn type_info() -> PgTypeInfo {
92        <Inner as Type<Postgres>>::type_info()
93    }
94
95    fn compatible(ty: &PgTypeInfo) -> bool {
96        <Inner as Type<Postgres>>::compatible(ty)
97    }
98}
99
100impl PgHasArrayType for Decimal {
101    fn array_type_info() -> PgTypeInfo {
102        <Inner as PgHasArrayType>::array_type_info()
103    }
104}
105
106impl Encode<'_, Postgres> for Decimal {
107    fn encode_by_ref(
108        &self,
109        buf: &mut PgArgumentBuffer,
110    ) -> Result<IsNull, Box<dyn std::error::Error + Send + Sync>> {
111        <Inner as Encode<Postgres>>::encode_by_ref(&self.0, buf)
112    }
113}
114
115impl<'r> Decode<'r, Postgres> for Decimal {
116    fn decode(value: PgValueRef<'r>) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
117        <Inner as Decode<Postgres>>::decode(value).map(Self)
118    }
119}
120
121// MySQL: delegates to the inner Decimal impl (DECIMAL/NUMERIC type)
122
123impl Type<MySql> for Decimal {
124    fn type_info() -> MySqlTypeInfo {
125        <Inner as Type<MySql>>::type_info()
126    }
127
128    fn compatible(ty: &MySqlTypeInfo) -> bool {
129        <Inner as Type<MySql>>::compatible(ty)
130    }
131}
132
133impl Encode<'_, MySql> for Decimal {
134    fn encode_by_ref(
135        &self,
136        buf: &mut Vec<u8>,
137    ) -> Result<IsNull, Box<dyn std::error::Error + Send + Sync>> {
138        <Inner as Encode<MySql>>::encode_by_ref(&self.0, buf)
139    }
140}
141
142impl<'r> Decode<'r, MySql> for Decimal {
143    fn decode(value: MySqlValueRef<'r>) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
144        <Inner as Decode<MySql>>::decode(value).map(Self)
145    }
146}