Миграции баз данных в Rust: Обзор инструментов и библиотек
При разработке любого приложения рано или поздно возникает необходимость изменить структуру базы данных. Добавление новых колонок, создание индексов или переименование таблиц — всё это требует аккуратного управления версиями схемы. В экосистеме Rust существует несколько зрелых решений для выполнения миграций. В этой статье мы рассмотрим основные подходы и библиотеки, доступные для задач управления схемой БД.
Зачем нужны миграции?
Миграции позволяют:
- Версионировать изменения — каждая миграция представляет собой отдельный файл с номером версии.
- Автоматизировать развёртывание — накатывать и откатывать изменения при деплое.
- Работать в команде — все разработчики синхронизируют схему локально.
- Избегать ошибок — миграции защищают от случайного изменения данных.
Основные инструменты для миграций в Rust
1. Diesel Migration (встроенный в Diesel ORM)
Diesel — самый популярный ORM для Rust. Он предоставляет встроенный движок для миграций через CLI-утилиту diesel_cli.
Основные возможности:
- Генерация файлов миграций с SQL-запросами.
- Поддержка PostgreSQL, MySQL, SQLite.
- Команды:
migration generate,migration run,migration redo. - Автоматическое отслеживание применённых миграций.
Пример создания и применения миграции:
# Установка CLI
cargo install diesel_cli --no-default-features --features postgres
# Создание новой миграции
diesel migration generate create_users
# В папке migrations/ появятся два SQL-файла:
# up.sql — код для наката
# down.sql — код для отката
# Применение миграции
diesel migration run
Содержимое up.sql:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);
down.sql:
DROP TABLE IF EXISTS users;
2. SQLx migrate (часть экосистемы SQLx)
SQLx — асинхронный драйвер для SQL-баз данных. Его подсистема миграций работает без ORM, только с чистыми SQL-скриптами.
Отличительные черты:
- Поддержка PostgreSQL, MySQL, SQLite, MSSQL.
- Интеграция с CLI и программный запуск из кода.
- Возможность использования Rust-кода для проверок перед миграцией.
- Автоматическая проверка целостности (хеши файлов).
Пример программного запуска миграций в Rust:
use sqlx::migrate::Migrator;
use sqlx::PgPool;
#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
let pool = PgPool::connect("postgres://user:pass@localhost/db").await?;
// Указываем путь к папке с миграциями
let migrator = Migrator::new(std::path::Path::new("./migrations")).await?;
// Запускаем все неприменённые миграции
migrator.run(&pool).await?;
println!("Миграции выполнены успешно!");
Ok(())
}
Структура папки migrations/:
migrations/
├── 20231001_initial.sql
├── 20231002_add_email_index.sql
└── 20231003_create_roles.sql
Каждый файл содержит обычный SQL, например:
-- 20231001_initial.sql
CREATE TABLE IF NOT EXISTS users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
username TEXT NOT NULL UNIQUE
);
3. SeaORM Migrator (часть SeaORM)
SeaORM — современный асинхронный ORM, который предлагает собственную систему миграций SeaORM Migrator. Она позволяет писать миграции на Rust, а не на SQL, что даёт больше контроля и типобезопасность.
Преимущества:
- Миграции пишутся на Rust с использованием структурированного API.
- Поддержка PostgreSQL, MySQL, SQLite.
- Встроенная поддержка откатов (rollback).
- Генерация миграций через CLI.
Пример миграции на Rust:
use sea_orm_migration::prelude::*;