From c30a4a5d88c31f60458700a445946c68124eb0e5 Mon Sep 17 00:00:00 2001 From: Pedro de Matos Fedricci Date: Fri, 1 Apr 2022 16:19:51 -0300 Subject: [PATCH] Add --source for migration subcommands (#1769) --- sqlx-cli/README.md | 24 +++++- sqlx-cli/src/lib.rs | 53 ++++++++---- sqlx-cli/src/opt.rs | 194 ++++++++++++++++++++++++++++++++++---------- 3 files changed, 207 insertions(+), 64 deletions(-) diff --git a/sqlx-cli/README.md b/sqlx-cli/README.md index 2b62da44..08e56e38 100644 --- a/sqlx-cli/README.md +++ b/sqlx-cli/README.md @@ -3,9 +3,9 @@ SQLx's associated command-line utility for managing databases, migrations, and enabling "offline" mode with `sqlx::query!()` and friends. -### Install +## Install -#### With Rust toolchain +### With Rust toolchain ```bash # supports all databases supported by SQLx @@ -40,21 +40,36 @@ sqlx database create sqlx database drop ``` +--- + #### Create and run migrations ```bash -$ sqlx migrate add +sqlx migrate add ``` + Creates a new file in `migrations/-.sql`. Add your database schema changes to this new file. --- + ```bash -$ sqlx migrate run +sqlx migrate run ``` + Compares the migration history of the running database against the `migrations/` folder and runs any scripts that are still pending. +--- + +Users can provide the directory for the migration scripts to `sqlx migrate` subcommands with the `--source` flag. + +```bash +sqlx migrate info --source ../relative/migrations +``` + +--- + #### Reverting Migrations If you would like to create _reversible_ migrations with corresponding "up" and "down" scripts, you use the `-r` flag when creating new migrations: @@ -133,6 +148,7 @@ In order for sqlx to be able to find queries behind certain feature flags you ne on by passing arguments to rustc. This is how you would turn all targets and features on. + ```bash cargo sqlx prepare -- --all-targets --all-features ``` diff --git a/sqlx-cli/src/lib.rs b/sqlx-cli/src/lib.rs index d02f4fa3..b877d450 100644 --- a/sqlx-cli/src/lib.rs +++ b/sqlx-cli/src/lib.rs @@ -15,35 +15,58 @@ pub async fn run(opt: Opt) -> Result<()> { match opt.command { Command::Migrate(migrate) => match migrate.command { MigrateCommand::Add { + source, description, reversible, - } => migrate::add(&migrate.source, &description, reversible).await?, + } => migrate::add(source.resolve(&migrate.source), &description, reversible).await?, MigrateCommand::Run { + source, dry_run, ignore_missing, database_url, - } => migrate::run(&migrate.source, &database_url, dry_run, ignore_missing).await?, - MigrateCommand::Revert { - dry_run, - ignore_missing, - database_url, - } => migrate::revert(&migrate.source, &database_url, dry_run, ignore_missing).await?, - MigrateCommand::Info { database_url } => { - migrate::info(&migrate.source, &database_url).await? + } => { + migrate::run( + source.resolve(&migrate.source), + &database_url, + dry_run, + *ignore_missing, + ) + .await? + } + MigrateCommand::Revert { + source, + dry_run, + ignore_missing, + database_url, + } => { + migrate::revert( + source.resolve(&migrate.source), + &database_url, + dry_run, + *ignore_missing, + ) + .await? + } + MigrateCommand::Info { + source, + database_url, + } => migrate::info(source.resolve(&migrate.source), &database_url).await?, + MigrateCommand::BuildScript { source, force } => { + migrate::build_script(source.resolve(&migrate.source), force)? } - MigrateCommand::BuildScript { force } => migrate::build_script(&migrate.source, force)?, }, Command::Database(database) => match database.command { DatabaseCommand::Create { database_url } => database::create(&database_url).await?, - DatabaseCommand::Drop { yes, database_url } => { - database::drop(&database_url, !yes).await? - } + DatabaseCommand::Drop { + confirmation, + database_url, + } => database::drop(&database_url, !confirmation).await?, DatabaseCommand::Reset { - yes, + confirmation, source, database_url, - } => database::reset(&source, &database_url, !yes).await?, + } => database::reset(&source, &database_url, !confirmation).await?, DatabaseCommand::Setup { source, database_url, diff --git a/sqlx-cli/src/opt.rs b/sqlx-cli/src/opt.rs index afa354d3..c7ac046f 100644 --- a/sqlx-cli/src/opt.rs +++ b/sqlx-cli/src/opt.rs @@ -1,4 +1,6 @@ -use clap::Parser; +use std::ops::{Deref, Not}; + +use clap::{Args, Parser}; #[derive(Parser, Debug)] #[clap(version, about, author)] @@ -35,9 +37,8 @@ pub enum Command { #[clap(last = true)] args: Vec, - /// Location of the DB, by default will be read from the DATABASE_URL env var - #[clap(long, short = 'D', env)] - database_url: String, + #[clap(flatten)] + database_url: DatabaseUrl, }, #[clap(alias = "mig")] @@ -55,48 +56,38 @@ pub struct DatabaseOpt { pub enum DatabaseCommand { /// Creates the database specified in your DATABASE_URL. Create { - /// Location of the DB, by default will be read from the DATABASE_URL env var - #[clap(long, short = 'D', env)] - database_url: String, + #[clap(flatten)] + database_url: DatabaseUrl, }, /// Drops the database specified in your DATABASE_URL. Drop { - /// Automatic confirmation. Without this option, you will be prompted before dropping - /// your database. - #[clap(short)] - yes: bool, + #[clap(flatten)] + confirmation: Confirmation, - /// Location of the DB, by default will be read from the DATABASE_URL env var - #[clap(long, short = 'D', env)] - database_url: String, + #[clap(flatten)] + database_url: DatabaseUrl, }, /// Drops the database specified in your DATABASE_URL, re-creates it, and runs any pending migrations. Reset { - /// Automatic confirmation. Without this option, you will be prompted before dropping - /// your database. - #[clap(short)] - yes: bool, + #[clap(flatten)] + confirmation: Confirmation, - /// Path to folder containing migrations. - #[clap(long, default_value = "migrations")] - source: String, + #[clap(flatten)] + source: Source, - /// Location of the DB, by default will be read from the DATABASE_URL env var - #[clap(long, short = 'D', env)] - database_url: String, + #[clap(flatten)] + database_url: DatabaseUrl, }, /// Creates the database specified in your DATABASE_URL and runs any pending migrations. Setup { - /// Path to folder containing migrations. - #[clap(long, default_value = "migrations")] - source: String, + #[clap(flatten)] + source: Source, - /// Location of the DB, by default will be read from the DATABASE_URL env var - #[clap(long, short = 'D', env)] - database_url: String, + #[clap(flatten)] + database_url: DatabaseUrl, }, } @@ -104,6 +95,7 @@ pub enum DatabaseCommand { #[derive(Parser, Debug)] pub struct MigrateOpt { /// Path to folder containing migrations. + /// Warning: deprecated, use --source #[clap(long, default_value = "migrations")] pub source: String, @@ -118,6 +110,9 @@ pub enum MigrateCommand { Add { description: String, + #[clap(flatten)] + source: SourceOverride, + /// If true, creates a pair of up and down migration files with same version /// else creates a single sql file #[clap(short)] @@ -126,47 +121,156 @@ pub enum MigrateCommand { /// Run all pending migrations. Run { + #[clap(flatten)] + source: SourceOverride, + /// List all the migrations to be run without applying #[clap(long)] dry_run: bool, - /// Ignore applied migrations that missing in the resolved migrations - #[clap(long)] - ignore_missing: bool, + #[clap(flatten)] + ignore_missing: IgnoreMissing, - /// Location of the DB, by default will be read from the DATABASE_URL env var - #[clap(long, short = 'D', env)] - database_url: String, + #[clap(flatten)] + database_url: DatabaseUrl, }, /// Revert the latest migration with a down file. Revert { + #[clap(flatten)] + source: SourceOverride, + /// List the migration to be reverted without applying #[clap(long)] dry_run: bool, - /// Ignore applied migrations that missing in the resolved migrations - #[clap(long)] - ignore_missing: bool, + #[clap(flatten)] + ignore_missing: IgnoreMissing, - /// Location of the DB, by default will be read from the DATABASE_URL env var - #[clap(long, short = 'D', env)] - database_url: String, + #[clap(flatten)] + database_url: DatabaseUrl, }, /// List all available migrations. Info { - /// Location of the DB, by default will be read from the DATABASE_URL env var - #[clap(long, env)] - database_url: String, + #[clap(flatten)] + source: SourceOverride, + + #[clap(flatten)] + database_url: DatabaseUrl, }, /// Generate a `build.rs` to trigger recompilation when a new migration is added. /// /// Must be run in a Cargo project root. BuildScript { + #[clap(flatten)] + source: SourceOverride, + /// Overwrite the build script if it already exists. #[clap(long)] force: bool, }, } + +/// Argument for the migration scripts source. +#[derive(Args, Debug)] +pub struct Source { + /// Path to folder containing migrations. + #[clap(long, default_value = "migrations")] + source: String, +} + +impl Deref for Source { + type Target = String; + + fn deref(&self) -> &Self::Target { + &self.source + } +} + +/// Argument for overriding migration scripts source. +// Note: once `MigrateOpt.source` is removed, usage can be replaced with `Source`. +#[derive(Args, Debug)] +pub struct SourceOverride { + /// Path to folder containing migrations [default: migrations] + #[clap(long)] + source: Option, +} + +impl SourceOverride { + /// Override command's `source` flag value with subcommand's + /// `source` flag value when provided. + #[inline] + pub(super) fn resolve<'a>(&'a self, source: &'a str) -> &'a str { + match self.source { + Some(ref source) => source, + None => source, + } + } +} + +/// Argument for the database URL. +#[derive(Args, Debug)] +pub struct DatabaseUrl { + /// Location of the DB, by default will be read from the DATABASE_URL env var + #[clap(long, short = 'D', env)] + database_url: String, +} + +impl Deref for DatabaseUrl { + type Target = String; + + fn deref(&self) -> &Self::Target { + &self.database_url + } +} + +/// Argument for automatic confirmantion. +#[derive(Args, Copy, Clone, Debug)] +pub struct Confirmation { + /// Automatic confirmation. Without this option, you will be prompted before dropping + /// your database. + #[clap(short)] + yes: bool, +} + +impl Deref for Confirmation { + type Target = bool; + + fn deref(&self) -> &Self::Target { + &self.yes + } +} + +impl Not for Confirmation { + type Output = bool; + + fn not(self) -> Self::Output { + !self.yes + } +} + +/// Argument for ignoring applied migrations that were not resolved. +#[derive(Args, Copy, Clone, Debug)] +pub struct IgnoreMissing { + /// Ignore applied migrations that are missing in the resolved migrations + #[clap(long)] + ignore_missing: bool, +} + +impl Deref for IgnoreMissing { + type Target = bool; + + fn deref(&self) -> &Self::Target { + &self.ignore_missing + } +} + +impl Not for IgnoreMissing { + type Output = bool; + + fn not(self) -> Self::Output { + !self.ignore_missing + } +}