diesel/type_impls/
option.rs1use 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}