1#![cfg_attr(docsrs, doc(cfg(feature = "sqlx")))]
16
17use std::str::FromStr;
18use thiserror::Error;
19
20use sqlx_core::{
21 database::Database,
22 decode::Decode,
23 encode::{Encode, IsNull},
24 error::BoxDynError,
25 types::Type,
26};
27
28#[derive(Error, Debug)]
33pub enum DecodeError {
34 #[error("Address decode error: source {0}")]
36 AddressDecodeError(String),
37
38 #[error("Uint decode error: source {0}")]
40 UintDecodeError(String),
41
42 #[error("FixedBytes decode error: source {0}")]
44 FixedBytesDecodeError(String),
45
46 #[error("Bytes decode error: source {0}")]
48 BytesDecodeError(String),
49}
50
51use crate::{SqlAddress, SqlBytes, SqlFixedBytes, SqlUint};
52
53impl<DB: Database> Type<DB> for SqlAddress
55where
56 String: Type<DB>,
57{
58 fn type_info() -> DB::TypeInfo {
59 <String as Type<DB>>::type_info()
60 }
61
62 fn compatible(ty: &DB::TypeInfo) -> bool {
63 <String as Type<DB>>::compatible(ty)
64 }
65}
66
67impl<'a, DB: Database> Encode<'a, DB> for SqlAddress
68where
69 String: Encode<'a, DB>,
70{
71 fn encode_by_ref(
72 &self,
73 buf: &mut <DB as Database>::ArgumentBuffer<'a>,
74 ) -> Result<IsNull, BoxDynError> {
75 self.to_string().to_lowercase().encode_by_ref(buf)
76 }
77}
78
79impl<'a, DB: Database> Decode<'a, DB> for SqlAddress
80where
81 String: Decode<'a, DB>,
82{
83 fn decode(value: <DB as Database>::ValueRef<'a>) -> Result<Self, BoxDynError> {
84 let s = String::decode(value)?;
85 SqlAddress::from_str(&s).map_err(|_| DecodeError::AddressDecodeError(s).into())
86 }
87}
88
89impl<const BITS: usize, const LIMBS: usize, DB: Database> Type<DB> for SqlUint<BITS, LIMBS>
91where
92 String: Type<DB>,
93{
94 fn type_info() -> DB::TypeInfo {
95 <String as Type<DB>>::type_info()
96 }
97
98 fn compatible(ty: &DB::TypeInfo) -> bool {
99 <String as Type<DB>>::compatible(ty)
100 }
101}
102
103impl<'a, const BITS: usize, const LIMBS: usize, DB: Database> Encode<'a, DB>
104 for SqlUint<BITS, LIMBS>
105where
106 String: Encode<'a, DB>,
107{
108 fn encode_by_ref(
109 &self,
110 buf: &mut <DB as Database>::ArgumentBuffer<'a>,
111 ) -> Result<IsNull, BoxDynError> {
112 self.to_string().to_lowercase().encode_by_ref(buf)
113 }
114}
115
116impl<'a, const BITS: usize, const LIMBS: usize, DB: Database> Decode<'a, DB>
117 for SqlUint<BITS, LIMBS>
118where
119 String: Decode<'a, DB>,
120{
121 fn decode(value: <DB as Database>::ValueRef<'a>) -> Result<Self, BoxDynError> {
122 let s = String::decode(value)?;
123 SqlUint::<BITS, LIMBS>::from_str(&s)
124 .map_err(|_| DecodeError::UintDecodeError(s.to_string()).into())
125 }
126}
127
128impl<DB: Database> Type<DB> for SqlFixedBytes<32>
130where
131 String: Type<DB>,
132{
133 fn type_info() -> DB::TypeInfo {
134 <String as Type<DB>>::type_info()
135 }
136
137 fn compatible(ty: &DB::TypeInfo) -> bool {
138 <String as Type<DB>>::compatible(ty)
139 }
140}
141impl<'a, DB: Database> Encode<'a, DB> for SqlFixedBytes<32>
142where
143 String: Encode<'a, DB>,
144{
145 fn encode_by_ref(
146 &self,
147 buf: &mut <DB as Database>::ArgumentBuffer<'a>,
148 ) -> Result<IsNull, BoxDynError> {
149 self.to_string().to_lowercase().encode_by_ref(buf)
150 }
151}
152impl<'a, DB: Database> Decode<'a, DB> for SqlFixedBytes<32>
153where
154 String: Decode<'a, DB>,
155{
156 fn decode(value: <DB as Database>::ValueRef<'a>) -> Result<Self, BoxDynError> {
157 let s = String::decode(value)?;
158 SqlFixedBytes::<32>::from_str(&s).map_err(|_| DecodeError::FixedBytesDecodeError(s).into())
159 }
160}
161
162impl<DB: Database> Type<DB> for SqlBytes
164where
165 String: Type<DB>,
166{
167 fn type_info() -> DB::TypeInfo {
168 <String as Type<DB>>::type_info()
169 }
170
171 fn compatible(ty: &DB::TypeInfo) -> bool {
172 <String as Type<DB>>::compatible(ty)
173 }
174}
175
176impl<'a, DB: Database> Encode<'a, DB> for SqlBytes
177where
178 String: Encode<'a, DB>,
179{
180 fn encode_by_ref(
181 &self,
182 buf: &mut <DB as Database>::ArgumentBuffer<'a>,
183 ) -> Result<IsNull, BoxDynError> {
184 self.to_string().to_lowercase().encode_by_ref(buf)
185 }
186}
187
188impl<'a, DB: Database> Decode<'a, DB> for SqlBytes
189where
190 String: Decode<'a, DB>,
191{
192 fn decode(value: <DB as Database>::ValueRef<'a>) -> Result<Self, BoxDynError> {
193 let s = String::decode(value)?;
194 SqlBytes::from_str(&s).map_err(|e| DecodeError::BytesDecodeError(e.to_string()).into())
195 }
196}