Skip to main content

diesel/
deserialize.rs

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