pub trait Queryable<ST, DB>: Sizedwhere
DB: Backend,{
type Row: FromStaticSqlRow<ST, DB>;
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
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.