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