Trait diesel::prelude::Queryable

source ·
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§

The Rust type you’d like to map from.

This is typically a tuple of all of your struct’s fields.

Required Methods§

Construct an instance of this type

Implementations on Foreign Types§

Implementors§