pub trait Queryable<ST, DB>: Sizedwhere
DB: Backend,{
type Row: FromStaticSqlRow<ST, DB>;
// Required method
fn build(row: Self::Row) -> Result<Self>;
}
Expand description
Trait indicating that a record can be queried from the database.
Types which implement Queryable
represent the result of a SQL query. This
does not necessarily mean they represent a single database table.
Diesel represents the return type of a query as a tuple. The purpose of this trait is to convert from a tuple of Rust values that have been deserialized into your struct.
This trait can be derived
§How to resolve compiler errors while loading data from the database
In case you getting uncomprehensable compiler errors while loading data
from the database you might want to consider using
#[derive(Selectable)]
+
#[diesel(check_for_backend(YourBackendType))]
to check for mismatching fields at compile
time. This drastically improves the quality of the generated error messages by pointing
to concrete mismatches at field level. You need to specify the concrete database backend
this specific struct is indented to be used with, as otherwise rustc cannot correctly
identify the required deserialization implementation.
§Interaction with NULL
/Option
Nullable
types can be queried into Option
.
This is valid for single fields, tuples, and structures with Queryable
.
With tuples and structs, the process for deserializing an Option<(A,B,C)>
is
to attempt to deserialize A
, B
and C
, and if either of these return an
UnexpectedNullError
, the Option
will be
deserialized as None
.
If all succeed, the Option
will be deserialized as Some((a,b,c))
.
§Examples
§Simple mapping from query to struct
If we just want to map a query to our struct, we can use derive
.
#[derive(Queryable, PartialEq, Debug)]
struct User {
id: i32,
name: String,
}
let first_user = users.order_by(id).first(connection)?;
let expected = User { id: 1, name: "Sean".into() };
assert_eq!(expected, first_user);
§Interaction with NULL
/Option
§Single field
table! {
animals {
id -> Integer,
species -> VarChar,
legs -> Integer,
name -> Nullable<VarChar>,
}
}
#[derive(Queryable, PartialEq, Debug)]
struct Animal {
id: i32,
name: Option<String>,
}
let all_animals = animals.select((id, name)).order_by(id).load(connection)?;
let expected = vec![Animal { id: 1, name: Some("Jack".to_owned()) }, Animal { id: 2, name: None }];
assert_eq!(expected, all_animals);
§Multiple fields
#[derive(Queryable, PartialEq, Debug)]
struct UserWithPost {
id: i32,
post: Option<Post>,
}
#[derive(Queryable, PartialEq, Debug)]
struct Post {
id: i32,
title: String,
}
let all_posts = users::table
.left_join(posts::table)
.select((
users::id,
(posts::id, posts::title).nullable()
))
.order_by((users::id, posts::id))
.load(connection)?;
let expected = vec![
UserWithPost { id: 1, post: Some(Post { id: 1, title: "My first post".to_owned() }) },
UserWithPost { id: 1, post: Some(Post { id: 2, title: "About Rust".to_owned() }) },
UserWithPost { id: 2, post: Some(Post { id: 3, title: "My first post too".to_owned() }) },
UserWithPost { id: 3, post: None },
];
assert_eq!(expected, all_posts);
§deserialize_as
attribute
If we want to do additional work during deserialization, we can use
deserialize_as
to use a different implementation.
struct LowercaseString(String);
impl Into<String> for LowercaseString {
fn into(self) -> String {
self.0
}
}
impl<DB> Queryable<Text, DB> for LowercaseString
where
DB: Backend,
String: FromSql<Text, DB>,
{
type Row = String;
fn build(s: String) -> deserialize::Result<Self> {
Ok(LowercaseString(s.to_lowercase()))
}
}
#[derive(Queryable, PartialEq, Debug)]
struct User {
id: i32,
#[diesel(deserialize_as = LowercaseString)]
name: String,
}
let first_user = users.first(connection)?;
let expected = User { id: 1, name: "sean".into() };
assert_eq!(expected, first_user);
§Manual implementation
Alternatively, we can implement the trait for our struct manually.
use schema::users;
use diesel::deserialize::{self, Queryable};
type DB = diesel::sqlite::Sqlite;
#[derive(PartialEq, Debug)]
struct User {
id: i32,
name: String,
}
impl Queryable<users::SqlType, DB> for User {
type Row = (i32, String);
fn build(row: Self::Row) -> deserialize::Result<Self> {
Ok(User {
id: row.0,
name: row.1.to_lowercase(),
})
}
}
let first_user = users.first(connection)?;
let expected = User { id: 1, name: "sean".into() };
assert_eq!(expected, first_user);
Required Associated Types§
sourcetype Row: FromStaticSqlRow<ST, DB>
type Row: FromStaticSqlRow<ST, DB>
The Rust type you’d like to map from.
This is typically a tuple of all of your struct’s fields.