ORM para Rust: comparação completa e exemplos de uso
O ecossistema Rust oferece várias soluções poderosas para trabalhar com bancos de dados. Neste artigo, compararemos detalhadamente três abordagens principais: Diesel (síncrono, ORM compilável), SeaORM (assíncrono, flexível) e SQLx (minimalista, com verificação de consultas em tempo de compilação). Você descobrirá qual ferramenta escolher para tarefas específicas e verá exemplos práticos de código.
1. Diesel — ORM síncrono comprovado
Diesel é o ORM mais maduro para Rust. Sua principal característica é a segurança de tipos em tempo de compilação. Todas as consultas SQL são verificadas durante a compilação, eliminando toda uma classe de erros. Funciona apenas de forma síncrona, mas com tokio é possível organizar um pool de conexões.
Exemplo de uso do Diesel:
// models.rs#[derive(Queryable, Insertable)]#[table_name = "users"]pub struct User { pub id: i32, pub name: String, pub email: String,}
// main.rsuse diesel::prelude::*;use diesel::dsl::insert_into;
fn main() { let conn = PgConnection::establish("postgres://user:pass@localhost/db") .expect("Database connection failed");
let new_user = User { id: 0, name: "Alice".into(), email: "alice@example.com".into(), };
let inserted = insert_into(users::table) .values(&new_user) .get_result::<User>(&conn) .expect("Insert failed");
println!("Created user: {}", inserted.name);}Vantagens: desempenho máximo, tipagem estrita, migrações integradas.
Desvantagens: síncrono, configuração complexa, não suporta async nativamente.
2. SeaORM — assíncrono e flexível
SeaORM é um ORM assíncrono moderno, construído sobre sqlx. Suporta tokio e async-std. Oferece uma API rica para CRUD, relacionamentos (um-para-um, um-para-muitos) e migrações. Ideal para aplicações web com Actix ou Axum.
Exemplo com SeaORM:
use sea_orm::*;use sea_orm::entity::prelude::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]#[sea_orm(table_name = "users")]pub struct Model { #[sea_orm(primary_key)] pub id: i32, pub name: String, pub email: String,}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]pub enum Relation {}
impl ActiveModelBehavior for ActiveModel {}
// Usoasync fn create_user(db: &DatabaseConnection) -> Result<(), DbErr> { let user = ActiveModel { name: Set("Bob".to_owned()), email: Set("bob@example.com".to_owned()), ..Default::default() }; let result = user.insert(db).await?; println!("User created with id: {}", result.id); Ok(())}Vantagens: async completo, suporte a PostgreSQL, MySQL, SQLite, migrações simples.
Desvantagens: mais lento que Diesel em testes sintéticos, mais dependências.
3. SQLx — leve e seguro
SQLx não é um ORM no sentido clássico, mas sim um driver SQL assíncrono com verificação de consultas em tempo de compilação. Você escreve SQL puro, e o SQLx verifica sua sintaxe e tipos de argumentos. Suporta PostgreSQL, MySQL, SQLite. É uma excelente escolha se você prefere controle total sobre as consultas.
Exemplo SQLx:
use sqlx::postgres::PgPool;
#[derive(sqlx::FromRow)]struct User { id: i32, name: String, email: String,}
#[tokio::main]async fn main() -> Result<(), sqlx::Error> { let pool = PgPool::connect("postgres://user:pass@localhost/db").await?;
let user = sqlx::query_as::<_, User>( "SELECT id, name, email FROM users WHERE email = $1"