Skip to content

Commit 45c0b85

Browse files
committed
feat: teach sqlx-cli about migrate.table-name
1 parent 1ff6a8a commit 45c0b85

File tree

10 files changed

+172
-151
lines changed

10 files changed

+172
-151
lines changed

sqlx-cli/src/migrate.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -130,10 +130,10 @@ pub async fn info(config: &Config, migration_source: &MigrationSourceOpt, connec
130130
let migrator = Migrator::new(ResolveWith(Path::new(source), config.migrate.to_resolve_config())).await?;
131131
let mut conn = crate::connect(connect_opts).await?;
132132

133-
conn.ensure_migrations_table().await?;
133+
conn.ensure_migrations_table(config.migrate.table_name()).await?;
134134

135135
let applied_migrations: HashMap<_, _> = conn
136-
.list_applied_migrations()
136+
.list_applied_migrations(config.migrate.table_name())
137137
.await?
138138
.into_iter()
139139
.map(|m| (m.version, m))
@@ -224,14 +224,14 @@ pub async fn run(
224224

225225
let mut conn = crate::connect(connect_opts).await?;
226226

227-
conn.ensure_migrations_table().await?;
227+
conn.ensure_migrations_table(config.migrate.table_name()).await?;
228228

229-
let version = conn.dirty_version().await?;
229+
let version = conn.dirty_version(config.migrate.table_name()).await?;
230230
if let Some(version) = version {
231231
bail!(MigrateError::Dirty(version));
232232
}
233233

234-
let applied_migrations = conn.list_applied_migrations().await?;
234+
let applied_migrations = conn.list_applied_migrations(config.migrate.table_name()).await?;
235235
validate_applied_migrations(&applied_migrations, &migrator, ignore_missing)?;
236236

237237
let latest_version = applied_migrations
@@ -269,7 +269,7 @@ pub async fn run(
269269
let elapsed = if dry_run || skip {
270270
Duration::new(0, 0)
271271
} else {
272-
conn.apply(migration).await?
272+
conn.apply(config.migrate.table_name(), migration).await?
273273
};
274274
let text = if skip {
275275
"Skipped"
@@ -319,14 +319,14 @@ pub async fn revert(
319319

320320
let mut conn = crate::connect(connect_opts).await?;
321321

322-
conn.ensure_migrations_table().await?;
322+
conn.ensure_migrations_table(config.migrate.table_name()).await?;
323323

324-
let version = conn.dirty_version().await?;
324+
let version = conn.dirty_version(config.migrate.table_name()).await?;
325325
if let Some(version) = version {
326326
bail!(MigrateError::Dirty(version));
327327
}
328328

329-
let applied_migrations = conn.list_applied_migrations().await?;
329+
let applied_migrations = conn.list_applied_migrations(config.migrate.table_name()).await?;
330330
validate_applied_migrations(&applied_migrations, &migrator, ignore_missing)?;
331331

332332
let latest_version = applied_migrations
@@ -360,7 +360,7 @@ pub async fn revert(
360360
let elapsed = if dry_run || skip {
361361
Duration::new(0, 0)
362362
} else {
363-
conn.revert(migration).await?
363+
conn.revert(config.migrate.table_name(), migration).await?
364364
};
365365
let text = if skip {
366366
"Skipped"

sqlx-cli/tests/common/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ use std::{
66
fs::remove_file,
77
path::{Path, PathBuf},
88
};
9+
use sqlx::_unstable::config::Config;
910

1011
pub struct TestDatabase {
1112
file_path: PathBuf,
1213
migrations: String,
14+
config: &'static Config,
1315
}
1416

1517
impl TestDatabase {
@@ -19,6 +21,7 @@ impl TestDatabase {
1921
let ret = Self {
2022
file_path,
2123
migrations: String::from(migrations_path.to_str().unwrap()),
24+
config: Config::from_crate(),
2225
};
2326
Command::cargo_bin("cargo-sqlx")
2427
.unwrap()
@@ -77,7 +80,7 @@ impl TestDatabase {
7780
let mut conn = SqliteConnection::connect(&self.connection_string())
7881
.await
7982
.unwrap();
80-
conn.list_applied_migrations()
83+
conn.list_applied_migrations(self.config.migrate.table_name())
8184
.await
8285
.unwrap()
8386
.iter()

sqlx-core/src/any/migrate.rs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,16 @@ impl MigrateDatabase for Any {
4444
}
4545

4646
impl Migrate for AnyConnection {
47-
fn ensure_migrations_table(&mut self) -> BoxFuture<'_, Result<(), MigrateError>> {
48-
Box::pin(async { self.get_migrate()?.ensure_migrations_table().await })
47+
fn ensure_migrations_table<'e>(&'e mut self, table_name: &'e str) -> BoxFuture<'e, Result<(), MigrateError>> {
48+
Box::pin(async { self.get_migrate()?.ensure_migrations_table(table_name).await })
4949
}
5050

51-
fn dirty_version(&mut self) -> BoxFuture<'_, Result<Option<i64>, MigrateError>> {
52-
Box::pin(async { self.get_migrate()?.dirty_version().await })
51+
fn dirty_version<'e>(&'e mut self, table_name: &'e str) -> BoxFuture<'e, Result<Option<i64>, MigrateError>> {
52+
Box::pin(async { self.get_migrate()?.dirty_version(table_name).await })
5353
}
5454

55-
fn list_applied_migrations(
56-
&mut self,
57-
) -> BoxFuture<'_, Result<Vec<AppliedMigration>, MigrateError>> {
58-
Box::pin(async { self.get_migrate()?.list_applied_migrations().await })
55+
fn list_applied_migrations<'e>(&'e mut self, table_name: &'e str) -> BoxFuture<'e, Result<Vec<AppliedMigration>, MigrateError>> {
56+
Box::pin(async { self.get_migrate()?.list_applied_migrations(table_name).await })
5957
}
6058

6159
fn lock(&mut self) -> BoxFuture<'_, Result<(), MigrateError>> {
@@ -66,17 +64,19 @@ impl Migrate for AnyConnection {
6664
Box::pin(async { self.get_migrate()?.unlock().await })
6765
}
6866

69-
fn apply<'e: 'm, 'm>(
67+
fn apply<'e>(
7068
&'e mut self,
71-
migration: &'m Migration,
72-
) -> BoxFuture<'m, Result<Duration, MigrateError>> {
73-
Box::pin(async { self.get_migrate()?.apply(migration).await })
69+
table_name: &'e str,
70+
migration: &'e Migration,
71+
) -> BoxFuture<'e, Result<Duration, MigrateError>> {
72+
Box::pin(async { self.get_migrate()?.apply(table_name, migration).await })
7473
}
7574

76-
fn revert<'e: 'm, 'm>(
75+
fn revert<'e>(
7776
&'e mut self,
78-
migration: &'m Migration,
79-
) -> BoxFuture<'m, Result<Duration, MigrateError>> {
80-
Box::pin(async { self.get_migrate()?.revert(migration).await })
77+
table_name: &'e str,
78+
migration: &'e Migration,
79+
) -> BoxFuture<'e, Result<Duration, MigrateError>> {
80+
Box::pin(async { self.get_migrate()?.revert(table_name, migration).await })
8181
}
8282
}

sqlx-core/src/config/migrate.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,10 @@ impl Config {
186186
self.migrations_dir.as_deref().unwrap_or("migrations")
187187
}
188188

189+
pub fn table_name(&self) -> &str {
190+
self.table_name.as_deref().unwrap_or("_sqlx_migrations")
191+
}
192+
189193
pub fn to_resolve_config(&self) -> crate::migrate::ResolveConfig {
190194
let mut config = crate::migrate::ResolveConfig::new();
191195
config.ignore_chars(self.ignored_chars.iter().copied());

sqlx-core/src/migrate/migrate.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,14 @@ pub trait MigrateDatabase {
2727
pub trait Migrate {
2828
// ensure migrations table exists
2929
// will create or migrate it if needed
30-
fn ensure_migrations_table(&mut self) -> BoxFuture<'_, Result<(), MigrateError>>;
30+
fn ensure_migrations_table<'e>(&'e mut self, table_name: &'e str) -> BoxFuture<'e, Result<(), MigrateError>>;
3131

3232
// Return the version on which the database is dirty or None otherwise.
3333
// "dirty" means there is a partially applied migration that failed.
34-
fn dirty_version(&mut self) -> BoxFuture<'_, Result<Option<i64>, MigrateError>>;
34+
fn dirty_version<'e>(&'e mut self, table_name: &'e str) -> BoxFuture<'e, Result<Option<i64>, MigrateError>>;
3535

3636
// Return the ordered list of applied migrations
37-
fn list_applied_migrations(
38-
&mut self,
39-
) -> BoxFuture<'_, Result<Vec<AppliedMigration>, MigrateError>>;
37+
fn list_applied_migrations<'e>(&'e mut self, table_name: &'e str) -> BoxFuture<'e, Result<Vec<AppliedMigration>, MigrateError>>;
4038

4139
// Should acquire a database lock so that only one migration process
4240
// can run at a time. [`Migrate`] will call this function before applying
@@ -50,16 +48,18 @@ pub trait Migrate {
5048
// run SQL from migration in a DDL transaction
5149
// insert new row to [_migrations] table on completion (success or failure)
5250
// returns the time taking to run the migration SQL
53-
fn apply<'e: 'm, 'm>(
51+
fn apply<'e>(
5452
&'e mut self,
55-
migration: &'m Migration,
56-
) -> BoxFuture<'m, Result<Duration, MigrateError>>;
53+
table_name: &'e str,
54+
migration: &'e Migration,
55+
) -> BoxFuture<'e, Result<Duration, MigrateError>>;
5756

5857
// run a revert SQL from migration in a DDL transaction
5958
// deletes the row in [_migrations] table with specified migration version on completion (success or failure)
6059
// returns the time taking to run the migration SQL
61-
fn revert<'e: 'm, 'm>(
60+
fn revert<'e>(
6261
&'e mut self,
63-
migration: &'m Migration,
64-
) -> BoxFuture<'m, Result<Duration, MigrateError>>;
62+
table_name: &'e str,
63+
migration: &'e Migration,
64+
) -> BoxFuture<'e, Result<Duration, MigrateError>>;
6565
}

sqlx-core/src/migrate/migrator.rs

Lines changed: 43 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -27,25 +27,6 @@ pub struct Migrator {
2727
pub table_name: Cow<'static, str>,
2828
}
2929

30-
fn validate_applied_migrations(
31-
applied_migrations: &[AppliedMigration],
32-
migrator: &Migrator,
33-
) -> Result<(), MigrateError> {
34-
if migrator.ignore_missing {
35-
return Ok(());
36-
}
37-
38-
let migrations: HashSet<_> = migrator.iter().map(|m| m.version).collect();
39-
40-
for applied_migration in applied_migrations {
41-
if !migrations.contains(&applied_migration.version) {
42-
return Err(MigrateError::VersionMissing(applied_migration.version));
43-
}
44-
}
45-
46-
Ok(())
47-
}
48-
4930
impl Migrator {
5031
#[doc(hidden)]
5132
pub const DEFAULT: Migrator = Migrator {
@@ -156,12 +137,21 @@ impl Migrator {
156137
<A::Connection as Deref>::Target: Migrate,
157138
{
158139
let mut conn = migrator.acquire().await?;
159-
self.run_direct(&mut *conn).await
140+
self.run_direct(None, &mut *conn).await
141+
}
142+
143+
pub async fn run_to<'a, A>(&self, target: i64, migrator: A) -> Result<(), MigrateError>
144+
where
145+
A: Acquire<'a>,
146+
<A::Connection as Deref>::Target: Migrate,
147+
{
148+
let mut conn = migrator.acquire().await?;
149+
self.run_direct(Some(target), &mut *conn).await
160150
}
161151

162152
// Getting around the annoying "implementation of `Acquire` is not general enough" error
163153
#[doc(hidden)]
164-
pub async fn run_direct<C>(&self, conn: &mut C) -> Result<(), MigrateError>
154+
pub async fn run_direct<C>(&self, target: Option<i64>, conn: &mut C) -> Result<(), MigrateError>
165155
where
166156
C: Migrate,
167157
{
@@ -172,14 +162,14 @@ impl Migrator {
172162

173163
// creates [_migrations] table only if needed
174164
// eventually this will likely migrate previous versions of the table
175-
conn.ensure_migrations_table().await?;
165+
conn.ensure_migrations_table(&self.table_name).await?;
176166

177-
let version = conn.dirty_version().await?;
167+
let version = conn.dirty_version(&self.table_name).await?;
178168
if let Some(version) = version {
179169
return Err(MigrateError::Dirty(version));
180170
}
181171

182-
let applied_migrations = conn.list_applied_migrations().await?;
172+
let applied_migrations = conn.list_applied_migrations(&self.table_name).await?;
183173
validate_applied_migrations(&applied_migrations, self)?;
184174

185175
let applied_migrations: HashMap<_, _> = applied_migrations
@@ -188,6 +178,11 @@ impl Migrator {
188178
.collect();
189179

190180
for migration in self.iter() {
181+
if target.is_some_and(|target| target < migration.version) {
182+
// Target version reached
183+
break;
184+
}
185+
191186
if migration.migration_type.is_down_migration() {
192187
continue;
193188
}
@@ -199,7 +194,7 @@ impl Migrator {
199194
}
200195
}
201196
None => {
202-
conn.apply(migration).await?;
197+
conn.apply(&self.table_name, migration).await?;
203198
}
204199
}
205200
}
@@ -244,14 +239,14 @@ impl Migrator {
244239

245240
// creates [_migrations] table only if needed
246241
// eventually this will likely migrate previous versions of the table
247-
conn.ensure_migrations_table().await?;
242+
conn.ensure_migrations_table(&self.table_name).await?;
248243

249-
let version = conn.dirty_version().await?;
244+
let version = conn.dirty_version(&self.table_name).await?;
250245
if let Some(version) = version {
251246
return Err(MigrateError::Dirty(version));
252247
}
253248

254-
let applied_migrations = conn.list_applied_migrations().await?;
249+
let applied_migrations = conn.list_applied_migrations(&self.table_name).await?;
255250
validate_applied_migrations(&applied_migrations, self)?;
256251

257252
let applied_migrations: HashMap<_, _> = applied_migrations
@@ -266,7 +261,7 @@ impl Migrator {
266261
.filter(|m| applied_migrations.contains_key(&m.version))
267262
.filter(|m| m.version > target)
268263
{
269-
conn.revert(migration).await?;
264+
conn.revert(&self.table_name, migration).await?;
270265
}
271266

272267
// unlock the migrator to allow other migrators to run
@@ -278,3 +273,22 @@ impl Migrator {
278273
Ok(())
279274
}
280275
}
276+
277+
fn validate_applied_migrations(
278+
applied_migrations: &[AppliedMigration],
279+
migrator: &Migrator,
280+
) -> Result<(), MigrateError> {
281+
if migrator.ignore_missing {
282+
return Ok(());
283+
}
284+
285+
let migrations: HashSet<_> = migrator.iter().map(|m| m.version).collect();
286+
287+
for applied_migration in applied_migrations {
288+
if !migrations.contains(&applied_migration.version) {
289+
return Err(MigrateError::VersionMissing(applied_migration.version));
290+
}
291+
}
292+
293+
Ok(())
294+
}

sqlx-core/src/testing/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ async fn setup_test_db<DB: Database>(
243243

244244
if let Some(migrator) = args.migrator {
245245
migrator
246-
.run_direct(&mut conn)
246+
.run_direct(None, &mut conn)
247247
.await
248248
.expect("failed to apply migrations");
249249
}

0 commit comments

Comments
 (0)