From 7107371727ac6231a94706517e5348b6ac1d9507 Mon Sep 17 00:00:00 2001 From: Saurav Sharma Date: Sat, 6 Jan 2024 18:29:24 +0545 Subject: [PATCH] feat!: direcly provides MigrationCommand to create cli Signed-off-by: Saurav Sharma --- .github/workflows/publish.yml | 3 ++ README.MD | 36 ++++++++++++++++--- examples/mysql/main.rs | 3 +- examples/postgres/main.rs | 3 +- examples/sqlite/main.rs | 3 +- src/cli.rs | 66 +++++++++++++++++++++-------------- src/migrator/mod.rs | 6 ++-- 7 files changed, 83 insertions(+), 37 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index ccffa10..dc7a656 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -3,6 +3,9 @@ on: push: tags: "v*" +permissions: + contents: write + jobs: publish_crate: name: Publish to crates.io diff --git a/README.MD b/README.MD index 2164b5e..95fdbfe 100644 --- a/README.MD +++ b/README.MD @@ -95,7 +95,7 @@ impl Migration for FirstMigration { } // use parents function to add parents of a migrations. - fn parents(&self) -> Vec>> { + fn parents(&self) -> Vec>> { vec![] } @@ -133,10 +133,37 @@ migrator.apply_all(&pool).await.unwrap(); migrator.revert_all(&pool).await.unwrap(); ``` -Or you can create cli +Or you can create cli using ```rust -sqlx_migrator::cli::run(Box::new(migrator), &pool).await.unwrap(); +use sqlx_migrator::cli::MigrationCommand; +MigrationCommand::parse_and_run(Box::new(migrator), &pool).await.unwrap(); +``` + +If you want to extend your own clap based cli then you can add migrator to sub command enum and then run migrator +```rust +#[derive(clap::Parser)] +struct Cli { + #[command(subcommand)] + sub_command: CliSubcommand +} + +#[derive(clap::Subcommand)] +enum CliSubcommand { + #[command()] + Migrator(sqlx_migrator::cli::MigrationCommand) +} + +impl Cli { + async fn run() { + let cli = Self::parse(); + match cli.sub_command { + Migrator(m) => { + m.run(Box::new(migrator), &pool).await.unwrap() + } + } + } +} ``` # Migrate from sqlx default sql based migration @@ -152,7 +179,8 @@ Can be easily applied by following above usage docs where you only need to write Then you can create cli for migrator ```rust -sqlx_migrator::cli::run(Box::new(migrator), &pool).await.unwrap(); +use sqlx_migrator::cli::MigrationCommand; +MigrationCommand::parse_and_run(Box::new(migrator), &pool).await.unwrap(); ``` and run fake apply cli command diff --git a/examples/mysql/main.rs b/examples/mysql/main.rs index 4c0a1f8..194e98a 100644 --- a/examples/mysql/main.rs +++ b/examples/mysql/main.rs @@ -1,4 +1,5 @@ //! Example crate for mysql +use sqlx_migrator::cli::MigrationCommand; use sqlx_migrator::migrator::{Info, Migrator}; use sqlx_migrator::sqlx::MySql; @@ -10,7 +11,7 @@ async fn main() { let mut migrator = Migrator::default(); migrator.add_migrations(migrations::migrations()); // There are two way to run migration. Either you can create cli as shown below - sqlx_migrator::cli::run(Box::new(migrator), &pool) + MigrationCommand::parse_and_run(Box::new(migrator), &pool) .await .unwrap(); // Or you can directly use migrator apply_all function instead of creating diff --git a/examples/postgres/main.rs b/examples/postgres/main.rs index e01996d..fd2a06a 100644 --- a/examples/postgres/main.rs +++ b/examples/postgres/main.rs @@ -1,4 +1,5 @@ //! Example crate for postgres +use sqlx_migrator::cli::MigrationCommand; use sqlx_migrator::migrator::{Info, Migrator}; use sqlx_migrator::sqlx::Postgres; @@ -10,7 +11,7 @@ async fn main() { let mut migrator = Migrator::default().with_prefix("prefix").unwrap(); migrator.add_migrations(migrations::migrations()); // There are two way to run migration. Either you can create cli as shown below - sqlx_migrator::cli::run(Box::new(migrator), &pool) + MigrationCommand::parse_and_run(Box::new(migrator), &pool) .await .unwrap(); // Or you can directly use migrator apply_all function instead of creating diff --git a/examples/sqlite/main.rs b/examples/sqlite/main.rs index 2e84306..b0be657 100644 --- a/examples/sqlite/main.rs +++ b/examples/sqlite/main.rs @@ -1,4 +1,5 @@ //! Example crate for sqlite +use sqlx_migrator::cli::MigrationCommand; use sqlx_migrator::migrator::{Info, Migrator}; use sqlx_migrator::sqlx::Sqlite; @@ -10,7 +11,7 @@ async fn main() { let mut migrator = Migrator::default(); migrator.add_migrations(migrations::migrations()); // There are two way to run migration. Either you can create cli as shown below - sqlx_migrator::cli::run(Box::new(migrator), &pool) + MigrationCommand::parse_and_run(Box::new(migrator), &pool) .await .unwrap(); // Or you can directly use migrator apply_all function instead of creating diff --git a/src/cli.rs b/src/cli.rs index 6f09163..ea204cd 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -8,15 +8,48 @@ use sqlx::Pool; use crate::error::Error; use crate::migrator::{Migrate, Plan}; +/// Migration command for performing rust based sqlx migrations #[derive(Parser, Debug)] -struct Args { +pub struct MigrationCommand { #[command(subcommand)] sub_command: SubCommand, } +impl MigrationCommand { + /// Parse `MigrationCommand` and run migration command line interface + /// + /// # Errors + /// If migration command fails to complete and raise some issue + pub async fn parse_and_run( + migrator: Box>, + pool: &Pool, + ) -> Result<(), Error> + where + DB: sqlx::Database, + { + let migration_command = Self::parse(); + migration_command.run(migrator, pool).await + } + + /// Run migration command line interface + /// + /// # Errors + /// If migration command fails to complete and raise some issue + pub async fn run( + &self, + migrator: Box>, + pool: &Pool, + ) -> Result<(), Error> + where + DB: sqlx::Database, + { + self.sub_command.handle_subcommand(migrator, pool).await?; + Ok(()) + } +} + #[derive(Subcommand, Debug)] -/// Subcommand for sqlx migrator cli -pub enum SubCommand { +enum SubCommand { /// Apply migrations #[command()] Apply(Apply), @@ -34,11 +67,7 @@ pub enum SubCommand { } impl SubCommand { - /// Handle all subcommand operations - /// - /// # Errors - /// If any subcommand operations fail running - pub async fn handle_subcommand( + async fn handle_subcommand( &self, migrator: Box>, pool: &Pool, @@ -136,9 +165,8 @@ where } #[derive(Parser, Debug)] -/// CLI struct for apply subcommand #[allow(clippy::struct_excessive_bools)] -pub struct Apply { +struct Apply { /// App name up to which migration needs to be applied. If migration option /// is also present than only till migration is applied #[arg(long)] @@ -242,9 +270,8 @@ impl Apply { } #[derive(Parser, Debug)] -/// CLI struct for revert subcommand #[allow(clippy::struct_excessive_bools)] -pub struct Revert { +struct Revert { /// Revert all migration. Conflicts with app args #[arg(long, conflicts_with = "app")] all: bool, @@ -341,18 +368,3 @@ impl Revert { Ok(()) } } - -/// Run full cli by parsing args with help of migrator. If you only need to add -/// subcommand to your app than use `SubCommand` enum `handle_subcommand` -/// function -/// -/// # Errors -/// When command fails to run and raises error -pub async fn run(migrator: Box>, pool: &Pool) -> Result<(), Error> -where - DB: sqlx::Database, -{ - let args = Args::parse(); - args.sub_command.handle_subcommand(migrator, pool).await?; - Ok(()) -} diff --git a/src/migrator/mod.rs b/src/migrator/mod.rs index a921325..1f38190 100644 --- a/src/migrator/mod.rs +++ b/src/migrator/mod.rs @@ -222,9 +222,9 @@ pub trait Info { let migration_parents = migration.parents(); let migration_replaces = migration.replaces(); let is_new_value = self.migrations_mut().insert(migration); - // Only add parents and replaces if migrations was added first time. This can - // increase performance of recursive addition by ignoring parent and replace - // migration recursive addition + // Only add parents and replaces migrations if current migration was added first + // time. This can increase performance of recursive addition by ignoring + // parent and replace migration recursive addition if is_new_value { for parent in migration_parents { self.add_migration(parent);