Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Querying Records

Toasty generates several ways to retrieve records: by primary key, by indexed fields, or by building queries with filters.

Get by primary key

<YourModel>::get_by_id() fetches a single record by its primary key. It returns the record directly, or an error if no record exists with that key.

#![allow(unused)]
fn main() {
use toasty::Model;
#[derive(Debug, toasty::Model)]
struct User {
    #[key]
    #[auto]
    id: u64,
    name: String,
    #[unique]
    email: String,
}
async fn __example(mut db: toasty::Db) -> toasty::Result<()> {
let user = User::get_by_id(&mut db, &1).await?;
println!("Found: {}", user.name);
Ok(())
}
}

The method name matches the key field name. A model with #[key] code: String generates get_by_code(). Composite keys generate combined names like get_by_student_id_and_course_id().

Get all records

<YourModel>::all() returns a query for all records of that model.

#![allow(unused)]
fn main() {
use toasty::Model;
#[derive(Debug, toasty::Model)]
struct User {
    #[key]
    #[auto]
    id: u64,
    name: String,
    #[unique]
    email: String,
}
async fn __example(mut db: toasty::Db) -> toasty::Result<()> {
let users = User::all().exec(&mut db).await?;

for user in &users {
    println!("{}: {}", user.id, user.name);
}
Ok(())
}
}

Executing queries

Queries returned by all(), filter(), and filter_by_*() are not executed until you call a terminal method. Toasty provides three terminal methods:

.exec() — collect all results

Returns all matching records as a Vec:

#![allow(unused)]
fn main() {
use toasty::Model;
#[derive(Debug, toasty::Model)]
struct User {
    #[key]
    #[auto]
    id: u64,
    name: String,
    #[unique]
    email: String,
}
async fn __example(mut db: toasty::Db) -> toasty::Result<()> {
let users: Vec<User> = User::all().exec(&mut db).await?;
Ok(())
}
}

.first() — get the first result or None

Returns Option<User>Some if at least one record matches, None if the query returns no results:

#![allow(unused)]
fn main() {
use toasty::Model;
#[derive(Debug, toasty::Model)]
struct User {
    #[key]
    #[auto]
    id: u64,
    name: String,
    #[unique]
    email: String,
}
async fn __example(mut db: toasty::Db) -> toasty::Result<()> {
let maybe_user = User::all().first(&mut db).await?;

match maybe_user {
    Some(user) => println!("Found: {}", user.name),
    None => println!("No users found"),
}
Ok(())
}
}

.get() — get exactly one result

Returns the record directly, or an error if no record matches. Use this when you expect the query to return exactly one result:

#![allow(unused)]
fn main() {
use toasty::Model;
#[derive(Debug, toasty::Model)]
struct User {
    #[key]
    #[auto]
    id: u64,
    name: String,
    #[unique]
    email: String,
}
async fn __example(mut db: toasty::Db, user_id: u64) -> toasty::Result<()> {
let user = User::filter_by_id(user_id).get(&mut db).await?;
Ok(())
}
}

Filtering by indexed fields

Toasty generates filter_by_* methods for indexed and key fields. These return a query builder that you can execute with any terminal method.

#![allow(unused)]
fn main() {
use toasty::Model;
#[derive(Debug, toasty::Model)]
struct User {
    #[key]
    #[auto]
    id: u64,
    name: String,
    #[unique]
    email: String,
}
async fn __example(mut db: toasty::Db) -> toasty::Result<()> {
// filter_by_id returns a query builder
let user = User::filter_by_id(1).get(&mut db).await?;

// filter_by_email is generated because email has #[unique]
let user = User::filter_by_email("alice@example.com")
    .get(&mut db)
    .await?;
Ok(())
}
}

The difference between get_by_* and filter_by_*: get_by_* methods execute immediately and return the record. filter_by_* methods return a query builder that you can further customize before executing.

Filtering with expressions

For queries beyond simple field equality, use <YourModel>::filter() with field expressions. The Filtering with Expressions chapter covers this in detail. Here is a quick example:

#![allow(unused)]
fn main() {
use toasty::Model;
#[derive(Debug, toasty::Model)]
struct User {
    #[key]
    #[auto]
    id: u64,
    name: String,
    #[unique]
    email: String,
}
async fn __example(mut db: toasty::Db) -> toasty::Result<()> {
let users = User::filter(User::fields().name().eq("Alice"))
    .exec(&mut db)
    .await?;
Ok(())
}
}

Chaining filters

You can chain .filter() on an existing query to add more conditions:

let users = User::filter_by_name("Alice")
    .filter(User::fields().age().gt(25))
    .exec(&mut db)
    .await?;

Each .filter() call adds an AND condition to the query.

Batch key lookups

For primary key fields, Toasty generates a filter_by_<key>_batch() method that fetches multiple records by key in a single query:

#![allow(unused)]
fn main() {
use toasty::Model;
#[derive(Debug, toasty::Model)]
struct User {
    #[key]
    #[auto]
    id: u64,
    name: String,
    #[unique]
    email: String,
}
async fn __example(mut db: toasty::Db) -> toasty::Result<()> {
let users = User::filter_by_id_batch([&1, &2, &3])
    .exec(&mut db)
    .await?;
Ok(())
}
}

This is more efficient than calling get_by_id() in a loop.

What gets generated

For a model with #[key] on id and #[unique] on email, Toasty generates:

MethodReturnsDescription
User::all()Query builderAll records
User::filter(expr)Query builderRecords matching expression
User::filter_by_id(id)Query builderRecords matching key
User::filter_by_id_batch(ids)Query builderRecords matching any key in list
User::filter_by_email(email)Query builderRecords matching unique field
User::get_by_id(&mut db, &id)Result<User>One record by key (immediate)
User::get_by_email(&mut db, email)Result<User>One record by unique field (immediate)

Query builders support these terminal methods:

MethodReturns
.exec(&mut db)Result<Vec<User>>
.first(&mut db)Result<Option<User>>
.get(&mut db)Result<User>