Getting Started with Diesel

To begin, ensure that you have Rust installed on your machine. You can install Rust using rustup. Once Rust is set up, create a new Rust project:

cargo new rust_diesel_example
cd rust_diesel_example

Next, add Diesel and the database driver you intend to use to your Cargo.toml. For this example, we'll use PostgreSQL:

[dependencies]
diesel = { version = "2.0", features = ["postgres"] }
dotenv = "0.15"

You can also use SQLite or MySQL by changing the features accordingly.

Setting Up the Database

Before using Diesel, you need to set up your database. For PostgreSQL, you can create a new database using the following command in your terminal:

createdb rust_diesel_example

Next, create a .env file in your project root to store your database URL:

DATABASE_URL=postgres://username:password@localhost/rust_diesel_example

Replace username and password with your PostgreSQL credentials.

Creating the Schema

To define your database schema, you can use Diesel's CLI tool. First, install the Diesel CLI:

cargo install diesel_cli --no-default-features --features postgres

Initialize Diesel in your project:

diesel setup

Next, create a migration for a sample users table:

diesel migration generate create_users

This command creates a new migration file in the migrations directory. Open the generated migration file and define the users table:

-- up.sql
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    name VARCHAR NOT NULL,
    email VARCHAR NOT NULL UNIQUE
);

-- down.sql
DROP TABLE users;

Run the migration to create the table:

diesel migration run

Defining the Models

Now, let's create a model for the users table. Create a new file named models.rs in the src directory:

// src/models.rs
use diesel::{Queryable, Insertable};
use serde::{Serialize, Deserialize};

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

#[derive(Insertable, Serialize, Deserialize)]
#[table_name = "users"]
pub struct NewUser<'a> {
    pub name: &'a str,
    pub email: &'a str,
}

Performing CRUD Operations

In your main.rs, you can now perform CRUD operations. First, import the necessary modules:

// src/main.rs
#[macro_use]
extern crate diesel;
extern crate dotenv;

use dotenv::dotenv;
use std::env;
use diesel::prelude::*;
use crate::models::{User, NewUser};

mod models;

fn establish_connection() -> PgConnection {
    dotenv().ok();
    let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
    PgConnection::establish(&database_url).expect(&format!("Error connecting to {}", database_url))
}

Create

To create a new user, you can write the following function:

fn create_user(conn: &PgConnection, name: &str, email: &str) -> User {
    let new_user = NewUser { name, email };

    diesel::insert_into(users::table)
        .values(&new_user)
        .get_result(conn)
        .expect("Error saving new user")
}

Read

To read users from the database, you can use:

fn get_users(conn: &PgConnection) -> Vec<User> {
    use crate::schema::users::dsl::*;

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

Update

Updating a user can be done as follows:

fn update_user(conn: &PgConnection, user_id: i32, new_name: &str) {
    use crate::schema::users::dsl::*;

    diesel::update(users.find(user_id))
        .set(name.eq(new_name))
        .execute(conn)
        .expect("Error updating user");
}

Delete

Finally, to delete a user:

fn delete_user(conn: &PgConnection, user_id: i32) {
    use crate::schema::users::dsl::*;

    diesel::delete(users.find(user_id))
        .execute(conn)
        .expect("Error deleting user");
}

Putting It All Together

In your main function, you can now call these functions to interact with your database:

fn main() {
    let connection = establish_connection();

    // Create a new user
    let user = create_user(&connection, "Alice", "[email protected]");
    println!("Created user: {:?}", user);

    // Read users
    let users = get_users(&connection);
    println!("All users: {:?}", users);

    // Update user
    update_user(&connection, user.id, "Alice Smith");

    // Delete user
    delete_user(&connection, user.id);
}

Conclusion

In this tutorial, we covered how to set up Diesel in a Rust application, define a database schema, and perform CRUD operations. Diesel's type safety and compile-time checks help ensure that your database interactions are reliable and efficient.

Learn more with useful resources: