sqlx_core/
value.rs

1use crate::database::Database;
2use crate::decode::Decode;
3use crate::error::{mismatched_types, Error};
4use crate::type_info::TypeInfo;
5use crate::types::Type;
6use std::borrow::Cow;
7
8/// An owned value from the database.
9pub trait Value {
10    type Database: Database<Value = Self>;
11
12    /// Get this value as a reference.
13    fn as_ref(&self) -> <Self::Database as Database>::ValueRef<'_>;
14
15    /// Get the type information for this value.
16    fn type_info(&self) -> Cow<'_, <Self::Database as Database>::TypeInfo>;
17
18    /// Returns `true` if the SQL value is `NULL`.
19    fn is_null(&self) -> bool;
20
21    /// Decode this single value into the requested type.
22    ///
23    /// # Panics
24    ///
25    /// Panics if the value cannot be decoded into the requested type.
26    /// See [`try_decode`](Self::try_decode) for a non-panicking version.
27    ///
28    #[inline]
29    fn decode<'r, T>(&'r self) -> T
30    where
31        T: Decode<'r, Self::Database> + Type<Self::Database>,
32    {
33        self.try_decode::<T>().unwrap()
34    }
35
36    /// Decode this single value into the requested type.
37    ///
38    /// Unlike [`decode`](Self::decode), this method does not check that the type of this
39    /// value is compatible with the Rust type and blindly tries to decode the value.
40    ///
41    /// # Panics
42    ///
43    /// Panics if the value cannot be decoded into the requested type.
44    /// See [`try_decode_unchecked`](Self::try_decode_unchecked) for a non-panicking version.
45    ///
46    #[inline]
47    fn decode_unchecked<'r, T>(&'r self) -> T
48    where
49        T: Decode<'r, Self::Database>,
50    {
51        self.try_decode_unchecked::<T>().unwrap()
52    }
53
54    /// Decode this single value into the requested type.
55    ///
56    /// # Errors
57    ///
58    ///  * [`Decode`] if the value could not be decoded into the requested type.
59    ///
60    /// [`Decode`]: Error::Decode
61    ///
62    #[inline]
63    fn try_decode<'r, T>(&'r self) -> Result<T, Error>
64    where
65        T: Decode<'r, Self::Database> + Type<Self::Database>,
66    {
67        if !self.is_null() {
68            let ty = self.type_info();
69
70            if !ty.is_null() && !T::compatible(&ty) {
71                return Err(Error::Decode(mismatched_types::<Self::Database, T>(&ty)));
72            }
73        }
74
75        self.try_decode_unchecked()
76    }
77
78    /// Decode this single value into the requested type.
79    ///
80    /// Unlike [`try_decode`](Self::try_decode), this method does not check that the type of this
81    /// value is compatible with the Rust type and blindly tries to decode the value.
82    ///
83    /// # Errors
84    ///
85    ///  * [`Decode`] if the value could not be decoded into the requested type.
86    ///
87    /// [`Decode`]: Error::Decode
88    ///
89    #[inline]
90    fn try_decode_unchecked<'r, T>(&'r self) -> Result<T, Error>
91    where
92        T: Decode<'r, Self::Database>,
93    {
94        T::decode(self.as_ref()).map_err(Error::Decode)
95    }
96}
97
98/// A reference to a single value from the database.
99pub trait ValueRef<'r>: Sized {
100    type Database: Database;
101
102    /// Creates an owned value from this value reference.
103    ///
104    /// This is just a reference increment in PostgreSQL and MySQL and thus is `O(1)`. In SQLite,
105    /// this is a copy.
106    fn to_owned(&self) -> <Self::Database as Database>::Value;
107
108    /// Get the type information for this value.
109    fn type_info(&self) -> Cow<'_, <Self::Database as Database>::TypeInfo>;
110
111    /// Returns `true` if the SQL value is `NULL`.
112    fn is_null(&self) -> bool;
113}