Featured image of post Rust Diesel ORM In a Nutshell

Rust Diesel ORM In a Nutshell

Rust ORM

Rust Diesel ORM In a Nutshell

So, you’ve been messing around with Rust, and you’ve realized you need a database. You start Googling, and BOOM—you stumble upon Diesel, Rust’s fancy-pants ORM (Object-Relational Mapper). But what exactly is it, and why should you care?


Why Diesel?

Rust is all about safety and performance, right? Diesel embraces that philosophy by making SQL interactions type-safe. No more “Oops, I sent a string where an integer was expected” kind of bugs.

With Diesel, your database interactions are checked at compile time, meaning fewer runtime surprises and more confidence in your code. Plus, it’s built for speed. Because who likes slow queries?


Setting Up Diesel

1. Install Diesel CLI

First things first, install the Diesel CLI. You’ll need cargo and some patience:

1
cargo install diesel_cli --no-default-features --features sqlite

You can swap sqlite with postgres or mysql depending on your database of choice.

2. Initialize Diesel

Run the following in your Rust project’s root:

1
diesel setup

This sets up a diesel.toml configuration file and a migrations directory. If you see errors, you probably forgot to install the database you’re using. Go fix that first!

3. Add Diesel to Cargo.toml

1
2
3
[dependencies]
diesel = { version = "2.0", features = ["sqlite"] }
serde = { version = "1.0", features = ["derive"] }

Again, swap out sqlite for postgres or mysql if needed.


Defining a Schema

Diesel uses diesel print-schema to generate a Rust representation of your database schema. Run:

1
diesel print-schema > src/schema.rs

Now, you’ll have a schema.rs file that looks something like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// src/schema.rs

// Auto-generated by Diesel. DO NOT EDIT!
table! {
    users (id) {
        id -> Integer,
        name -> Text,
        email -> Text,
    }
}

Boom! Your database schema is now part of your Rust code. Nice and safe.


Creating Models

Next, define your Rust models. This is where things start getting fun.

1
2
3
4
5
6
7
8
9
// src/models.rs
use diesel::prelude::*;

#[derive(Queryable)]
pub struct User {
    pub id: i32,
    pub name: String,
    pub email: String,
}

This User struct now matches the users table. Diesel’s magic ensures that everything is type-safe.


Running Queries

Inserting Data

Adding a new user is as easy as:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
use diesel::prelude::*;
use diesel::sqlite::SqliteConnection;
use crate::schema::users;
use crate::models::User;

pub fn create_user(conn: &SqliteConnection, name: &str, email: &str) -> User {
    use crate::schema::users::dsl::*;

    let new_user = (name.eq(name), email.eq(email));
    
    diesel::insert_into(users)
        .values(&new_user)
        .execute(conn)
        .expect("Error saving new user");
}

Fetching Data

Want to get all users? Easy:

1
2
3
4
5
pub fn get_users(conn: &SqliteConnection) -> Vec<User> {
    use crate::schema::users::dsl::*;

    users.load::<User>(conn).expect("Error loading users")
}

Diesel handles all the boilerplate, and you get your results in a nice, safe Vec<User>.


Diesel vs Other ORMs

Here’s a quick comparison between Diesel and some popular ORMs:

FeatureDieselSQLxSeaORM
Compile-time safety✅ Yes❌ No❌ No
Async support❌ No✅ Yes✅ Yes
Raw SQL support✅ Yes✅ Yes✅ Yes
Migration support✅ Yes✅ Yes✅ Yes
Learning curveMediumEasyHard

As you can see, Diesel shines in compile-time safety, but it’s not async-friendly. If you need async, SQLx or SeaORM might be better choices.



Key Ideas

ConceptSummary
Diesel ORMRust’s type-safe, compile-time-checked database ORM
SetupInstall Diesel CLI, initialize, and configure Cargo dependencies
Schemadiesel print-schema generates Rust code for your database schema
ModelsDefine Rust structs that match your DB tables
QueriesDiesel makes inserts, updates, and selects type-safe and intuitive
ComparisonDiesel is safer but lacks async, unlike SQLx or SeaORM

References