Convert Figma logo to code with AI

diesel-rs logodiesel

A safe, extensible ORM and Query Builder for Rust

12,518
1,043
12,518
136

Top Related Projects

6,922

🐚 An async & dynamic ORM for Rust

12,950

🧰 The Rust SQL Toolkit. An async, pure Rust SQL crate featuring compile-time checked queries without a DSL. Supports PostgreSQL, MySQL, and SQLite.

🚂 Engine components of Prisma ORM

2,246

Rust Compile Time ORM robustness,async, pure Rust Dynamic SQL

Native PostgreSQL driver for the Rust programming language

Quick Overview

Diesel is a safe, extensible ORM and Query Builder for Rust. It provides a high-level, type-safe API for interacting with SQL databases, allowing developers to write efficient database queries without compromising on Rust's safety guarantees.

Pros

  • Strong type safety and compile-time query checking
  • Support for multiple database backends (PostgreSQL, MySQL, SQLite)
  • Excellent performance due to zero-cost abstractions
  • Seamless integration with Rust's ecosystem and tooling

Cons

  • Steeper learning curve compared to some other ORMs
  • Limited support for NoSQL databases
  • May require more boilerplate code for complex queries
  • Documentation can be challenging for beginners

Code Examples

  1. Defining a table structure:
table! {
    users (id) {
        id -> Integer,
        name -> Text,
        email -> Text,
    }
}
  1. Inserting a new record:
let new_user = NewUser { name: "John Doe", email: "john@example.com" };
diesel::insert_into(users::table)
    .values(&new_user)
    .execute(conn)?;
  1. Querying records:
let results = users::table
    .filter(users::name.eq("John Doe"))
    .limit(5)
    .load::<User>(conn)?;
  1. Updating a record:
diesel::update(users::table)
    .filter(users::id.eq(1))
    .set(users::name.eq("Jane Doe"))
    .execute(conn)?;

Getting Started

  1. Add Diesel to your Cargo.toml:

    [dependencies]
    diesel = { version = "2.0.0", features = ["postgres"] }
    
  2. Set up the database connection:

    use diesel::prelude::*;
    use diesel::pg::PgConnection;
    
    let database_url = "postgres://username:password@localhost/diesel_demo";
    let conn = PgConnection::establish(&database_url)
        .expect("Error connecting to database");
    
  3. Generate schema and models:

    diesel setup
    diesel migration generate create_users
    diesel migration run
    
  4. Use Diesel in your Rust code:

    use diesel::prelude::*;
    use crate::schema::users;
    
    #[derive(Queryable)]
    struct User {
        id: i32,
        name: String,
        email: String,
    }
    
    let users = users::table.load::<User>(&mut conn)?;
    

Competitor Comparisons

6,922

🐚 An async & dynamic ORM for Rust

Pros of Sea-ORM

  • Async support out of the box, making it suitable for modern asynchronous Rust applications
  • More flexible and adaptable to different database schemas without requiring code regeneration
  • Supports multiple databases (MySQL, PostgreSQL, SQLite) with a unified API

Cons of Sea-ORM

  • Generally slower performance compared to Diesel due to its runtime abstraction
  • Less mature ecosystem and community support
  • Steeper learning curve for developers new to ORM concepts

Code Comparison

Diesel query:

let results = users
    .filter(published.eq(true))
    .limit(5)
    .load::<Post>(&mut conn)?;

Sea-ORM query:

let results = Post::find()
    .filter(post::Column::Published.eq(true))
    .limit(5)
    .all(&db).await?;

Both ORMs provide a similar query-building experience, but Sea-ORM's async nature is evident in its use of .await. Diesel's syntax is slightly more concise, while Sea-ORM's is more explicit about column references.

Sea-ORM offers more flexibility in working with different database schemas without regenerating code, which can be advantageous in certain development scenarios. However, Diesel's static approach often results in better performance and compile-time checks.

The choice between these ORMs depends on specific project requirements, such as the need for async support, performance considerations, and the desired level of abstraction.

12,950

🧰 The Rust SQL Toolkit. An async, pure Rust SQL crate featuring compile-time checked queries without a DSL. Supports PostgreSQL, MySQL, and SQLite.

Pros of SQLx

  • Async-first design, supporting modern asynchronous Rust programming
  • Compile-time checked queries, ensuring SQL correctness at compile-time
  • Support for multiple databases (PostgreSQL, MySQL, SQLite) without changing code

Cons of SQLx

  • Steeper learning curve due to its more low-level nature
  • Less abstraction over database operations compared to Diesel's ORM approach
  • Potentially more verbose for complex queries or relationships

Code Comparison

SQLx:

let users = sqlx::query!("SELECT * FROM users WHERE active = ?", true)
    .fetch_all(&pool)
    .await?;

Diesel:

let users = users::table
    .filter(users::active.eq(true))
    .load::<User>(&connection)?;

Summary

SQLx offers a more low-level, async-first approach with compile-time query checking, while Diesel provides a higher-level ORM experience. SQLx supports multiple databases seamlessly, but may require more code for complex operations. Diesel offers a more traditional ORM interface, potentially simplifying certain tasks at the cost of less flexibility in some scenarios.

🚂 Engine components of Prisma ORM

Pros of Prisma Engines

  • More extensive database support, including MongoDB and CockroachDB
  • Automatic database migrations and schema generation
  • Powerful query API with type-safe queries and results

Cons of Prisma Engines

  • Steeper learning curve due to its unique query API
  • Less flexibility in raw SQL queries compared to Diesel
  • Potentially higher overhead for simple applications

Code Comparison

Prisma query:

const users = await prisma.user.findMany({
  where: { age: { gte: 18 } },
  select: { name: true, email: true }
})

Diesel query:

let users = users::table
    .filter(users::age.ge(18))
    .select((users::name, users::email))
    .load::<(String, String)>(&mut conn)?;

Both Prisma and Diesel are powerful ORM tools for Rust, but they cater to different needs. Prisma offers a more comprehensive solution with automatic migrations and support for various databases, while Diesel provides a more Rust-native approach with better raw SQL integration. The choice between them depends on project requirements, database complexity, and developer preferences.

2,246

Rust Compile Time ORM robustness,async, pure Rust Dynamic SQL

Pros of rbatis

  • Supports multiple databases (MySQL, PostgreSQL, SQLite, etc.) out of the box
  • Provides dynamic SQL generation with a macro-based approach
  • Offers both synchronous and asynchronous APIs

Cons of rbatis

  • Less mature and less widely adopted compared to Diesel
  • Documentation may be less comprehensive or up-to-date
  • Steeper learning curve due to its macro-heavy approach

Code Comparison

rbatis:

#[crud_table]
#[derive(Clone, Debug)]
pub struct User {
    pub id: Option<u64>,
    pub name: Option<String>,
}

let user = User { id: None, name: Some("John".to_string()) };
rb.save(&user, &[]).await?;

Diesel:

#[derive(Queryable, Insertable)]
#[table_name = "users"]
struct User {
    id: Option<i32>,
    name: String,
}

let user = User { id: None, name: "John".to_string() };
diesel::insert_into(users::table).values(&user).execute(conn)?;

Both rbatis and Diesel provide ORM functionality for Rust, but they differ in their approach and feature set. rbatis offers more flexibility with database support and dynamic SQL generation, while Diesel is more established and has a simpler learning curve. The choice between them depends on specific project requirements and developer preferences.

Native PostgreSQL driver for the Rust programming language

Pros of rust-postgres

  • More lightweight and focused solely on PostgreSQL
  • Provides lower-level control over database operations
  • Supports asynchronous operations with tokio

Cons of rust-postgres

  • Requires more manual SQL writing compared to Diesel's ORM approach
  • Less abstraction for database-agnostic operations
  • Steeper learning curve for developers unfamiliar with raw SQL

Code Comparison

Diesel (ORM-style query):

let results = users
    .filter(published.eq(true))
    .limit(5)
    .load::<Post>(&mut conn)?;

rust-postgres (raw SQL query):

let rows = client.query(
    "SELECT * FROM posts WHERE published = $1 LIMIT $2",
    &[&true, &5],
)?;

Diesel focuses on type-safe, ORM-style queries using Rust's type system, while rust-postgres requires writing raw SQL strings. Diesel provides more compile-time safety and abstraction, whereas rust-postgres offers more direct control over the SQL being executed.

Both libraries are well-maintained and popular choices for working with PostgreSQL in Rust. Diesel is better suited for projects requiring an ORM with database-agnostic features, while rust-postgres is ideal for developers who prefer working directly with SQL and need PostgreSQL-specific functionality.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

diesel logo

A safe, extensible ORM and Query Builder for Rust

Build Status Gitter Crates.io

API Documentation: latest release – master branch

Homepage

Diesel gets rid of the boilerplate for database interaction and eliminates runtime errors without sacrificing performance. It takes full advantage of Rust's type system to create a low overhead query builder that "feels like Rust."

Supported databases:

  1. PostgreSQL
  2. MySQL
  3. SQLite

You can configure the database backend in Cargo.toml:

[dependencies]
diesel = { version = "<version>", features = ["<postgres|mysql|sqlite>"] }

Getting Started

Find our extensive Getting Started tutorial at https://diesel.rs/guides/getting-started. Guides on more specific features are coming soon.

Getting help

If you run into problems, Diesel has a very active Gitter room. You can come ask for help at gitter.im/diesel-rs/diesel. For help with longer questions and discussion about the future of Diesel, open a discussion on GitHub Discussions.

Usage

Simple queries

Simple queries are a complete breeze. Loading all users from a database:

users::table.load(&mut connection)

Executed SQL:

SELECT * FROM users;

Loading all the posts for a user:

Post::belonging_to(user).load(&mut connection)

Executed SQL:

SELECT * FROM posts WHERE user_id = 1;

Complex queries

Diesel's powerful query builder helps you construct queries as simple or complex as you need, at zero cost.

let versions = Version::belonging_to(krate)
  .select(id)
  .order(num.desc())
  .limit(5);
let downloads = version_downloads
  .filter(date.gt(now - 90.days()))
  .filter(version_id.eq_any(versions))
  .order(date)
  .load::<Download>(&mut conn)?;

Executed SQL:

SELECT version_downloads.*
  WHERE date > (NOW() - '90 days')
    AND version_id = ANY(
      SELECT id FROM versions
        WHERE crate_id = 1
        ORDER BY num DESC
        LIMIT 5
    )
  ORDER BY date

Less boilerplate

Diesel codegen generates boilerplate for you. It lets you focus on your business logic, not mapping to and from SQL rows.

That means you can write this:

#[derive(Queryable, Selectable)]
#[diesel(table_name = downloads)]
pub struct Download {
    id: i32,
    version_id: i32,
    downloads: i32,
    counted: i32,
    date: SystemTime,
}

Instead of this without Diesel:

pub struct Download {
    id: i32,
    version_id: i32,
    downloads: i32,
    counted: i32,
    date: SystemTime,
}

impl Download {
    fn from_row(row: &Row) -> Download {
        Download {
            id: row.get("id"),
            version_id: row.get("version_id"),
            downloads: row.get("downloads"),
            counted: row.get("counted"),
            date: row.get("date"),
        }
    }
}

Inserting data

It's not just about reading data. Diesel makes it easy to use structs for new records.

#[derive(Insertable)]
#[diesel(table_name = users)]
struct NewUser<'a> {
    name: &'a str,
    hair_color: Option<&'a str>,
}

let new_users = vec![
    NewUser { name: "Sean", hair_color: Some("Black") },
    NewUser { name: "Gordon", hair_color: None },
];

insert_into(users)
    .values(&new_users)
    .execute(&mut connection);

Executed SQL:

INSERT INTO users (name, hair_color) VALUES
  ('Sean', 'Black'),
  ('Gordon', DEFAULT)

If you need data from the rows you inserted, just change execute to get_result or get_results. Diesel will take care of the rest.

let new_users = vec![
    NewUser { name: "Sean", hair_color: Some("Black") },
    NewUser { name: "Gordon", hair_color: None },
];

let inserted_users = insert_into(users)
    .values(&new_users)
    .get_results::<User>(&mut connection);

Executed SQL:

INSERT INTO users (name, hair_color) VALUES
  ('Sean', 'Black'),
  ('Gordon', DEFAULT)
  RETURNING *

Updating data

Diesel's codegen can generate several ways to update a row, letting you encapsulate your logic in the way that makes sense for your app.

Modifying a struct:

post.published = true;
post.save_changes(&mut connection);

One-off batch changes:

update(users.filter(email.like("%@spammer.com")))
    .set(banned.eq(true))
    .execute(&mut connection)

Using a struct for encapsulation:

update(Settings::belonging_to(current_user))
    .set(&settings_form)
    .execute(&mut connection)

Raw SQL

There will always be certain queries that are just easier to write as raw SQL, or can't be expressed with the query builder. Even in these cases, Diesel provides an easy to use API for writing raw SQL.

#[derive(QueryableByName)]
#[diesel(table_name = users)]
struct User {
    id: i32,
    name: String,
    organization_id: i32,
}

// Using `include_str!` allows us to keep the SQL in a
// separate file, where our editor can give us SQL specific
// syntax highlighting.
sql_query(include_str!("complex_users_by_organization.sql"))
    .bind::<Integer, _>(organization_id)
    .bind::<BigInt, _>(offset)
    .bind::<BigInt, _>(limit)
    .load::<User>(&mut conn)?;

Code of conduct

Anyone who interacts with Diesel in any space, including but not limited to this GitHub repository, must follow our code of conduct.

License

Licensed under either of these:

Contributing

Before contributing, please read the contributors guide for useful information about setting up Diesel locally, coding style and common abbreviations.

Unless you explicitly state otherwise, any contribution you intentionally submit for inclusion in the work, as defined in the Apache-2.0 license, shall be dual-licensed as above, without any additional terms or conditions.