Миграции баз данных в Rust: обзор инструментов Diesel, SeaORM и sqlx
Управление изменениями схемы базы данных — одна из ключевых задач в разработке любого веб-приложения. В экосистеме Rust для этой цели существует несколько зрелых инструментов. В этой статье мы рассмотрим три основных подхода к миграциям: Diesel, SeaORM и sqlx. Каждый из них предлагает свой уникальный подход к управлению версиями схемы БД, и выбор правильного инструмента может существенно повлиять на архитектуру проекта.
1. Diesel — классический ORM с интеграцией миграций
Diesel — это безопасный, расширяемый ORM и Query Builder для Rust, который тесно интегрирован с системой миграций. Его главное преимущество — проверка типов на уровне компиляции: структуры таблиц генерируются на основе схемы БД, что исключает ошибки несоответствия типов.
Миграции в Diesel — это обычные SQL-файлы, организованные в директории migrations/. Каждая миграция содержит два файла: up.sql (применение изменений) и down.sql (откат).
Пример структуры миграции для создания таблицы пользователей:
-- migrations/2024-01-15-120000_create_users/up.sql
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username VARCHAR(255) NOT NULL UNIQUE,
email VARCHAR(255) NOT NULL UNIQUE,
created_at TIMESTAMP NOT NULL DEFAULT NOW()
);
-- migrations/2024-01-15-120000_create_users/down.sql
DROP TABLE IF EXISTS users;
Для запуска миграций используется CLI-инструмент diesel_cli:
# Установка
cargo install diesel_cli --no-default-features --features postgres
# Запуск миграций
diesel migration run
# Откат последней миграции
diesel migration revert
# Генерация новой миграции
diesel migration generate create_users
Плюсы Diesel:
- Полная проверка типов на этапе компиляции
- Простая и понятная структура миграций (чистый SQL)
- Встроенная поддержка откатов
- Отличная производительность
Минусы:
- Требуется установка дополнительного CLI-инструмента
- Сложная настройка для проектов с несколькими базами данных
- Меньшая гибкость по сравнению с sqlx
2. SeaORM — асинхронный ORM с гибкой системой миграций
SeaORM (на основе sea-query и sqlx) — это асинхронный ORM, который предлагает более современный подход к миграциям. В отличие от Diesel, миграции в SeaORM пишутся на Rust, а не на SQL, что позволяет использовать всю мощь языка для описания изменений схемы.
Пример миграции с использованием SeaORM:
use sea_orm_migration::prelude::*;
#[derive(DeriveMigrationName)]
pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.create_table(
Table::create()
.table(Users::Table)
.if_not_exists()
.col(
ColumnDef::new(Users::Id)
.integer()
.not_null()
.auto_increment()
.primary_key(),
)
.col(ColumnDef::new(Users::Username).string().not_null())
.col(ColumnDef::new(Users::Email).string().not_null())
.col(
ColumnDef::new(Users::CreatedAt)
.timestamp()
.default(Expr::current_timestamp()),
)
.to_owned(),
)
.await
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.drop_table(Table::drop().table(Users::Table).to_owned())
.await
}
}
SeaORM предоставляет встроенную поддержку миграций через sea-orm-cli:
# Генерация новой миграции
sea-orm-cli migrate generate create_users_table
# Применение миграций
sea-orm-cli migrate up
# Откат
sea-orm-cli migrate down
Плюсы SeaORM:
- Миграции на Rust — полный контроль и типизация
- Асинхронность из коробки
- Простая интеграция с Actix-web и Axum
- Хорошая документация
Минусы:
- Больше шаблонного кода по сравнению с SQL-миграциями
- Менее зрелый, чем Diesel
- Зависимость от