ORM для Rust: сравнение и примеры
Экосистема Rust предлагает несколько мощных решений для работы с базами данных. В этой статье мы сравним три популярных ORM-подобных инструмента: Diesel, SeaORM и SQLx. Каждый из них имеет свою философию и область применения. Рассмотрим их особенности, производительность и приведём практические примеры.
1. Diesel — классический ORM с безопасностью типов
Diesel — самый зрелый ORM для Rust, построенный на принципе «безопасность типов во время компиляции». Он требует явного описания схемы через миграции и генерирует строго типизированные структуры.
Особенности:
- Компиляция проверяет корректность запросов (ошибки SQL — на этапе сборки)
- Поддержка PostgreSQL, MySQL, SQLite
- Синхронный движок (для асинхронности требуется
diesel-async) - Собственный DSL для построения запросов
Пример кода (Diesel + PostgreSQL):
// models.rs
use 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.rs
use 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()
}
Когда выбрать: для проектов, где критична безопасность запросов на этапе компиляции, и вы готовы к строгой схеме.
2. SeaORM — асинхронный ORM с ActiveRecord-подходом
SeaORM — современный асинхронный ORM, вдохновлённый Ruby on Rails. Поддерживает как код-ферст, так и генерацию сущностей из существующей БД.
Особенности:
- Полная асинхронность (Tokio, async-std)
- Поддержка PostgreSQL, MySQL, SQLite, а также CockroachDB
- Миграции, связи (has_many, belongs_to), пагинация
- Генератор кода
sea-orm-cli
Пример кода (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
}
// Использование
async fn example() {
let db = Database::connect("postgres://user:pass@localhost/db").await.unwrap();
if let Some(user) = find_user(&db, 42).await.unwrap() {
println!("User: {} ({})", user.name, user.email);
}
}
Когда выбрать: для асинхронных веб-приложений (Actix, Axum), где нужна активная разработка и богатый функционал «из коробки».
3. SQLx — «почти ORM» с максимальной гибкостью
SQLx — не совсем ORM, а скорее асинхронный SQL-клиент с проверкой запросов. Он позволяет писать чистый SQL, но проверяет его корректность на этапе компиляции.
Особенности:
- Проверка запросов во время компиляции (через макрос
sqlx::query!) - Полная асинхронность
- Поддержка PostgreSQL, MySQL, SQLite, MSSQL
- Поддержка JSON, миграций, пула соединений
Пример кода (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
}
Когда выбрать: если вы предпочитаете писать SQL вручную, но хотите проверку типов и асинхронность. Отлично подходит для сложных запросов.
Сравнительная таблица
- Тип проверки: Diesel — компиляция; SeaORM — runtime + частичная ком