Skip to content

Commit 0ffb6a9

Browse files
author
Markus Gasser
committed
Add the possibility to skip migrations
1 parent 1dd526a commit 0ffb6a9

17 files changed

Lines changed: 489 additions & 47 deletions

File tree

sqlx-cli/src/database.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,16 @@ pub async fn setup(
6262
connect_opts: &ConnectOpts,
6363
) -> anyhow::Result<()> {
6464
create(connect_opts).await?;
65-
migrate::run(config, migration_source, connect_opts, false, false, None).await
65+
migrate::run(
66+
config,
67+
migration_source,
68+
connect_opts,
69+
false,
70+
false,
71+
None,
72+
false,
73+
)
74+
.await
6675
}
6776

6877
async fn ask_to_continue_drop(db_url: String) -> bool {

sqlx-cli/src/lib.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use futures_util::TryFutureExt;
2727
use sqlx::AnyConnection;
2828
use tokio::{select, signal};
2929

30-
use crate::opt::{Command, ConnectOpts, DatabaseCommand, MigrateCommand};
30+
use crate::opt::{Command, ConnectOpts, DatabaseCommand, MigrateCommand, OverrideCommand};
3131

3232
pub mod database;
3333
pub mod metadata;
@@ -99,6 +99,7 @@ async fn do_run(opt: Opt) -> anyhow::Result<()> {
9999
dry_run,
100100
*ignore_missing,
101101
target_version,
102+
false,
102103
)
103104
.await?
104105
}
@@ -124,6 +125,30 @@ async fn do_run(opt: Opt) -> anyhow::Result<()> {
124125
)
125126
.await?
126127
}
128+
MigrateCommand::Override { command } => match command {
129+
OverrideCommand::Skip {
130+
source,
131+
config,
132+
mut connect_opts,
133+
dry_run,
134+
ignore_missing,
135+
target_version,
136+
} => {
137+
let config = config.load_config().await?;
138+
connect_opts.populate_db_url(&config)?;
139+
140+
migrate::run(
141+
&config,
142+
&source,
143+
&connect_opts,
144+
dry_run,
145+
*ignore_missing,
146+
target_version,
147+
true,
148+
)
149+
.await?
150+
}
151+
},
127152
MigrateCommand::Info {
128153
source,
129154
config,

sqlx-cli/src/migrate.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ pub async fn run(
220220
dry_run: bool,
221221
ignore_missing: bool,
222222
target_version: Option<i64>,
223+
skip: bool,
223224
) -> anyhow::Result<()> {
224225
let migrator = migration_source.resolve(config).await?;
225226

@@ -277,18 +278,23 @@ pub async fn run(
277278
}
278279
}
279280
None => {
280-
let skip =
281+
let exceeds_target =
281282
target_version.is_some_and(|target_version| migration.version > target_version);
282283

283-
let elapsed = if dry_run || skip {
284+
let elapsed = if dry_run || exceeds_target {
285+
Duration::new(0, 0)
286+
} else if skip {
287+
conn.skip(config.migrate.table_name(), migration).await?;
284288
Duration::new(0, 0)
285289
} else {
286290
conn.apply(config.migrate.table_name(), migration).await?
287291
};
288-
let text = if skip {
292+
let text = if exceeds_target {
289293
"Skipped"
290294
} else if dry_run {
291295
"Can apply"
296+
} else if skip {
297+
"Skipped on request"
292298
} else {
293299
"Applied"
294300
};

sqlx-cli/src/opt.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,12 @@ pub enum MigrateCommand {
247247
target_version: Option<i64>,
248248
},
249249

250+
/// Override migration state, potentially dangerous operations.
251+
Override {
252+
#[clap(subcommand)]
253+
command: OverrideCommand,
254+
},
255+
250256
/// Revert the latest migration with a down file.
251257
Revert {
252258
#[clap(flatten)]
@@ -300,6 +306,33 @@ pub enum MigrateCommand {
300306
},
301307
}
302308

309+
#[derive(clap::Subcommand, Debug)]
310+
pub enum OverrideCommand {
311+
/// Skip all pending migrations without running them.
312+
Skip {
313+
#[clap(flatten)]
314+
source: MigrationSourceOpt,
315+
316+
#[clap(flatten)]
317+
config: ConfigOpt,
318+
319+
#[clap(flatten)]
320+
connect_opts: ConnectOpts,
321+
322+
/// List all the migrations to be skipped without marking them as applied.
323+
#[clap(long)]
324+
dry_run: bool,
325+
326+
#[clap(flatten)]
327+
ignore_missing: IgnoreMissing,
328+
329+
/// Apply migrations up to the specified version. If unspecified, apply all
330+
/// pending migrations. If already at the target version, then no-op.
331+
#[clap(long)]
332+
target_version: Option<i64>,
333+
},
334+
}
335+
303336
#[derive(Args, Debug)]
304337
pub struct AddMigrationOpts {
305338
pub description: String,

sqlx-cli/tests/common/mod.rs

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,22 @@ pub struct TestDatabase {
1313
pub config_path: Option<PathBuf>,
1414
}
1515

16+
pub enum MigrateCommand {
17+
Run,
18+
Revert,
19+
Skip,
20+
}
21+
22+
impl AsRef<str> for MigrateCommand {
23+
fn as_ref(&self) -> &str {
24+
match self {
25+
MigrateCommand::Run => "run",
26+
MigrateCommand::Revert => "revert",
27+
MigrateCommand::Skip => "override skip",
28+
}
29+
}
30+
}
31+
1632
impl TestDatabase {
1733
pub fn new(name: &str, migrations: &str) -> Self {
1834
// Note: only set when _building_
@@ -58,19 +74,17 @@ impl TestDatabase {
5874
format!("sqlite://{}", self.file_path.display())
5975
}
6076

61-
pub fn run_migration(&self, revert: bool, version: Option<i64>, dry_run: bool) -> Assert {
77+
pub fn run_migration(
78+
&self,
79+
migrate_command: MigrateCommand,
80+
version: Option<i64>,
81+
dry_run: bool,
82+
) -> Assert {
6283
let mut command = Command::cargo_bin("sqlx").unwrap();
6384
command
64-
.args([
65-
"migrate",
66-
match revert {
67-
true => "revert",
68-
false => "run",
69-
},
70-
"--database-url",
71-
&self.connection_string(),
72-
"--source",
73-
])
85+
.arg("migrate")
86+
.args(migrate_command.as_ref().split_whitespace())
87+
.args(["--database-url", &self.connection_string(), "--source"])
7488
.arg(&self.migrations_path);
7589

7690
if let Some(config_path) = &self.config_path {

0 commit comments

Comments
 (0)