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}