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}