1#[doc(inline)]
20pub use super::wit::v2::postgres::{Connection, Error as PgError};
21#[doc(inline)]
22pub use super::wit::v2::rdbms_types::*;
23
24#[derive(Debug, thiserror::Error)]
26pub enum Error {
27 #[error("error value decoding: {0}")]
29 Decode(String),
30 #[error(transparent)]
32 PgError(#[from] PgError),
33}
34
35pub trait Decode: Sized {
37 fn decode(value: &DbValue) -> Result<Self, Error>;
39}
40
41impl<T> Decode for Option<T>
42where
43 T: Decode,
44{
45 fn decode(value: &DbValue) -> Result<Self, Error> {
46 match value {
47 DbValue::DbNull => Ok(None),
48 v => Ok(Some(T::decode(v)?)),
49 }
50 }
51}
52
53impl Decode for bool {
54 fn decode(value: &DbValue) -> Result<Self, Error> {
55 match value {
56 DbValue::Boolean(boolean) => Ok(*boolean),
57 _ => Err(Error::Decode(format_decode_err("BOOL", value))),
58 }
59 }
60}
61
62impl Decode for i16 {
63 fn decode(value: &DbValue) -> Result<Self, Error> {
64 match value {
65 DbValue::Int16(n) => Ok(*n),
66 _ => Err(Error::Decode(format_decode_err("SMALLINT", value))),
67 }
68 }
69}
70
71impl Decode for i32 {
72 fn decode(value: &DbValue) -> Result<Self, Error> {
73 match value {
74 DbValue::Int32(n) => Ok(*n),
75 _ => Err(Error::Decode(format_decode_err("INT", value))),
76 }
77 }
78}
79
80impl Decode for i64 {
81 fn decode(value: &DbValue) -> Result<Self, Error> {
82 match value {
83 DbValue::Int64(n) => Ok(*n),
84 _ => Err(Error::Decode(format_decode_err("BIGINT", value))),
85 }
86 }
87}
88
89impl Decode for f32 {
90 fn decode(value: &DbValue) -> Result<Self, Error> {
91 match value {
92 DbValue::Floating32(n) => Ok(*n),
93 _ => Err(Error::Decode(format_decode_err("REAL", value))),
94 }
95 }
96}
97
98impl Decode for f64 {
99 fn decode(value: &DbValue) -> Result<Self, Error> {
100 match value {
101 DbValue::Floating64(n) => Ok(*n),
102 _ => Err(Error::Decode(format_decode_err("DOUBLE PRECISION", value))),
103 }
104 }
105}
106
107impl Decode for Vec<u8> {
108 fn decode(value: &DbValue) -> Result<Self, Error> {
109 match value {
110 DbValue::Binary(n) => Ok(n.to_owned()),
111 _ => Err(Error::Decode(format_decode_err("BYTEA", value))),
112 }
113 }
114}
115
116impl Decode for String {
117 fn decode(value: &DbValue) -> Result<Self, Error> {
118 match value {
119 DbValue::Str(s) => Ok(s.to_owned()),
120 _ => Err(Error::Decode(format_decode_err(
121 "CHAR, VARCHAR, TEXT",
122 value,
123 ))),
124 }
125 }
126}
127
128fn format_decode_err(types: &str, value: &DbValue) -> String {
129 format!("Expected {} from the DB but got {:?}", types, value)
130}
131
132#[cfg(test)]
133mod tests {
134 use super::*;
135
136 #[test]
137 fn boolean() {
138 assert!(bool::decode(&DbValue::Boolean(true)).unwrap());
139 assert!(bool::decode(&DbValue::Int32(0)).is_err());
140 assert!(Option::<bool>::decode(&DbValue::DbNull).unwrap().is_none());
141 }
142
143 #[test]
144 fn int16() {
145 assert_eq!(i16::decode(&DbValue::Int16(0)).unwrap(), 0);
146 assert!(i16::decode(&DbValue::Int32(0)).is_err());
147 assert!(Option::<i16>::decode(&DbValue::DbNull).unwrap().is_none());
148 }
149
150 #[test]
151 fn int32() {
152 assert_eq!(i32::decode(&DbValue::Int32(0)).unwrap(), 0);
153 assert!(i32::decode(&DbValue::Boolean(false)).is_err());
154 assert!(Option::<i32>::decode(&DbValue::DbNull).unwrap().is_none());
155 }
156
157 #[test]
158 fn int64() {
159 assert_eq!(i64::decode(&DbValue::Int64(0)).unwrap(), 0);
160 assert!(i64::decode(&DbValue::Boolean(false)).is_err());
161 assert!(Option::<i64>::decode(&DbValue::DbNull).unwrap().is_none());
162 }
163
164 #[test]
165 fn floating32() {
166 assert!(f32::decode(&DbValue::Floating32(0.0)).is_ok());
167 assert!(f32::decode(&DbValue::Boolean(false)).is_err());
168 assert!(Option::<f32>::decode(&DbValue::DbNull).unwrap().is_none());
169 }
170
171 #[test]
172 fn floating64() {
173 assert!(f64::decode(&DbValue::Floating64(0.0)).is_ok());
174 assert!(f64::decode(&DbValue::Boolean(false)).is_err());
175 assert!(Option::<f64>::decode(&DbValue::DbNull).unwrap().is_none());
176 }
177
178 #[test]
179 fn str() {
180 assert_eq!(
181 String::decode(&DbValue::Str(String::from("foo"))).unwrap(),
182 String::from("foo")
183 );
184
185 assert!(String::decode(&DbValue::Int32(0)).is_err());
186 assert!(Option::<String>::decode(&DbValue::DbNull)
187 .unwrap()
188 .is_none());
189 }
190
191 #[test]
192 fn binary() {
193 assert!(Vec::<u8>::decode(&DbValue::Binary(vec![0, 0])).is_ok());
194 assert!(Vec::<u8>::decode(&DbValue::Boolean(false)).is_err());
195 assert!(Option::<Vec<u8>>::decode(&DbValue::DbNull)
196 .unwrap()
197 .is_none());
198 }
199}