cdbc/
value.rs

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