ORM pour Rust : comparaison et exemples
L'écosystème Rust propose plusieurs solutions puissantes pour travailler avec les bases de données. Dans cet article, nous comparons trois outils de type ORM populaires : Diesel, SeaORM et SQLx. Chacun a sa propre philosophie et son domaine d'application. Examinons leurs caractéristiques, leurs performances et donnons des exemples pratiques.
1. Diesel — l'ORM classique avec sécurité de typage
Diesel est l'ORM le plus mature pour Rust, construit sur le principe de « sécurité de typage à la compilation ». Il nécessite une description explicite du schéma via des migrations et génère des structures strictement typées.
Caractéristiques :
- La compilation vérifie la validité des requêtes (erreurs SQL — à l'étape de construction)
- Prise en charge de PostgreSQL, MySQL, SQLite
- Moteur synchrone (pour l'asynchrone, nécessite
diesel-async) - DSL propre pour la construction de requêtes
Exemple de code (Diesel + PostgreSQL) :
// models.rsuse diesel::prelude::*;
#[derive(Queryable, Selectable)]#[diesel(table_name = crate::schema::users)]#[diesel(check_for_backend(diesel::pg::Pg))]pub struct User { pub id: i32, pub name: String, pub email: String,}
// main.rsuse diesel::prelude::*;use diesel::pg::PgConnection;
fn get_user(conn: &mut PgConnection, user_id: i32) -> Option<User> { use crate::schema::users::dsl::*; users.filter(id.eq(user_id)) .first::<User>(conn) .ok()}Quand choisir : pour les projets où la sécurité des requêtes à la compilation est critique et où vous êtes prêt à adopter un schéma strict.
2. SeaORM — ORM asynchrone avec approche ActiveRecord
SeaORM est un ORM asynchrone moderne, inspiré de Ruby on Rails. Il prend en charge à la fois le code-first et la génération d'entités à partir d'une base de données existante.
Caractéristiques :
- Asynchrone complet (Tokio, async-std)
- Prise en charge de PostgreSQL, MySQL, SQLite, ainsi que CockroachDB
- Migrations, relations (has_many, belongs_to), pagination
- Générateur de code
sea-orm-cli
Exemple de code (SeaORM + PostgreSQL) :
use sea_orm::*;use entity::user;
async fn find_user(db: &DatabaseConnection, user_id: i32) -> Result<Option<user::Model>, DbErr> { user::Entity::find_by_id(user_id) .one(db) .await}
// Utilisationasync fn example() { let db = Database::connect("postgres://user:pass@localhost/db").await.unwrap(); if let Some(user) = find_user(&db, 42).await.unwrap() { println!("Utilisateur : {} ({})", user.name, user.email); }}Quand choisir : pour les applications web asynchrones (Actix, Axum) où un développement actif et des fonctionnalités riches « prêtes à l'emploi » sont nécessaires.
3. SQLx — « presque ORM » avec une flexibilité maximale
SQLx n'est pas tout à fait un ORM, mais plutôt un client SQL asynchrone avec vérification des requêtes. Il permet d'écrire du SQL pur, mais vérifie sa validité à la compilation.
Caractéristiques :
- Vérification des requêtes à la compilation (via la macro
sqlx::query!) - Asynchrone complet
- Prise en charge de PostgreSQL, MySQL, SQLite, MSSQL
- Prise en charge de JSON, migrations, pool de connexions
Exemple de code (SQLx + PostgreSQL) :
use sqlx::PgPool;
#[derive(sqlx::FromRow)]struct User { id: i32, name: String, email: String,}
async fn get_user(pool: &PgPool, user_id: i32) -> Result<Option<User>, sqlx::Error> { sqlx::query_as::<_, User>("SELECT id, name, email FROM users WHERE id = $1") .bind(user_id) .fetch_optional(pool) .await}Quand choisir : si vous préférez écrire du SQL