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//}