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