diesel/type_impls/
option.rs

1use crate::backend::Backend;
2use crate::deserialize::{self, FromSql, Queryable, QueryableByName};
3use crate::expression::bound::Bound;
4use crate::expression::*;
5use crate::query_builder::QueryId;
6use crate::serialize::{self, IsNull, Output, ToSql};
7use crate::sql_types::{is_nullable, HasSqlType, Nullable, SingleValue, SqlType};
8use crate::NullableExpressionMethods;
9
10impl<T, DB> HasSqlType<Nullable<T>> for DB
11where
12    DB: Backend + HasSqlType<T>,
13    T: SqlType,
14{
15    fn metadata(lookup: &mut DB::MetadataLookup) -> DB::TypeMetadata {
16        <DB as HasSqlType<T>>::metadata(lookup)
17    }
18}
19
20impl<T> QueryId for Nullable<T>
21where
22    T: QueryId + SqlType<IsNull = is_nullable::NotNull>,
23{
24    type QueryId = T::QueryId;
25
26    const HAS_STATIC_QUERY_ID: bool = T::HAS_STATIC_QUERY_ID;
27}
28
29impl<T, ST, DB> FromSql<Nullable<ST>, DB> for Option<T>
30where
31    T: FromSql<ST, DB>,
32    DB: Backend,
33    ST: SqlType<IsNull = is_nullable::NotNull>,
34{
35    fn from_sql(bytes: DB::RawValue<'_>) -> deserialize::Result<Self> {
36        T::from_sql(bytes).map(Some)
37    }
38
39    fn from_nullable_sql(bytes: Option<DB::RawValue<'_>>) -> deserialize::Result<Self> {
40        match bytes {
41            Some(bytes) => T::from_sql(bytes).map(Some),
42            None => Ok(None),
43        }
44    }
45}
46
47impl<T, ST, DB> ToSql<Nullable<ST>, DB> for Option<T>
48where
49    T: ToSql<ST, DB>,
50    DB: Backend,
51    ST: SqlType<IsNull = is_nullable::NotNull>,
52{
53    fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> serialize::Result {
54        if let Some(ref value) = *self {
55            value.to_sql(out)
56        } else {
57            Ok(IsNull::Yes)
58        }
59    }
60}
61
62impl<T, ST> AsExpression<Nullable<ST>> for Option<T>
63where
64    ST: SqlType<IsNull = is_nullable::NotNull>,
65    Nullable<ST>: TypedExpressionType,
66{
67    type Expression = Bound<Nullable<ST>, Self>;
68
69    fn as_expression(self) -> Self::Expression {
70        Bound::new(self)
71    }
72}
73
74impl<T, ST> AsExpression<Nullable<ST>> for &Option<T>
75where
76    ST: SqlType<IsNull = is_nullable::NotNull>,
77    Nullable<ST>: TypedExpressionType,
78{
79    type Expression = Bound<Nullable<ST>, Self>;
80
81    fn as_expression(self) -> Self::Expression {
82        Bound::new(self)
83    }
84}
85
86impl<T, DB> QueryableByName<DB> for Option<T>
87where
88    DB: Backend,
89    T: QueryableByName<DB>,
90{
91    fn build<'a>(row: &impl crate::row::NamedRow<'a, DB>) -> deserialize::Result<Self> {
92        match T::build(row) {
93            Ok(v) => Ok(Some(v)),
94            Err(e) if e.is::<crate::result::UnexpectedNullError>() => Ok(None),
95            Err(e) => Err(e),
96        }
97    }
98}
99
100impl<ST, T, DB> Queryable<ST, DB> for Option<T>
101where
102    ST: SingleValue<IsNull = is_nullable::IsNullable>,
103    DB: Backend,
104    Self: FromSql<ST, DB>,
105{
106    type Row = Self;
107
108    fn build(row: Self::Row) -> deserialize::Result<Self> {
109        Ok(row)
110    }
111}
112
113impl<T, DB> Selectable<DB> for Option<T>
114where
115    DB: Backend,
116    T: Selectable<DB>,
117    crate::dsl::Nullable<T::SelectExpression>: Expression,
118{
119    type SelectExpression = crate::dsl::Nullable<T::SelectExpression>;
120
121    fn construct_selection() -> Self::SelectExpression {
122        T::construct_selection().nullable()
123    }
124}
125
126#[cfg(test)]
127#[diesel_test_helper::test]
128#[cfg(feature = "postgres")]
129fn option_to_sql() {
130    use crate::pg::Pg;
131    use crate::query_builder::bind_collector::ByteWrapper;
132    use crate::sql_types;
133
134    type Type = sql_types::Nullable<sql_types::VarChar>;
135
136    let mut buffer = Vec::new();
137    let is_null = {
138        let mut bytes = Output::test(ByteWrapper(&mut buffer));
139        ToSql::<Type, Pg>::to_sql(&None::<String>, &mut bytes).unwrap()
140    };
141    assert_eq!(IsNull::Yes, is_null);
142    assert!(buffer.is_empty());
143
144    let is_null = {
145        let mut bytes = Output::test(ByteWrapper(&mut buffer));
146        ToSql::<Type, Pg>::to_sql(&Some(""), &mut bytes).unwrap()
147    };
148    assert_eq!(IsNull::No, is_null);
149    assert!(buffer.is_empty());
150
151    let is_null = {
152        let mut bytes = Output::test(ByteWrapper(&mut buffer));
153        ToSql::<Type, Pg>::to_sql(&Some("Sean"), &mut bytes).unwrap()
154    };
155    let expected_bytes = b"Sean".to_vec();
156    assert_eq!(IsNull::No, is_null);
157    assert_eq!(buffer, expected_bytes);
158}