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}