Skip to content

Commit

Permalink
feat: Allow specifying multiple migration sources in CLI
Browse files Browse the repository at this point in the history
  • Loading branch information
Tortoaster committed Apr 8, 2024
1 parent 45b5b61 commit 6354fa4
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 18 deletions.
8 changes: 4 additions & 4 deletions sqlx-cli/src/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,18 @@ pub async fn drop(connect_opts: &ConnectOpts, confirm: bool, force: bool) -> any
}

pub async fn reset(
migration_source: &str,
migration_sources: &[String],
connect_opts: &ConnectOpts,
confirm: bool,
force: bool,
) -> anyhow::Result<()> {
drop(connect_opts, confirm, force).await?;
setup(migration_source, connect_opts).await
setup(migration_sources, connect_opts).await
}

pub async fn setup(migration_source: &str, connect_opts: &ConnectOpts) -> anyhow::Result<()> {
pub async fn setup(migration_sources: &[String], connect_opts: &ConnectOpts) -> anyhow::Result<()> {
create(connect_opts).await?;
migrate::run(migration_source, connect_opts, false, false, None).await
migrate::run(migration_sources, connect_opts, false, false, None).await
}

fn ask_to_continue_drop(db_url: &str) -> bool {
Expand Down
34 changes: 26 additions & 8 deletions sqlx-cli/src/migrate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,12 @@ fn short_checksum(checksum: &[u8]) -> String {
s
}

pub async fn info(migration_source: &str, connect_opts: &ConnectOpts) -> anyhow::Result<()> {
let migrator = Migrator::new(Path::new(migration_source)).await?;
pub async fn info(migration_sources: &[String], connect_opts: &ConnectOpts) -> anyhow::Result<()> {
let paths: Vec<_> = migration_sources
.iter()
.map(|source| Path::new(source))
.collect();
let migrator = Migrator::new(paths).await?;
let mut conn = crate::connect(&connect_opts).await?;

conn.ensure_migrations_table().await?;
Expand Down Expand Up @@ -272,13 +276,17 @@ fn validate_applied_migrations(
}

pub async fn run(
migration_source: &str,
migration_sources: &[String],
connect_opts: &ConnectOpts,
dry_run: bool,
ignore_missing: bool,
target_version: Option<i64>,
) -> anyhow::Result<()> {
let migrator = Migrator::new(Path::new(migration_source)).await?;
let paths: Vec<_> = migration_sources
.iter()
.map(|source| Path::new(source))
.collect();
let migrator = Migrator::new(paths).await?;
if let Some(target_version) = target_version {
if !migrator.version_exists(target_version) {
bail!(MigrateError::VersionNotPresent(target_version));
Expand Down Expand Up @@ -367,13 +375,17 @@ pub async fn run(
}

pub async fn revert(
migration_source: &str,
migration_sources: &[String],
connect_opts: &ConnectOpts,
dry_run: bool,
ignore_missing: bool,
target_version: Option<i64>,
) -> anyhow::Result<()> {
let migrator = Migrator::new(Path::new(migration_source)).await?;
let paths: Vec<_> = migration_sources
.iter()
.map(|source| Path::new(source))
.collect();
let migrator = Migrator::new(paths).await?;
if let Some(target_version) = target_version {
if target_version != 0 && !migrator.version_exists(target_version) {
bail!(MigrateError::VersionNotPresent(target_version));
Expand Down Expand Up @@ -461,7 +473,7 @@ pub async fn revert(
Ok(())
}

pub fn build_script(migration_source: &str, force: bool) -> anyhow::Result<()> {
pub fn build_script(migration_sources: &[String], force: bool) -> anyhow::Result<()> {
anyhow::ensure!(
Path::new("Cargo.toml").exists(),
"must be run in a Cargo project root"
Expand All @@ -472,11 +484,17 @@ pub fn build_script(migration_source: &str, force: bool) -> anyhow::Result<()> {
"build.rs already exists; use --force to overwrite"
);

let instructions = migration_sources
.iter()
.map(|source| format!(r#"println!("cargo:rerun-if-changed={source}");"#))
.collect::<Vec<_>>()
.join("\n ");

let contents = format!(
r#"// generated by `sqlx migrate build-script`
fn main() {{
// trigger recompilation when a new migration is added
println!("cargo:rerun-if-changed={migration_source}");
{instructions}
}}"#,
);

Expand Down
28 changes: 22 additions & 6 deletions sqlx-cli/src/opt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ pub enum DatabaseCommand {
confirmation: Confirmation,

#[clap(flatten)]
source: Source,
source: Sources,

#[clap(flatten)]
connect_opts: ConnectOpts,
Expand All @@ -101,7 +101,7 @@ pub enum DatabaseCommand {
/// Creates the database specified in your DATABASE_URL and runs any pending migrations.
Setup {
#[clap(flatten)]
source: Source,
source: Sources,

#[clap(flatten)]
connect_opts: ConnectOpts,
Expand Down Expand Up @@ -156,7 +156,7 @@ pub enum MigrateCommand {
/// Run all pending migrations.
Run {
#[clap(flatten)]
source: Source,
source: Sources,

/// List all the migrations to be run without applying
#[clap(long)]
Expand All @@ -177,7 +177,7 @@ pub enum MigrateCommand {
/// Revert the latest migration with a down file.
Revert {
#[clap(flatten)]
source: Source,
source: Sources,

/// List the migration to be reverted without applying
#[clap(long)]
Expand All @@ -199,7 +199,7 @@ pub enum MigrateCommand {
/// List all available migrations.
Info {
#[clap(flatten)]
source: Source,
source: Sources,

#[clap(flatten)]
connect_opts: ConnectOpts,
Expand All @@ -210,7 +210,7 @@ pub enum MigrateCommand {
/// Must be run in a Cargo project root.
BuildScript {
#[clap(flatten)]
source: Source,
source: Sources,

/// Overwrite the build script if it already exists.
#[clap(long)]
Expand All @@ -234,6 +234,22 @@ impl Deref for Source {
}
}

/// Argument for the migration scripts sources.
#[derive(Args, Debug)]
pub struct Sources {
/// Paths to folders containing migrations.
#[clap(long, default_values_t = vec!["migrations".to_owned()])]
source: Vec<String>,
}

impl Deref for Sources {
type Target = Vec<String>;

fn deref(&self) -> &Self::Target {
&self.source
}
}

/// Argument for the database URL.
#[derive(Args, Debug)]
pub struct ConnectOpts {
Expand Down
19 changes: 19 additions & 0 deletions sqlx-core/src/migrate/source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::error::BoxDynError;
use crate::migrate::{Migration, MigrationType};
use futures_core::future::BoxFuture;

use futures_util::future;
use std::borrow::Cow;
use std::fmt::Debug;
use std::fs;
Expand Down Expand Up @@ -44,6 +45,24 @@ impl MigrationSource<'static> for PathBuf {
}
}

impl<'s, S: MigrationSource<'s> + Send + 's> MigrationSource<'s> for Vec<S> {
fn resolve(self) -> BoxFuture<'s, Result<Vec<Migration>, BoxDynError>> {
Box::pin(async move {
let migration_sets: Vec<_> =
future::join_all(self.into_iter().map(MigrationSource::resolve))
.await
.into_iter()
.collect::<Result<_, _>>()?;

// Merge migration sets by version in ascending order
let mut migrations: Vec<_> = migration_sets.into_iter().flatten().collect();
migrations.sort_by_key(|migration| migration.version);

Ok(migrations)
})
}
}

#[derive(thiserror::Error, Debug)]
#[error("{message}")]
pub struct ResolveError {
Expand Down

0 comments on commit 6354fa4

Please sign in to comment.