diesel/type_impls/
option.rsuse std::io::Write;
use backend::Backend;
use deserialize::{self, FromSql, FromSqlRow, Queryable, QueryableByName};
use expression::bound::Bound;
use expression::*;
use query_builder::QueryId;
use result::UnexpectedNullError;
use row::NamedRow;
use serialize::{self, IsNull, Output, ToSql};
use sql_types::{HasSqlType, NotNull, Nullable};
#[cfg(feature = "mysql")]
use sql_types::IsSigned;
impl<T, DB> HasSqlType<Nullable<T>> for DB
where
DB: Backend + HasSqlType<T>,
T: NotNull,
{
fn metadata(lookup: &DB::MetadataLookup) -> DB::TypeMetadata {
<DB as HasSqlType<T>>::metadata(lookup)
}
#[cfg(feature = "with-deprecated")]
#[allow(deprecated)]
fn row_metadata(out: &mut Vec<DB::TypeMetadata>, lookup: &DB::MetadataLookup) {
<DB as HasSqlType<T>>::row_metadata(out, lookup)
}
#[cfg(feature = "mysql")]
fn mysql_row_metadata(
out: &mut Vec<(DB::TypeMetadata, IsSigned)>,
lookup: &DB::MetadataLookup,
) {
<DB as HasSqlType<T>>::mysql_row_metadata(out, lookup)
}
}
impl<T> QueryId for Nullable<T>
where
T: QueryId + NotNull,
{
type QueryId = T::QueryId;
const HAS_STATIC_QUERY_ID: bool = T::HAS_STATIC_QUERY_ID;
}
impl<T, ST, DB> FromSql<Nullable<ST>, DB> for Option<T>
where
T: FromSql<ST, DB>,
DB: Backend,
ST: NotNull,
{
fn from_sql(bytes: Option<&DB::RawValue>) -> deserialize::Result<Self> {
match bytes {
Some(_) => T::from_sql(bytes).map(Some),
None => Ok(None),
}
}
}
impl<T, ST, DB> Queryable<Nullable<ST>, DB> for Option<T>
where
T: Queryable<ST, DB>,
DB: Backend,
Option<T::Row>: FromSqlRow<Nullable<ST>, DB>,
ST: NotNull,
{
type Row = Option<T::Row>;
fn build(row: Self::Row) -> Self {
row.map(T::build)
}
}
impl<T, DB> QueryableByName<DB> for Option<T>
where
T: QueryableByName<DB>,
DB: Backend,
{
fn build<R: NamedRow<DB>>(row: &R) -> deserialize::Result<Self> {
match T::build(row) {
Ok(v) => Ok(Some(v)),
Err(e) => {
if e.is::<UnexpectedNullError>() {
Ok(None)
} else {
Err(e)
}
}
}
}
}
impl<T, ST, DB> FromSqlRow<Nullable<ST>, DB> for Option<T>
where
T: FromSqlRow<ST, DB>,
DB: Backend,
ST: NotNull,
{
const FIELDS_NEEDED: usize = T::FIELDS_NEEDED;
fn build_from_row<R: ::row::Row<DB>>(row: &mut R) -> deserialize::Result<Self> {
let fields_needed = Self::FIELDS_NEEDED;
if row.next_is_null(fields_needed) {
row.advance(fields_needed);
Ok(None)
} else {
T::build_from_row(row).map(Some)
}
}
}
impl<T, ST, DB> ToSql<Nullable<ST>, DB> for Option<T>
where
T: ToSql<ST, DB>,
DB: Backend,
ST: NotNull,
{
fn to_sql<W: Write>(&self, out: &mut Output<W, DB>) -> serialize::Result {
if let Some(ref value) = *self {
value.to_sql(out)
} else {
Ok(IsNull::Yes)
}
}
}
impl<T, ST> AsExpression<Nullable<ST>> for Option<T>
where
ST: NotNull,
{
type Expression = Bound<Nullable<ST>, Self>;
fn as_expression(self) -> Self::Expression {
Bound::new(self)
}
}
impl<'a, T, ST> AsExpression<Nullable<ST>> for &'a Option<T>
where
ST: NotNull,
{
type Expression = Bound<Nullable<ST>, Self>;
fn as_expression(self) -> Self::Expression {
Bound::new(self)
}
}
#[cfg(all(test, feature = "postgres"))]
use pg::Pg;
#[cfg(all(test, feature = "postgres"))]
use sql_types;
#[test]
#[cfg(feature = "postgres")]
fn option_to_sql() {
type Type = sql_types::Nullable<sql_types::VarChar>;
let mut bytes = Output::test();
let is_null = ToSql::<Type, Pg>::to_sql(&None::<String>, &mut bytes).unwrap();
assert_eq!(IsNull::Yes, is_null);
assert!(bytes.is_empty());
let is_null = ToSql::<Type, Pg>::to_sql(&Some(""), &mut bytes).unwrap();
assert_eq!(IsNull::No, is_null);
assert!(bytes.is_empty());
let is_null = ToSql::<Type, Pg>::to_sql(&Some("Sean"), &mut bytes).unwrap();
let expectd_bytes = b"Sean".to_vec();
assert_eq!(IsNull::No, is_null);
assert_eq!(bytes, expectd_bytes);
}