#spring #migration #database-migrations #framework #sql #di

springtime-migrate-refinery

基于依赖注入的 SQL 迁移框架

3 个版本

0.2.2 2024年5月7日
0.2.1 2023年11月27日
0.2.0 2023年5月8日

#1560 in 数据库接口

MIT 许可证

165KB
3K SLoC

Springtime Migrate Refinery

crates.io version build status

refinery 是一个强大的 Rust SQL 迁移工具包,使创建迁移变得简单。此包将 refinery 与更广泛的 Springtime 框架 集成,允许通过依赖注入提供数据库客户端和迁移,从而进一步简化创建和应用迁移,无论是从文件还是 Rust 代码中。

注意:除了这个包,您还需要导入 springtime-di

特性

  • 自动迁移发现
  • 基于文件和代码的迁移
  • 启动时自动应用配置的数据库客户端的迁移
  • 支持所有 refinery 数据库客户端

基本用法

refinery 类似,基本用法包括创建或嵌入迁移,并提供所需数据库的运行器。

以下示例假设您熟悉 springtimespringtime-di

use refinery_core::Runner;
use springtime::application;
use springtime::future::{BoxFuture, FutureExt};
use springtime_di::instance_provider::ErrorPtr;
use springtime_migrate_refinery::migration::embed_migrations;
use springtime_migrate_refinery::runner::MigrationRunnerExecutor;

// this is all that's needed to embed sql migrations from the given folder (the default path is
// "migrations")
embed_migrations!("examples/migrations");

// this is a migration source, which can provide migrations from code, instead of sql files
#[derive(Component)]
struct ExampleMigrationSource;

// register the source with dependency injection
#[component_alias]
impl MigrationSource for ExampleMigrationSource {
    fn migrations(&self) -> Result<Vec<Migration>, ErrorPtr> {
        Migration::unapplied("V00__test", "CREATE TABLE test (id INTEGER PRIMARY KEY);")
            .map(|migration| vec![migration])
            .map_err(|error| Arc::new(error) as ErrorPtr)
    }
}

// refinery migration runner needs a concrete DB client to run - this necessitates an abstraction
// layer; please see MigrationRunnerExecutor for details
struct ExampleMigrationRunnerExecutor;

impl MigrationRunnerExecutor for ExampleMigrationRunnerExecutor {
    fn run_migrations(&self, _runner: &Runner) -> BoxFuture<'_, Result<(), ErrorPtr>> {
        // run migrations here with the given runner
        async { Ok(()) }.boxed()
    }
}

// note: for the sake of simplicity, errors are unwrapped, rather than gracefully handled
#[tokio::main]
async fn main() {
    // create our application, which will run refinery migration runner before other runners
    let mut application =
        application::create_default().expect("unable to create default application");

    // will run migrations from the "migrations" folder if MigrationRunnerExecutor(s) are available
    application.run().await.expect("error running application");
}

依赖

~9–26MB
~398K SLoC