Interacting with Relational Databases in Rust: A Comparison of Diesel and SQLx

Introduction to Diesel and SQLx

Rust is a systems programming language that prioritizes safety, performance, and concurrency. When it comes to interacting with relational databases, Rust provides several libraries to choose from. In this article, we’ll explore two popular libraries: Diesel and SQLx.

What is Diesel?

Diesel is an Object-Relational Mapping (ORM) library that supports PostgreSQL, MySQL, and SQLite. ORMs help abstract the details of relational databases, allowing developers to interact with databases using object-oriented programming. Diesel provides a query builder, making it easier to write SQL queries and reducing the risk of SQL injection attacks.

What is SQLx?

SQLx is a Rust SQL library that provides a low-level interface for interacting with databases. Unlike Diesel, SQLx is not an ORM; instead, it focuses on providing a simple and efficient way to execute SQL queries. SQLx supports connection pooling, cross-platform development, and asynchronous notifications, making it a great choice for high-performance applications.

Getting Started with Diesel

To get started with Diesel, we’ll create a new project and add the required dependencies. We’ll then set up our database connection and create a migration to define our database schema.


cargo new classroom_diesel

Add the following dependencies to your Cargo.toml file:


[dependencies]
diesel = { version = "1.4.4", features = ["mysql"] }
dotenv = "0.15.0"

Next, we’ll create a model for our Students table and use Diesel’s query builder to perform CRUD operations.


// models.rs
use diesel::prelude::*;

#[derive(Debug, Queryable)]
pub struct Student {
    pub id: i32,
    pub firstname: String,
    pub lastname: String,
    pub age: i32,
}

// main.rs
use diesel::prelude::*;
use dotenv::dotenv;
use std::env;

fn main() {
    // Load environment variables
    dotenv().ok();

    // Establish a database connection
    let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
    let conn = PgConnection::establish(&database_url).unwrap();

    // Create a new student
    let new_student = Student {
        id: 1,
        first_name: "John".to_string(),
        last_name: "Doe".to_string(),
        age: 25,
    };

    diesel::insert_into(students::table)
       .values(new_student)
       .execute(&conn)
       .unwrap();
}

Getting Started with SQLx

To get started with SQLx, we’ll create a new project and add the required dependencies. We’ll then establish a database connection and use SQLx’s query API to perform CRUD operations.


cargo new classroom_sqlx

Add the following dependencies to your Cargo.toml file:


[dependencies]
sqlx = { version = "0.5.11", features = ["mysql"] }
dotenv = "0.15.0"

Next, we’ll use SQLx’s query API to perform CRUD operations.


// main.rs
use sqlx::mysql::{MySqlPool, MySqlRow};
use dotenv::dotenv;
use std::env;

#[async_std::main]
async fn main() -> sqlx::Result<()> {
    // Load environment variables
    dotenv().ok();

    // Establish a database connection
    let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
    let pool = MySqlPool::connect(&database_url).await?;

    // Create a new student
    let new_student = (
        1,
        "John".to_string(),
        "Doe".to_string(),
        25,
    );

    sqlx::query!("INSERT INTO students (id, first_name, last_name, age) VALUES (?,?,?,?)")
       .bind(new_student)
       .execute(&pool)
       .await?;
}

Conclusion

In conclusion, both Diesel and SQLx provide a way to interact with relational databases in Rust. Diesel provides an ORM interface, making it easier to work with databases using object-oriented programming. SQLx provides a low-level interface, giving developers more control over their database interactions. The choice between Diesel and SQLx ultimately depends on the specific needs of your application.

Leave a Reply