sqlx_core_oldapi/
decode.rs

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