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}