1#[doc(inline)]
91pub use super::wit::pg3::Connection;
92
93pub use super::wit::pg3::RowSet;
124
125#[doc(inline)]
126pub use super::wit::pg3::{Error as PgError, *};
127
128use chrono::{Datelike, Timelike};
129
130#[derive(Debug, thiserror::Error)]
132pub enum Error {
133 #[error("error value decoding: {0}")]
135 Decode(String),
136 #[error(transparent)]
138 PgError(#[from] PgError),
139}
140
141pub trait Decode: Sized {
143 fn decode(value: &DbValue) -> Result<Self, Error>;
145}
146
147impl<T> Decode for Option<T>
148where
149 T: Decode,
150{
151 fn decode(value: &DbValue) -> Result<Self, Error> {
152 match value {
153 DbValue::DbNull => Ok(None),
154 v => Ok(Some(T::decode(v)?)),
155 }
156 }
157}
158
159impl Decode for bool {
160 fn decode(value: &DbValue) -> Result<Self, Error> {
161 match value {
162 DbValue::Boolean(boolean) => Ok(*boolean),
163 _ => Err(Error::Decode(format_decode_err("BOOL", value))),
164 }
165 }
166}
167
168impl Decode for i16 {
169 fn decode(value: &DbValue) -> Result<Self, Error> {
170 match value {
171 DbValue::Int16(n) => Ok(*n),
172 _ => Err(Error::Decode(format_decode_err("SMALLINT", value))),
173 }
174 }
175}
176
177impl Decode for i32 {
178 fn decode(value: &DbValue) -> Result<Self, Error> {
179 match value {
180 DbValue::Int32(n) => Ok(*n),
181 _ => Err(Error::Decode(format_decode_err("INT", value))),
182 }
183 }
184}
185
186impl Decode for i64 {
187 fn decode(value: &DbValue) -> Result<Self, Error> {
188 match value {
189 DbValue::Int64(n) => Ok(*n),
190 _ => Err(Error::Decode(format_decode_err("BIGINT", value))),
191 }
192 }
193}
194
195impl Decode for f32 {
196 fn decode(value: &DbValue) -> Result<Self, Error> {
197 match value {
198 DbValue::Floating32(n) => Ok(*n),
199 _ => Err(Error::Decode(format_decode_err("REAL", value))),
200 }
201 }
202}
203
204impl Decode for f64 {
205 fn decode(value: &DbValue) -> Result<Self, Error> {
206 match value {
207 DbValue::Floating64(n) => Ok(*n),
208 _ => Err(Error::Decode(format_decode_err("DOUBLE PRECISION", value))),
209 }
210 }
211}
212
213impl Decode for Vec<u8> {
214 fn decode(value: &DbValue) -> Result<Self, Error> {
215 match value {
216 DbValue::Binary(n) => Ok(n.to_owned()),
217 _ => Err(Error::Decode(format_decode_err("BYTEA", value))),
218 }
219 }
220}
221
222impl Decode for String {
223 fn decode(value: &DbValue) -> Result<Self, Error> {
224 match value {
225 DbValue::Str(s) => Ok(s.to_owned()),
226 _ => Err(Error::Decode(format_decode_err(
227 "CHAR, VARCHAR, TEXT",
228 value,
229 ))),
230 }
231 }
232}
233
234impl Decode for chrono::NaiveDate {
235 fn decode(value: &DbValue) -> Result<Self, Error> {
236 match value {
237 DbValue::Date((year, month, day)) => {
238 let naive_date =
239 chrono::NaiveDate::from_ymd_opt(*year, (*month).into(), (*day).into())
240 .ok_or_else(|| {
241 Error::Decode(format!(
242 "invalid date y={}, m={}, d={}",
243 year, month, day
244 ))
245 })?;
246 Ok(naive_date)
247 }
248 _ => Err(Error::Decode(format_decode_err("DATE", value))),
249 }
250 }
251}
252
253impl Decode for chrono::NaiveTime {
254 fn decode(value: &DbValue) -> Result<Self, Error> {
255 match value {
256 DbValue::Time((hour, minute, second, nanosecond)) => {
257 let naive_time = chrono::NaiveTime::from_hms_nano_opt(
258 (*hour).into(),
259 (*minute).into(),
260 (*second).into(),
261 *nanosecond,
262 )
263 .ok_or_else(|| {
264 Error::Decode(format!(
265 "invalid time {}:{}:{}:{}",
266 hour, minute, second, nanosecond
267 ))
268 })?;
269 Ok(naive_time)
270 }
271 _ => Err(Error::Decode(format_decode_err("TIME", value))),
272 }
273 }
274}
275
276impl Decode for chrono::NaiveDateTime {
277 fn decode(value: &DbValue) -> Result<Self, Error> {
278 match value {
279 DbValue::Datetime((year, month, day, hour, minute, second, nanosecond)) => {
280 let naive_date =
281 chrono::NaiveDate::from_ymd_opt(*year, (*month).into(), (*day).into())
282 .ok_or_else(|| {
283 Error::Decode(format!(
284 "invalid date y={}, m={}, d={}",
285 year, month, day
286 ))
287 })?;
288 let naive_time = chrono::NaiveTime::from_hms_nano_opt(
289 (*hour).into(),
290 (*minute).into(),
291 (*second).into(),
292 *nanosecond,
293 )
294 .ok_or_else(|| {
295 Error::Decode(format!(
296 "invalid time {}:{}:{}:{}",
297 hour, minute, second, nanosecond
298 ))
299 })?;
300 let dt = chrono::NaiveDateTime::new(naive_date, naive_time);
301 Ok(dt)
302 }
303 _ => Err(Error::Decode(format_decode_err("DATETIME", value))),
304 }
305 }
306}
307
308impl Decode for chrono::Duration {
309 fn decode(value: &DbValue) -> Result<Self, Error> {
310 match value {
311 DbValue::Timestamp(n) => Ok(chrono::Duration::seconds(*n)),
312 _ => Err(Error::Decode(format_decode_err("BIGINT", value))),
313 }
314 }
315}
316
317macro_rules! impl_parameter_value_conversions {
318 ($($ty:ty => $id:ident),*) => {
319 $(
320 impl From<$ty> for ParameterValue {
321 fn from(v: $ty) -> ParameterValue {
322 ParameterValue::$id(v)
323 }
324 }
325 )*
326 };
327}
328
329impl_parameter_value_conversions! {
330 i8 => Int8,
331 i16 => Int16,
332 i32 => Int32,
333 i64 => Int64,
334 f32 => Floating32,
335 f64 => Floating64,
336 bool => Boolean,
337 String => Str,
338 Vec<u8> => Binary
339}
340
341impl From<chrono::NaiveDateTime> for ParameterValue {
342 fn from(v: chrono::NaiveDateTime) -> ParameterValue {
343 ParameterValue::Datetime((
344 v.year(),
345 v.month() as u8,
346 v.day() as u8,
347 v.hour() as u8,
348 v.minute() as u8,
349 v.second() as u8,
350 v.nanosecond(),
351 ))
352 }
353}
354
355impl From<chrono::NaiveTime> for ParameterValue {
356 fn from(v: chrono::NaiveTime) -> ParameterValue {
357 ParameterValue::Time((
358 v.hour() as u8,
359 v.minute() as u8,
360 v.second() as u8,
361 v.nanosecond(),
362 ))
363 }
364}
365
366impl From<chrono::NaiveDate> for ParameterValue {
367 fn from(v: chrono::NaiveDate) -> ParameterValue {
368 ParameterValue::Date((v.year(), v.month() as u8, v.day() as u8))
369 }
370}
371
372impl From<chrono::TimeDelta> for ParameterValue {
373 fn from(v: chrono::TimeDelta) -> ParameterValue {
374 ParameterValue::Timestamp(v.num_seconds())
375 }
376}
377
378impl<T: Into<ParameterValue>> From<Option<T>> for ParameterValue {
379 fn from(o: Option<T>) -> ParameterValue {
380 match o {
381 Some(v) => v.into(),
382 None => ParameterValue::DbNull,
383 }
384 }
385}
386
387fn format_decode_err(types: &str, value: &DbValue) -> String {
388 format!("Expected {} from the DB but got {:?}", types, value)
389}
390
391#[cfg(test)]
392mod tests {
393 use chrono::NaiveDateTime;
394
395 use super::*;
396
397 #[test]
398 fn boolean() {
399 assert!(bool::decode(&DbValue::Boolean(true)).unwrap());
400 assert!(bool::decode(&DbValue::Int32(0)).is_err());
401 assert!(Option::<bool>::decode(&DbValue::DbNull).unwrap().is_none());
402 }
403
404 #[test]
405 fn int16() {
406 assert_eq!(i16::decode(&DbValue::Int16(0)).unwrap(), 0);
407 assert!(i16::decode(&DbValue::Int32(0)).is_err());
408 assert!(Option::<i16>::decode(&DbValue::DbNull).unwrap().is_none());
409 }
410
411 #[test]
412 fn int32() {
413 assert_eq!(i32::decode(&DbValue::Int32(0)).unwrap(), 0);
414 assert!(i32::decode(&DbValue::Boolean(false)).is_err());
415 assert!(Option::<i32>::decode(&DbValue::DbNull).unwrap().is_none());
416 }
417
418 #[test]
419 fn int64() {
420 assert_eq!(i64::decode(&DbValue::Int64(0)).unwrap(), 0);
421 assert!(i64::decode(&DbValue::Boolean(false)).is_err());
422 assert!(Option::<i64>::decode(&DbValue::DbNull).unwrap().is_none());
423 }
424
425 #[test]
426 fn floating32() {
427 assert!(f32::decode(&DbValue::Floating32(0.0)).is_ok());
428 assert!(f32::decode(&DbValue::Boolean(false)).is_err());
429 assert!(Option::<f32>::decode(&DbValue::DbNull).unwrap().is_none());
430 }
431
432 #[test]
433 fn floating64() {
434 assert!(f64::decode(&DbValue::Floating64(0.0)).is_ok());
435 assert!(f64::decode(&DbValue::Boolean(false)).is_err());
436 assert!(Option::<f64>::decode(&DbValue::DbNull).unwrap().is_none());
437 }
438
439 #[test]
440 fn str() {
441 assert_eq!(
442 String::decode(&DbValue::Str(String::from("foo"))).unwrap(),
443 String::from("foo")
444 );
445
446 assert!(String::decode(&DbValue::Int32(0)).is_err());
447 assert!(Option::<String>::decode(&DbValue::DbNull)
448 .unwrap()
449 .is_none());
450 }
451
452 #[test]
453 fn binary() {
454 assert!(Vec::<u8>::decode(&DbValue::Binary(vec![0, 0])).is_ok());
455 assert!(Vec::<u8>::decode(&DbValue::Boolean(false)).is_err());
456 assert!(Option::<Vec<u8>>::decode(&DbValue::DbNull)
457 .unwrap()
458 .is_none());
459 }
460
461 #[test]
462 fn date() {
463 assert_eq!(
464 chrono::NaiveDate::decode(&DbValue::Date((1, 2, 4))).unwrap(),
465 chrono::NaiveDate::from_ymd_opt(1, 2, 4).unwrap()
466 );
467 assert_ne!(
468 chrono::NaiveDate::decode(&DbValue::Date((1, 2, 4))).unwrap(),
469 chrono::NaiveDate::from_ymd_opt(1, 2, 5).unwrap()
470 );
471 assert!(Option::<chrono::NaiveDate>::decode(&DbValue::DbNull)
472 .unwrap()
473 .is_none());
474 }
475
476 #[test]
477 fn time() {
478 assert_eq!(
479 chrono::NaiveTime::decode(&DbValue::Time((1, 2, 3, 4))).unwrap(),
480 chrono::NaiveTime::from_hms_nano_opt(1, 2, 3, 4).unwrap()
481 );
482 assert_ne!(
483 chrono::NaiveTime::decode(&DbValue::Time((1, 2, 3, 4))).unwrap(),
484 chrono::NaiveTime::from_hms_nano_opt(1, 2, 4, 5).unwrap()
485 );
486 assert!(Option::<chrono::NaiveTime>::decode(&DbValue::DbNull)
487 .unwrap()
488 .is_none());
489 }
490
491 #[test]
492 fn datetime() {
493 let date = chrono::NaiveDate::from_ymd_opt(1, 2, 3).unwrap();
494 let mut time = chrono::NaiveTime::from_hms_nano_opt(4, 5, 6, 7).unwrap();
495 assert_eq!(
496 chrono::NaiveDateTime::decode(&DbValue::Datetime((1, 2, 3, 4, 5, 6, 7))).unwrap(),
497 chrono::NaiveDateTime::new(date, time)
498 );
499
500 time = chrono::NaiveTime::from_hms_nano_opt(4, 5, 6, 8).unwrap();
501 assert_ne!(
502 NaiveDateTime::decode(&DbValue::Datetime((1, 2, 3, 4, 5, 6, 7))).unwrap(),
503 chrono::NaiveDateTime::new(date, time)
504 );
505 assert!(Option::<chrono::NaiveDateTime>::decode(&DbValue::DbNull)
506 .unwrap()
507 .is_none());
508 }
509
510 #[test]
511 fn timestamp() {
512 assert_eq!(
513 chrono::Duration::decode(&DbValue::Timestamp(1)).unwrap(),
514 chrono::Duration::seconds(1),
515 );
516 assert_ne!(
517 chrono::Duration::decode(&DbValue::Timestamp(2)).unwrap(),
518 chrono::Duration::seconds(1)
519 );
520 assert!(Option::<chrono::Duration>::decode(&DbValue::DbNull)
521 .unwrap()
522 .is_none());
523 }
524}