diesel/
deserialize.rs

1//! Types and traits related to deserializing values from the database
2
3use std::error::Error;
4use std::result;
5
6use crate::backend::Backend;
7use crate::expression::select_by::SelectBy;
8use crate::row::{NamedRow, Row};
9use crate::sql_types::{SingleValue, SqlType, Untyped};
10use crate::Selectable;
11
12/// A specialized result type representing the result of deserializing
13/// a value from the database.
14pub type Result<T> = result::Result<T, Box<dyn Error + Send + Sync>>;
15
16/// Trait indicating that a record can be queried from the database.
17///
18/// Types which implement `Queryable` represent the result of a SQL query. This
19/// does not necessarily mean they represent a single database table.
20///
21/// Diesel represents the return type of a query as a tuple. The purpose of this
22/// trait is to convert from a tuple of Rust values that have been deserialized
23/// into your struct.
24///
25/// This trait can be [derived](derive@Queryable)
26///
27/// ## How to resolve compiler errors while loading data from the database
28///
29/// In case you getting uncomprehensable compiler errors while loading data
30/// from the database you might want to consider using
31/// [`#[derive(Selectable)]`](derive@crate::prelude::Selectable) +
32/// `#[diesel(check_for_backend(YourBackendType))]` to check for mismatching fields at compile
33/// time. This drastically improves the quality of the generated error messages by pointing
34/// to concrete mismatches at field level. You need to specify the concrete database backend
35/// this specific struct is indented to be used with, as otherwise rustc cannot correctly
36/// identify the required deserialization implementation.
37///
38/// ## Interaction with `NULL`/`Option`
39/// [`Nullable`][crate::sql_types::Nullable] types can be queried into `Option`.
40/// This is valid for single fields, tuples, and structures with `Queryable`.
41///
42/// With tuples and structs, the process for deserializing an `Option<(A,B,C)>` is
43/// to attempt to deserialize `A`, `B` and `C`, and if either of these return an
44/// [`UnexpectedNullError`](crate::result::UnexpectedNullError), the `Option` will be
45/// deserialized as `None`.
46/// If all succeed, the `Option` will be deserialized as `Some((a,b,c))`.
47///
48/// # Examples
49///
50/// ## Simple mapping from query to struct
51///
52/// If we just want to map a query to our struct, we can use `derive`.
53///
54/// ```rust
55/// # include!("doctest_setup.rs");
56/// #
57/// #[derive(Queryable, PartialEq, Debug)]
58/// struct User {
59///     id: i32,
60///     name: String,
61/// }
62///
63/// # fn main() {
64/// #     run_test();
65/// # }
66/// #
67/// # fn run_test() -> QueryResult<()> {
68/// #     use schema::users::dsl::*;
69/// #     let connection = &mut establish_connection();
70/// let first_user = users.order_by(id).first(connection)?;
71/// let expected = User { id: 1, name: "Sean".into() };
72/// assert_eq!(expected, first_user);
73/// #     Ok(())
74/// # }
75/// ```
76///
77/// ## Interaction with `NULL`/`Option`
78///
79/// ### Single field
80/// ```rust
81/// # include!("doctest_setup.rs");
82/// # use diesel::sql_types::*;
83/// #
84/// table! {
85///     animals {
86///         id -> Integer,
87///         species -> VarChar,
88///         legs -> Integer,
89///         name -> Nullable<VarChar>,
90///     }
91/// }
92/// #
93/// #[derive(Queryable, PartialEq, Debug)]
94/// struct Animal {
95///     id: i32,
96///     name: Option<String>,
97/// }
98///
99/// # fn main() {
100/// #     run_test();
101/// # }
102/// #
103/// # fn run_test() -> QueryResult<()> {
104/// #     use schema::animals::dsl::*;
105/// #     let connection = &mut establish_connection();
106/// let all_animals = animals.select((id, name)).order_by(id).load(connection)?;
107/// let expected = vec![Animal { id: 1, name: Some("Jack".to_owned()) }, Animal { id: 2, name: None }];
108/// assert_eq!(expected, all_animals);
109/// #     Ok(())
110/// # }
111/// ```
112///
113/// ### Multiple fields
114/// ```rust
115/// # include!("doctest_setup.rs");
116/// #
117/// #[derive(Queryable, PartialEq, Debug)]
118/// struct UserWithPost {
119///     id: i32,
120///     post: Option<Post>,
121/// }
122/// #[derive(Queryable, PartialEq, Debug)]
123/// struct Post {
124///     id: i32,
125///     title: String,
126/// }
127///
128/// # fn main() {
129/// #     run_test();
130/// # }
131/// #
132/// # fn run_test() -> QueryResult<()> {
133/// #     use schema::{posts, users};
134/// #     let connection = &mut establish_connection();
135/// #     diesel::insert_into(users::table)
136/// #         .values(users::name.eq("Ruby"))
137/// #         .execute(connection)?;
138/// let all_posts = users::table
139///     .left_join(posts::table)
140///     .select((
141///         users::id,
142///         (posts::id, posts::title).nullable()
143///     ))
144///     .order_by((users::id, posts::id))
145///     .load(connection)?;
146/// let expected = vec![
147///     UserWithPost { id: 1, post: Some(Post { id: 1, title: "My first post".to_owned() }) },
148///     UserWithPost { id: 1, post: Some(Post { id: 2, title: "About Rust".to_owned() }) },
149///     UserWithPost { id: 2, post: Some(Post { id: 3, title: "My first post too".to_owned() }) },
150///     UserWithPost { id: 3, post: None },
151/// ];
152/// assert_eq!(expected, all_posts);
153/// #     Ok(())
154/// # }
155/// ```
156///
157/// ## `deserialize_as` attribute
158///
159/// If we want to do additional work during deserialization, we can use
160/// `deserialize_as` to use a different implementation.
161///
162/// ```rust
163/// # include!("doctest_setup.rs");
164/// #
165/// # use schema::users;
166/// # use diesel::backend::{self, Backend};
167/// # use diesel::deserialize::{self, Queryable, FromSql};
168/// # use diesel::sql_types::Text;
169/// #
170/// struct LowercaseString(String);
171///
172/// impl Into<String> for LowercaseString {
173///     fn into(self) -> String {
174///         self.0
175///     }
176/// }
177///
178/// impl<DB> Queryable<Text, DB> for LowercaseString
179/// where
180///     DB: Backend,
181///     String: FromSql<Text, DB>,
182/// {
183///     type Row = String;
184///
185///     fn build(s: String) -> deserialize::Result<Self> {
186///         Ok(LowercaseString(s.to_lowercase()))
187///     }
188/// }
189///
190/// #[derive(Queryable, PartialEq, Debug)]
191/// struct User {
192///     id: i32,
193///     #[diesel(deserialize_as = LowercaseString)]
194///     name: String,
195/// }
196///
197/// # fn main() {
198/// #     run_test();
199/// # }
200/// #
201/// # fn run_test() -> QueryResult<()> {
202/// #     use schema::users::dsl::*;
203/// #     let connection = &mut establish_connection();
204/// let first_user = users.first(connection)?;
205/// let expected = User { id: 1, name: "sean".into() };
206/// assert_eq!(expected, first_user);
207/// #     Ok(())
208/// # }
209/// ```
210///
211/// ## Manual implementation
212///
213/// Alternatively, we can implement the trait for our struct manually.
214///
215/// ```rust
216/// # include!("doctest_setup.rs");
217/// #
218/// use schema::users;
219/// use diesel::deserialize::{self, Queryable};
220///
221/// # /*
222/// type DB = diesel::sqlite::Sqlite;
223/// # */
224///
225/// #[derive(PartialEq, Debug)]
226/// struct User {
227///     id: i32,
228///     name: String,
229/// }
230///
231/// impl Queryable<users::SqlType, DB> for User {
232///     type Row = (i32, String);
233///
234///     fn build(row: Self::Row) -> deserialize::Result<Self> {
235///         Ok(User {
236///             id: row.0,
237///             name: row.1.to_lowercase(),
238///         })
239///     }
240/// }
241///
242/// # fn main() {
243/// #     run_test();
244/// # }
245/// #
246/// # fn run_test() -> QueryResult<()> {
247/// #     use schema::users::dsl::*;
248/// #     let connection = &mut establish_connection();
249/// let first_user = users.first(connection)?;
250/// let expected = User { id: 1, name: "sean".into() };
251/// assert_eq!(expected, first_user);
252/// #     Ok(())
253/// # }
254/// ```
255pub trait Queryable<ST, DB>: Sized
256where
257    DB: Backend,
258{
259    /// The Rust type you'd like to map from.
260    ///
261    /// This is typically a tuple of all of your struct's fields.
262    type Row: FromStaticSqlRow<ST, DB>;
263
264    /// Construct an instance of this type
265    fn build(row: Self::Row) -> Result<Self>;
266}
267
268#[doc(inline)]
269pub use diesel_derives::Queryable;
270
271/// Deserializes the result of a query constructed with [`sql_query`].
272///
273/// This trait can be [derived](derive@QueryableByName)
274///
275/// [`sql_query`]: crate::sql_query()
276///
277/// # Examples
278///
279/// If we just want to map a query to our struct, we can use `derive`.
280///
281/// ```rust
282/// # include!("doctest_setup.rs");
283/// # use schema::users;
284/// # use diesel::sql_query;
285/// #
286/// #[derive(QueryableByName, PartialEq, Debug)]
287/// struct User {
288///     id: i32,
289///     name: String,
290/// }
291///
292/// # fn main() {
293/// #     run_test();
294/// # }
295/// #
296/// # fn run_test() -> QueryResult<()> {
297/// #     let connection = &mut establish_connection();
298/// let first_user = sql_query("SELECT * FROM users ORDER BY id LIMIT 1")
299///     .get_result(connection)?;
300/// let expected = User { id: 1, name: "Sean".into() };
301/// assert_eq!(expected, first_user);
302/// #     Ok(())
303/// # }
304/// ```
305///
306/// If we want to do additional work during deserialization, we can use
307/// `deserialize_as` to use a different implementation.
308///
309/// ```rust
310/// # include!("doctest_setup.rs");
311/// # use diesel::sql_query;
312/// # use schema::users;
313/// # use diesel::backend::{self, Backend};
314/// # use diesel::deserialize::{self, FromSql};
315/// #
316/// struct LowercaseString(String);
317///
318/// impl Into<String> for LowercaseString {
319///     fn into(self) -> String {
320///         self.0
321///     }
322/// }
323///
324/// impl<DB, ST> FromSql<ST, DB> for LowercaseString
325/// where
326///     DB: Backend,
327///     String: FromSql<ST, DB>,
328/// {
329///     fn from_sql(bytes: DB::RawValue<'_>) -> deserialize::Result<Self> {
330///         String::from_sql(bytes)
331///             .map(|s| LowercaseString(s.to_lowercase()))
332///     }
333/// }
334///
335/// #[derive(QueryableByName, PartialEq, Debug)]
336/// struct User {
337///     id: i32,
338///     #[diesel(deserialize_as = LowercaseString)]
339///     name: String,
340/// }
341///
342/// # fn main() {
343/// #     run_test();
344/// # }
345/// #
346/// # fn run_test() -> QueryResult<()> {
347/// #     let connection = &mut establish_connection();
348/// let first_user = sql_query("SELECT * FROM users ORDER BY id LIMIT 1")
349///     .get_result(connection)?;
350/// let expected = User { id: 1, name: "sean".into() };
351/// assert_eq!(expected, first_user);
352/// #     Ok(())
353/// # }
354/// ```
355pub trait QueryableByName<DB>
356where
357    Self: Sized,
358    DB: Backend,
359{
360    /// Construct an instance of `Self` from the database row
361    fn build<'a>(row: &impl NamedRow<'a, DB>) -> Result<Self>;
362}
363
364#[doc(inline)]
365pub use diesel_derives::QueryableByName;
366
367/// Deserialize a single field of a given SQL type.
368///
369/// When possible, implementations of this trait should prefer to use an
370/// existing implementation, rather than reading from `bytes`. (For example, if
371/// you are implementing this for an enum which is represented as an integer in
372/// the database, prefer `i32::from_sql(bytes)` (or the explicit form
373/// `<i32 as FromSql<Integer, DB>>::from_sql(bytes)`) over reading from `bytes`
374/// directly)
375///
376/// Types which implement this trait should also have `#[derive(FromSqlRow)]`
377///
378/// ### Backend specific details
379///
380/// - For PostgreSQL, the bytes will be sent using the binary protocol, not text.
381/// - For SQLite, the actual type of `DB::RawValue` is private API. All
382///   implementations of this trait must be written in terms of an existing
383///   primitive.
384/// - For MySQL, the value of `bytes` will depend on the return value of
385///   `type_metadata` for the given SQL type. See [`MysqlType`] for details.
386/// - For third party backends, consult that backend's documentation.
387///
388/// [`MysqlType`]: ../mysql/enum.MysqlType.html
389///
390/// ### Examples
391///
392/// Most implementations of this trait will be defined in terms of an existing
393/// implementation.
394///
395/// ```rust
396/// # use diesel::backend::{self, Backend};
397/// # use diesel::sql_types::*;
398/// # use diesel::deserialize::{self, FromSql, FromSqlRow};
399/// #
400/// #[repr(i32)]
401/// #[derive(Debug, Clone, Copy, FromSqlRow)]
402/// pub enum MyEnum {
403///     A = 1,
404///     B = 2,
405/// }
406///
407/// impl<DB> FromSql<Integer, DB> for MyEnum
408/// where
409///     DB: Backend,
410///     i32: FromSql<Integer, DB>,
411/// {
412///     fn from_sql(bytes: DB::RawValue<'_>) -> deserialize::Result<Self> {
413///         match i32::from_sql(bytes)? {
414///             1 => Ok(MyEnum::A),
415///             2 => Ok(MyEnum::B),
416///             x => Err(format!("Unrecognized variant {}", x).into()),
417///         }
418///     }
419/// }
420/// ```
421#[diagnostic::on_unimplemented(
422    message = "cannot deserialize a value of the database type `{A}` as `{Self}`",
423    note = "double check your type mappings via the documentation of `{A}`"
424)]
425pub trait FromSql<A, DB: Backend>: Sized {
426    /// See the trait documentation.
427    fn from_sql(bytes: DB::RawValue<'_>) -> Result<Self>;
428
429    /// A specialized variant of `from_sql` for handling null values.
430    ///
431    /// The default implementation returns an `UnexpectedNullError` for
432    /// an encountered null value and calls `Self::from_sql` otherwise
433    ///
434    /// If your custom type supports null values you need to provide a
435    /// custom implementation.
436    #[inline(always)]
437    fn from_nullable_sql(bytes: Option<DB::RawValue<'_>>) -> Result<Self> {
438        match bytes {
439            Some(bytes) => Self::from_sql(bytes),
440            None => Err(Box::new(crate::result::UnexpectedNullError)),
441        }
442    }
443}
444
445/// Deserialize a database row into a rust data structure
446///
447/// Diesel provides wild card implementations of this trait for all types
448/// that implement one of the following traits:
449///    * [`Queryable`]
450///    * [`QueryableByName`]
451#[diagnostic::on_unimplemented(
452    note = "double check your type mappings via the documentation of `{ST}`",
453    note = "`diesel::sql_query` requires the loading target to column names for loading values.\n\
454             You need to provide a type that explicitly derives `diesel::deserialize::QueryableByName`"
455)]
456pub trait FromSqlRow<ST, DB: Backend>: Sized {
457    /// See the trait documentation.
458    fn build_from_row<'a>(row: &impl Row<'a, DB>) -> Result<Self>;
459}
460
461#[doc(inline)]
462pub use diesel_derives::FromSqlRow;
463
464/// A marker trait indicating that the corresponding type consumes a static at
465/// compile time known number of field
466///
467/// There is normally no need to implement this trait. Diesel provides
468/// wild card impls for all types that implement `FromSql<ST, DB>` or `Queryable<ST, DB>`
469/// where the size of `ST` is known
470pub trait StaticallySizedRow<ST, DB: Backend>: FromSqlRow<ST, DB> {
471    /// The number of fields that this type will consume.
472    const FIELD_COUNT: usize;
473}
474
475impl<DB, T> FromSqlRow<Untyped, DB> for T
476where
477    DB: Backend,
478    T: QueryableByName<DB>,
479{
480    fn build_from_row<'a>(row: &impl Row<'a, DB>) -> Result<Self> {
481        T::build(row)
482    }
483}
484
485/// A helper trait to deserialize a statically sized row into a tuple
486///
487/// **If you see an error message mentioning this trait you are likely trying to
488/// map the result of a query to a struct with mismatching field types. Recheck
489/// your field order and the concrete field types.**
490///
491/// You should not need to implement this trait directly.
492/// Diesel provides wild card implementations for any supported tuple size
493/// and for any type that implements `FromSql<ST, DB>`.
494///
495// This is a distinct trait from `FromSqlRow` because otherwise we
496// are getting conflicting implementation errors for our `FromSqlRow`
497// implementation for tuples and our wild card impl for all types
498// implementing `Queryable`
499pub trait FromStaticSqlRow<ST, DB: Backend>: Sized {
500    /// See the trait documentation
501    fn build_from_row<'a>(row: &impl Row<'a, DB>) -> Result<Self>;
502}
503
504#[doc(hidden)]
505pub trait SqlTypeOrSelectable {}
506
507impl<ST> SqlTypeOrSelectable for ST where ST: SqlType + SingleValue {}
508impl<U, DB> SqlTypeOrSelectable for SelectBy<U, DB>
509where
510    U: Selectable<DB>,
511    DB: Backend,
512{
513}
514
515impl<T, ST, DB> FromSqlRow<ST, DB> for T
516where
517    T: Queryable<ST, DB>,
518    ST: SqlTypeOrSelectable,
519    DB: Backend,
520    T::Row: FromStaticSqlRow<ST, DB>,
521{
522    // This inline(always) attribute is here as benchmarks have shown
523    // up to 5% reduction in instruction count of having it here
524    //
525    // A plain inline attribute does not show similar improvements
526    #[inline(always)]
527    fn build_from_row<'a>(row: &impl Row<'a, DB>) -> Result<Self> {
528        let row = <T::Row as FromStaticSqlRow<ST, DB>>::build_from_row(row)?;
529        T::build(row)
530    }
531}
532
533impl<T, ST, DB> FromStaticSqlRow<ST, DB> for T
534where
535    DB: Backend,
536    T: FromSql<ST, DB>,
537    ST: SingleValue,
538{
539    fn build_from_row<'a>(row: &impl Row<'a, DB>) -> Result<Self> {
540        use crate::row::Field;
541
542        let field = row.get(0).ok_or(crate::result::UnexpectedEndOfRow)?;
543        T::from_nullable_sql(field.value()).map_err(|e| {
544            if e.is::<crate::result::UnexpectedNullError>() {
545                e
546            } else {
547                Box::new(crate::result::DeserializeFieldError::new(field, e))
548            }
549        })
550    }
551}
552
553// We cannot have this impl because rustc
554// then complains in third party crates that
555// diesel may implement `SingleValue` for tuples
556// in the future. While that is theoretically true,
557// that will likely not happen in practice.
558// If we get negative trait impls at some point in time
559// it should be possible to make this work.
560/*impl<T, ST, DB> Queryable<ST, DB> for T
561where
562    DB: Backend,
563    T: FromStaticSqlRow<ST, DB>,
564    ST: SingleValue,
565{
566    type Row = Self;
567
568    fn build(row: Self::Row) -> Self {
569        row
570    }
571}*/
572
573impl<T, ST, DB> StaticallySizedRow<ST, DB> for T
574where
575    ST: SqlTypeOrSelectable + crate::util::TupleSize,
576    T: Queryable<ST, DB>,
577    DB: Backend,
578{
579    const FIELD_COUNT: usize = <ST as crate::util::TupleSize>::SIZE;
580}
581
582/// A helper trait for giving a type a useful default value.
583///
584/// This is needed for types that can be used as range to represent the empty range as
585/// (Bound::Excluded(DEFAULT), Bound::Excluded(DEFAULT)).
586/// When possible, implementations of this trait should fall back to using std::default::Default.
587#[allow(dead_code)]
588pub(crate) trait Defaultable {
589    /// Returns the "default value" for a type.
590    fn default_value() -> Self;
591}
592
593// We cannot have this impl because rustc
594// then complains in third party crates that
595// diesel may implement `Default`in the future.
596// If we get negative trait impls at some point in time
597// it should be possible to make this work.
598//// Defaultable for types that has Default
599//impl<T: Default> Defaultable for T {
600//    fn default_value() -> Self {
601//        T::default()
602//    }
603//}