Skip to main content

diesel/pg/types/
primitives.rs

1use std::io::prelude::*;
2
3#[cfg(feature = "postgres_backend")]
4use crate::deserialize::FromSqlRef;
5use crate::deserialize::{self, FromSql, Queryable};
6use crate::pg::{Pg, PgValue};
7use crate::serialize::{self, IsNull, Output, ToSql};
8use crate::sql_types;
9
10#[cfg(feature = "postgres_backend")]
11impl FromSql<sql_types::Bool, Pg> for bool {
12    fn from_sql(bytes: PgValue<'_>) -> deserialize::Result<Self> {
13        let first_byte = bytes
14            .as_bytes()
15            .first()
16            .ok_or("Received an empty response from the server")?;
17        Ok(*first_byte != 0)
18    }
19}
20
21#[cfg(feature = "postgres_backend")]
22impl ToSql<sql_types::Bool, Pg> for bool {
23    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
24        out.write_all(&[*self as u8])
25            .map(|_| IsNull::No)
26            .map_err(Into::into)
27    }
28}
29
30#[cfg(feature = "postgres_backend")]
31impl FromSql<sql_types::CChar, Pg> for u8 {
32    fn from_sql(bytes: PgValue<'_>) -> deserialize::Result<Self> {
33        let first_byte = bytes
34            .as_bytes()
35            .first()
36            .ok_or("Received an empty response from the server")?;
37        Ok(*first_byte)
38    }
39}
40
41#[cfg(feature = "postgres_backend")]
42impl ToSql<sql_types::CChar, Pg> for u8 {
43    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
44        out.write_all(&[*self])
45            .map(|_| IsNull::No)
46            .map_err(Into::into)
47    }
48}
49
50/// The returned pointer is *only* valid for the lifetime to the argument of
51/// `from_sql`. This impl is intended for uses where you want to write a new
52/// impl in terms of `String`, but don't want to allocate. We have to return a
53/// raw pointer instead of a reference with a lifetime due to the structure of
54/// `FromSql`
55#[cfg(feature = "postgres_backend")]
56impl FromSql<sql_types::Text, Pg> for *const str {
57    fn from_sql(value: PgValue<'_>) -> deserialize::Result<Self> {
58        use core::str;
59        let string = str::from_utf8(value.as_bytes())?;
60        Ok(string as *const _)
61    }
62}
63
64#[cfg(feature = "postgres_backend")]
65impl<'a> FromSqlRef<'a, sql_types::Text, Pg> for &'a str {
66    fn from_sql(value: &'a mut PgValue<'_>) -> deserialize::Result<Self> {
67        Ok(core::str::from_utf8(value.as_bytes())?)
68    }
69}
70
71#[cfg(feature = "postgres_backend")]
72impl Queryable<sql_types::VarChar, Pg> for *const str {
73    type Row = Self;
74
75    fn build(row: Self::Row) -> deserialize::Result<Self> {
76        Ok(row)
77    }
78}
79
80#[cfg(feature = "postgres_backend")]
81impl ToSql<sql_types::Citext, Pg> for String {
82    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
83        out.write_all(self.as_bytes())?;
84        Ok(IsNull::No)
85    }
86}
87
88#[cfg(feature = "postgres_backend")]
89impl ToSql<sql_types::Citext, Pg> for str {
90    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
91        out.write_all(self.as_bytes())?;
92        Ok(IsNull::No)
93    }
94}
95
96#[cfg(feature = "postgres_backend")]
97impl FromSql<sql_types::Citext, Pg> for String {
98    fn from_sql(value: PgValue<'_>) -> deserialize::Result<Self> {
99        let string = String::from_utf8(value.as_bytes().to_vec())?;
100        Ok(string)
101    }
102}
103
104#[cfg(feature = "postgres_backend")]
105impl ToSql<crate::pg::sql_types::Bpchar, Pg> for str {
106    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
107        <str as ToSql<sql_types::Text, Pg>>::to_sql(self, out)
108    }
109}
110
111#[cfg(feature = "postgres_backend")]
112impl ToSql<crate::pg::sql_types::Bpchar, Pg> for String {
113    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
114        <String as ToSql<sql_types::Text, Pg>>::to_sql(self, out)
115    }
116}
117
118#[cfg(feature = "postgres_backend")]
119impl<'a> FromSqlRef<'a, crate::pg::sql_types::Bpchar, Pg> for &'a str {
120    fn from_sql(value: &'a mut PgValue<'_>) -> deserialize::Result<Self> {
121        Ok(core::str::from_utf8(value.as_bytes())?)
122    }
123}
124
125/// The returned pointer is *only* valid for the lifetime to the argument of
126/// `from_sql`. This impl is intended for uses where you want to write a new
127/// impl in terms of `Vec<u8>`, but don't want to allocate. We have to return a
128/// raw pointer instead of a reference with a lifetime due to the structure of
129/// `FromSql`
130#[cfg(feature = "postgres_backend")]
131impl FromSql<sql_types::Binary, Pg> for *const [u8] {
132    fn from_sql(value: PgValue<'_>) -> deserialize::Result<Self> {
133        Ok(value.as_bytes() as *const _)
134    }
135}
136
137impl<'a> FromSqlRef<'a, sql_types::Binary, Pg> for &'a [u8] {
138    fn from_sql(bytes: &'a mut PgValue<'_>) -> deserialize::Result<Self> {
139        Ok(bytes.as_bytes())
140    }
141}
142
143#[cfg(feature = "postgres_backend")]
144impl Queryable<sql_types::Binary, Pg> for *const [u8] {
145    type Row = Self;
146
147    fn build(row: Self::Row) -> deserialize::Result<Self> {
148        Ok(row)
149    }
150}
151
152#[cfg(test)]
153mod tests {
154    use super::*;
155
156    #[diesel_test_helper::test]
157    fn cchar_to_sql() {
158        use crate::query_builder::bind_collector::ByteWrapper;
159
160        let mut buffer = Vec::new();
161        let mut bytes = Output::test(ByteWrapper(&mut buffer));
162        ToSql::<sql_types::CChar, Pg>::to_sql(&b'A', &mut bytes).unwrap();
163        ToSql::<sql_types::CChar, Pg>::to_sql(&b'\xc4', &mut bytes).unwrap();
164        assert_eq!(buffer, vec![65u8, 196u8]);
165    }
166
167    #[diesel_test_helper::test]
168    fn cchar_from_sql() {
169        let result = <u8 as FromSql<sql_types::CChar, Pg>>::from_nullable_sql(None);
170        assert_eq!(
171            result.unwrap_err().to_string(),
172            "Unexpected null for non-null column"
173        );
174    }
175
176    #[diesel_test_helper::test]
177    fn bool_to_sql() {
178        use crate::query_builder::bind_collector::ByteWrapper;
179
180        let mut buffer = Vec::new();
181        let mut bytes = Output::test(ByteWrapper(&mut buffer));
182        ToSql::<sql_types::Bool, Pg>::to_sql(&true, &mut bytes).unwrap();
183        ToSql::<sql_types::Bool, Pg>::to_sql(&false, &mut bytes).unwrap();
184        assert_eq!(buffer, vec![1u8, 0u8]);
185    }
186
187    #[diesel_test_helper::test]
188    fn no_bool_from_sql() {
189        let result = <bool as FromSql<sql_types::Bool, Pg>>::from_nullable_sql(None);
190        assert_eq!(
191            result.unwrap_err().to_string(),
192            "Unexpected null for non-null column"
193        );
194    }
195}