From 6189e93c1ba8c4844803d2a7dbc1c725f21ef0b6 Mon Sep 17 00:00:00 2001 From: aoengin Date: Sun, 4 Jan 2026 13:33:38 +0300 Subject: [PATCH 1/2] feat(migration): ensure deterministic migration order by sorting ups before downs --- sqlx-core/src/migrate/migration_type.rs | 8 ++++++++ sqlx-core/src/migrate/migrator.rs | 8 ++++++-- sqlx-core/src/migrate/source.rs | 10 +++++++--- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/sqlx-core/src/migrate/migration_type.rs b/sqlx-core/src/migrate/migration_type.rs index 350ddb3f27..401e6c3555 100644 --- a/sqlx-core/src/migrate/migration_type.rs +++ b/sqlx-core/src/migrate/migration_type.rs @@ -74,6 +74,14 @@ impl MigrationType { } } + /// Ordering helper to sort ups before downs when versions tie. + pub fn direction_order(&self) -> u8 { + match self { + MigrationType::ReversibleDown => 1, + MigrationType::Simple | MigrationType::ReversibleUp => 0, + } + } + #[deprecated = "unused"] pub fn infer(migrator: &Migrator, reversible: bool) -> MigrationType { match migrator.iter().last() { diff --git a/sqlx-core/src/migrate/migrator.rs b/sqlx-core/src/migrate/migrator.rs index 53295c92d0..76eb37218a 100644 --- a/sqlx-core/src/migrate/migrator.rs +++ b/sqlx-core/src/migrate/migrator.rs @@ -87,8 +87,12 @@ impl Migrator { /// let m = Migrator::with_migrations(migrations); /// ``` pub fn with_migrations(mut migrations: Vec) -> Self { - // Ensure that we are sorted by version in ascending order. - migrations.sort_by_key(|m| m.version); + // Ensure deterministic order: version ascending, then up before down when versions match. + migrations.sort_by(|a, b| { + a.version + .cmp(&b.version) + .then_with(|| a.migration_type.direction_order().cmp(&b.migration_type.direction_order())) + }); Self { migrations: Cow::Owned(migrations), ..Self::DEFAULT diff --git a/sqlx-core/src/migrate/source.rs b/sqlx-core/src/migrate/source.rs index 4648e53f1e..f3b1bd057d 100644 --- a/sqlx-core/src/migrate/source.rs +++ b/sqlx-core/src/migrate/source.rs @@ -248,9 +248,13 @@ pub fn resolve_blocking_with_config( )); } - // Ensure that we are sorted by version in ascending order. - migrations.sort_by_key(|(m, _)| m.version); - + // Ensure deterministic order: version ascending, then up before down when versions match. + migrations.sort_by(|(a, _), (b, _)| { + a.version + .cmp(&b.version) + .then_with(|| a.migration_type.direction_order().cmp(&b.migration_type.direction_order())) + }); + Ok(migrations) } From d0bacfaa5012bb191a7e4150ae8dddee46bd9888 Mon Sep 17 00:00:00 2001 From: aoengin Date: Sun, 4 Jan 2026 14:56:45 +0300 Subject: [PATCH 2/2] cargo fmt --- sqlx-core/src/migrate/migrator.rs | 8 +++++--- sqlx-core/src/migrate/source.rs | 10 ++++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/sqlx-core/src/migrate/migrator.rs b/sqlx-core/src/migrate/migrator.rs index 76eb37218a..1c09ca880b 100644 --- a/sqlx-core/src/migrate/migrator.rs +++ b/sqlx-core/src/migrate/migrator.rs @@ -89,9 +89,11 @@ impl Migrator { pub fn with_migrations(mut migrations: Vec) -> Self { // Ensure deterministic order: version ascending, then up before down when versions match. migrations.sort_by(|a, b| { - a.version - .cmp(&b.version) - .then_with(|| a.migration_type.direction_order().cmp(&b.migration_type.direction_order())) + a.version.cmp(&b.version).then_with(|| { + a.migration_type + .direction_order() + .cmp(&b.migration_type.direction_order()) + }) }); Self { migrations: Cow::Owned(migrations), diff --git a/sqlx-core/src/migrate/source.rs b/sqlx-core/src/migrate/source.rs index f3b1bd057d..9eb99e18fd 100644 --- a/sqlx-core/src/migrate/source.rs +++ b/sqlx-core/src/migrate/source.rs @@ -250,11 +250,13 @@ pub fn resolve_blocking_with_config( // Ensure deterministic order: version ascending, then up before down when versions match. migrations.sort_by(|(a, _), (b, _)| { - a.version - .cmp(&b.version) - .then_with(|| a.migration_type.direction_order().cmp(&b.migration_type.direction_order())) + a.version.cmp(&b.version).then_with(|| { + a.migration_type + .direction_order() + .cmp(&b.migration_type.direction_order()) + }) }); - + Ok(migrations) }