sqlx_core/
decode.rs

1//! Provides [`Decode`] for decoding values from the database.
2
3use crate::database::Database;
4use crate::error::BoxDynError;
5
6use crate::value::ValueRef;
7
8/// A type that can be decoded from the database.
9///
10/// ## How can I implement `Decode`?
11///
12/// A manual implementation of `Decode` can be useful when adding support for
13/// types externally to SQLx.
14///
15/// The following showcases how to implement `Decode` to be generic over [`Database`]. The
16/// implementation can be marginally simpler if you remove the `DB` type parameter and explicitly
17/// use the concrete [`ValueRef`](Database::ValueRef) and [`TypeInfo`](Database::TypeInfo) types.
18///
19/// ```rust
20/// # use sqlx_core::database::{Database};
21/// # use sqlx_core::decode::Decode;
22/// # use sqlx_core::types::Type;
23/// # use std::error::Error;
24/// #
25/// struct MyType;
26///
27/// # impl<DB: Database> Type<DB> for MyType {
28/// # fn type_info() -> DB::TypeInfo { todo!() }
29/// # }
30/// #
31/// # impl std::str::FromStr for MyType {
32/// # type Err = sqlx_core::error::Error;
33/// # fn from_str(s: &str) -> Result<Self, Self::Err> { todo!() }
34/// # }
35/// #
36/// // DB is the database driver
37/// // `'r` is the lifetime of the `Row` being decoded
38/// impl<'r, DB: Database> Decode<'r, DB> for MyType
39/// where
40///     // we want to delegate some of the work to string decoding so let's make sure strings
41///     // are supported by the database
42///     &'r str: Decode<'r, DB>
43/// {
44///     fn decode(
45///         value: <DB as Database>::ValueRef<'r>,
46///     ) -> Result<MyType, Box<dyn Error + 'static + Send + Sync>> {
47///         // the interface of ValueRef is largely unstable at the moment
48///         // so this is not directly implementable
49///
50///         // however, you can delegate to a type that matches the format of the type you want
51///         // to decode (such as a UTF-8 string)
52///
53///         let value = <&str as Decode<DB>>::decode(value)?;
54///
55///         // now you can parse this into your type (assuming there is a `FromStr`)
56///
57///         Ok(value.parse()?)
58///     }
59/// }
60/// ```
61pub trait Decode<'r, DB: Database>: Sized {
62    /// Decode a new value of this type using a raw value from the database.
63    fn decode(value: <DB as Database>::ValueRef<'r>) -> Result<Self, BoxDynError>;
64}
65
66// implement `Decode` for Option<T> for all SQL types
67impl<'r, DB, T> Decode<'r, DB> for Option<T>
68where
69    DB: Database,
70    T: Decode<'r, DB>,
71{
72    fn decode(value: <DB as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {
73        if value.is_null() {
74            Ok(None)
75        } else {
76            Ok(Some(T::decode(value)?))
77        }
78    }
79}