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