sqlx_core/
decode.rs

1//! Provides [`Decode`] for decoding values from the database.
2
3use std::borrow::Cow;
4use std::rc::Rc;
5use std::sync::Arc;
6
7use crate::database::Database;
8use crate::error::BoxDynError;
9
10use crate::value::ValueRef;
11
12/// A type that can be decoded from the database.
13///
14/// ## How can I implement `Decode`?
15///
16/// A manual implementation of `Decode` can be useful when adding support for
17/// types externally to SQLx.
18///
19/// The following showcases how to implement `Decode` to be generic over [`Database`]. The
20/// implementation can be marginally simpler if you remove the `DB` type parameter and explicitly
21/// use the concrete [`ValueRef`](Database::ValueRef) and [`TypeInfo`](Database::TypeInfo) types.
22///
23/// ```rust
24/// # use sqlx_core::database::{Database};
25/// # use sqlx_core::decode::Decode;
26/// # use sqlx_core::types::Type;
27/// # use std::error::Error;
28/// #
29/// struct MyType;
30///
31/// # impl<DB: Database> Type<DB> for MyType {
32/// # fn type_info() -> DB::TypeInfo { todo!() }
33/// # }
34/// #
35/// # impl std::str::FromStr for MyType {
36/// # type Err = sqlx_core::error::Error;
37/// # fn from_str(s: &str) -> Result<Self, Self::Err> { todo!() }
38/// # }
39/// #
40/// // DB is the database driver
41/// // `'r` is the lifetime of the `Row` being decoded
42/// impl<'r, DB: Database> Decode<'r, DB> for MyType
43/// where
44///     // we want to delegate some of the work to string decoding so let's make sure strings
45///     // are supported by the database
46///     &'r str: Decode<'r, DB>
47/// {
48///     fn decode(
49///         value: <DB as Database>::ValueRef<'r>,
50///     ) -> Result<MyType, Box<dyn Error + 'static + Send + Sync>> {
51///         // the interface of ValueRef is largely unstable at the moment
52///         // so this is not directly implementable
53///
54///         // however, you can delegate to a type that matches the format of the type you want
55///         // to decode (such as a UTF-8 string)
56///
57///         let value = <&str as Decode<DB>>::decode(value)?;
58///
59///         // now you can parse this into your type (assuming there is a `FromStr`)
60///
61///         Ok(value.parse()?)
62///     }
63/// }
64/// ```
65pub trait Decode<'r, DB: Database>: Sized {
66    /// Decode a new value of this type using a raw value from the database.
67    fn decode(value: <DB as Database>::ValueRef<'r>) -> Result<Self, BoxDynError>;
68}
69
70// implement `Decode` for Option<T> for all SQL types
71impl<'r, DB, T> Decode<'r, DB> for Option<T>
72where
73    DB: Database,
74    T: Decode<'r, DB>,
75{
76    fn decode(value: <DB as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {
77        if value.is_null() {
78            Ok(None)
79        } else {
80            Ok(Some(T::decode(value)?))
81        }
82    }
83}
84
85macro_rules! impl_decode_for_smartpointer {
86    ($smart_pointer:tt) => {
87        impl<'r, DB, T> Decode<'r, DB> for $smart_pointer<T>
88        where
89            DB: Database,
90            T: Decode<'r, DB>,
91        {
92            fn decode(value: <DB as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {
93                Ok(Self::new(T::decode(value)?))
94            }
95        }
96
97        impl<'r, DB> Decode<'r, DB> for $smart_pointer<str>
98        where
99            DB: Database,
100            &'r str: Decode<'r, DB>,
101        {
102            fn decode(value: <DB as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {
103                let ref_str = <&str as Decode<DB>>::decode(value)?;
104                Ok(ref_str.into())
105            }
106        }
107
108        impl<'r, DB> Decode<'r, DB> for $smart_pointer<[u8]>
109        where
110            DB: Database,
111            Vec<u8>: Decode<'r, DB>,
112        {
113            fn decode(value: <DB as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {
114                // The `Postgres` implementation requires this to be decoded as an owned value because
115                // bytes can be sent in text format.
116                let bytes = <Vec<u8> as Decode<DB>>::decode(value)?;
117                Ok(bytes.into())
118            }
119        }
120    };
121}
122
123impl_decode_for_smartpointer!(Arc);
124impl_decode_for_smartpointer!(Box);
125impl_decode_for_smartpointer!(Rc);
126
127// implement `Decode` for Cow<T> for all SQL types
128impl<'r, DB, T> Decode<'r, DB> for Cow<'_, T>
129where
130    DB: Database,
131    // `ToOwned` is required here to satisfy `Cow`
132    T: ToOwned + ?Sized,
133    <T as ToOwned>::Owned: Decode<'r, DB>,
134{
135    fn decode(value: <DB as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {
136        // See https://github.com/launchbadge/sqlx/pull/3674#discussion_r2008611502 for more info
137        // about why decoding to a `Cow::Owned` was chosen.
138        <<T as ToOwned>::Owned as Decode<DB>>::decode(value).map(Cow::Owned)
139    }
140}