Skip to content

Commit 317fb36

Browse files
authored
Add migrate & unmigrate core helpers (#250)
1 parent b2dd985 commit 317fb36

File tree

9 files changed

+76
-65
lines changed

9 files changed

+76
-65
lines changed

.github/workflows/ci.yml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,13 +102,18 @@ jobs:
102102
run: cd butane_codegen && cargo +stable test --all-features
103103
- name: Test CLI
104104
run: cd butane_cli && cargo +stable test --all-features
105-
- name: Run example cli tests
106-
run: cd example && cargo +stable test --all-features
107105
- name: Test
108106
run: cd butane && cargo +stable test --all-features
109-
- name: Check example migrations
107+
- name: Check example migrations have been updated
110108
run: |
111109
set -ex
112110
make regenerate-example-migrations
113111
git add -A
114112
git diff --exit-code
113+
- name: Run tests in examples
114+
run: |
115+
cargo +stable test -p example --all-features
116+
cd examples
117+
for dir in *; do
118+
cargo +stable test -p $dir --all-features
119+
done

butane/tests/migration-tests.rs

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
use butane::migrations::{
2-
adb::DeferredSqlType, adb::TypeIdentifier, adb::TypeKey, MemMigrations, Migration,
3-
MigrationMut, Migrations, MigrationsMut,
4-
};
5-
use butane::{db::Connection, prelude::*, SqlType, SqlVal};
61
use butane_core::codegen::{butane_type_with_migrations, model_with_migrations};
2+
use butane_core::db::{BackendConnection, Connection};
3+
use butane_core::migrations::adb::{DeferredSqlType, TypeIdentifier, TypeKey};
4+
use butane_core::migrations::{MemMigrations, Migration, MigrationMut, Migrations, MigrationsMut};
5+
use butane_core::{SqlType, SqlVal};
76
#[cfg(feature = "pg")]
87
use butane_test_helper::pg_connection;
98
#[cfg(feature = "sqlite")]
@@ -343,18 +342,21 @@ fn test_migrate(
343342
.create_migration(&backends, "v2", ms.latest().as_ref())
344343
.unwrap());
345344

346-
let mut to_apply = ms.unapplied_migrations(conn).unwrap();
345+
let to_apply = ms.unapplied_migrations(conn).unwrap();
347346
assert_eq!(to_apply.len(), 2);
348-
for m in &to_apply {
349-
m.apply(conn).unwrap();
350-
}
347+
348+
ms.migrate(conn).unwrap();
349+
350+
let to_apply = ms.unapplied_migrations(conn).unwrap();
351+
assert_eq!(to_apply.len(), 0);
352+
351353
verify_sql(conn, &ms, expected_up_sql, expected_down_sql);
352354

353355
// Now downgrade, just to make sure we can
354-
to_apply.reverse();
355-
for m in to_apply {
356-
m.downgrade(conn).unwrap();
357-
}
356+
ms.unmigrate(conn).unwrap();
357+
358+
let to_apply = ms.unapplied_migrations(conn).unwrap();
359+
assert_eq!(to_apply.len(), 2);
358360
}
359361

360362
fn verify_sql(
@@ -559,16 +561,19 @@ fn migration_delete_table(conn: &mut Connection, expected_up_sql: &str, expected
559561
.create_migration(&backends, "v2", ms.latest().as_ref())
560562
.unwrap());
561563

562-
let mut to_apply = ms.unapplied_migrations(conn).unwrap();
564+
let to_apply = ms.unapplied_migrations(conn).unwrap();
563565
assert_eq!(to_apply.len(), 2);
564-
for m in &to_apply {
565-
m.apply(conn).unwrap();
566-
}
566+
567+
ms.migrate(conn).unwrap();
568+
569+
let to_apply = ms.unapplied_migrations(conn).unwrap();
570+
assert_eq!(to_apply.len(), 0);
571+
567572
verify_sql(conn, &ms, expected_up_sql, expected_down_sql);
568573

569574
// Now downgrade, just to make sure we can
570-
to_apply.reverse();
571-
for m in to_apply {
572-
m.downgrade(conn).unwrap();
573-
}
575+
ms.unmigrate(conn).unwrap();
576+
577+
let to_apply = ms.unapplied_migrations(conn).unwrap();
578+
assert_eq!(to_apply.len(), 2);
574579
}

butane_core/src/migrations/mod.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::path::Path;
88
use fallible_iterator::FallibleIterator;
99
use nonempty::NonEmpty;
1010

11-
use crate::db::BackendRows;
11+
use crate::db::{BackendConnection, BackendRows};
1212
use crate::db::{Column, ConnectionMethods};
1313
use crate::sqlval::{FromSql, SqlValRef, ToSql};
1414
use crate::{db, query, DataObject, DataResult, Error, PrimaryKeyType, Result, SqlType};
@@ -109,6 +109,34 @@ pub trait Migrations {
109109
}
110110
Ok(None)
111111
}
112+
113+
/// Migrate connection forward.
114+
fn migrate(&self, connection: &mut impl BackendConnection) -> Result<()> {
115+
let to_apply = self.unapplied_migrations(connection)?;
116+
for migration in &to_apply {
117+
crate::info!("Applying migration {}", migration.name());
118+
migration.apply(connection)?;
119+
}
120+
Ok(())
121+
}
122+
123+
/// Remove all applied migrations.
124+
fn unmigrate(&self, connection: &mut impl BackendConnection) -> Result<()> {
125+
let mut migration = match self.last_applied_migration(connection)? {
126+
Some(migration) => migration,
127+
None => return Ok(()),
128+
};
129+
migration.downgrade(connection)?;
130+
131+
while let Ok(Some(migration_name)) = migration.migration_from() {
132+
migration = self
133+
.get_migration(&migration_name)
134+
.ok_or(Error::MigrationError("Migration not in chain".to_string()))?;
135+
crate::info!("Rolling back migration {}", migration.name());
136+
migration.downgrade(connection)?;
137+
}
138+
Ok(())
139+
}
112140
}
113141

114142
/// Extension of [`Migrations`] to modify the series of migrations.

butane_test_helper/src/lib.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -209,11 +209,7 @@ pub fn setup_db(backend: Box<dyn Backend>, conn: &mut Connection, migrate: bool)
209209
"expected to create migration"
210210
);
211211
log::info!("created current migration");
212-
let to_apply = mem_migrations.unapplied_migrations(conn).unwrap();
213-
for m in to_apply {
214-
log::info!("Applying migration {}", m.name());
215-
m.apply(conn).unwrap();
216-
}
212+
mem_migrations.migrate(conn).unwrap();
217213
}
218214

219215
/// Create a sqlite [`Connection`].

docs/getting-started.md

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -505,14 +505,11 @@ to use these migrations:
505505

506506
``` rust
507507
pub fn establish_connection() -> Connection {
508-
use butane::migrations::{Migration, Migrations};
508+
use butane::migrations::Migrations;
509509

510510
let mut connection = butane::db::connect(&ConnectionSpec::load(".butane/connection.json").unwrap()).unwrap();
511511
let migrations = butane_migrations::get_migrations().unwrap();
512-
let to_apply = migrations.unapplied_migrations(&connection).unwrap();
513-
for migration in to_apply {
514-
migration.apply(&mut connection).unwrap();
515-
}
512+
migrations.migrate(&mut connection).unwrap();
516513
connection
517514
}
518515
```

examples/getting_started/src/lib.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ pub mod butane_migrations;
66
pub mod models;
77

88
use butane::db::{Connection, ConnectionSpec};
9-
use butane::migrations::{Migration, Migrations};
9+
use butane::migrations::Migrations;
1010
use butane::prelude::*;
1111
use models::{Blog, Post};
1212

@@ -15,10 +15,7 @@ pub fn establish_connection() -> Connection {
1515
let mut connection =
1616
butane::db::connect(&ConnectionSpec::load(".butane/connection.json").unwrap()).unwrap();
1717
let migrations = butane_migrations::get_migrations().unwrap();
18-
let to_apply = migrations.unapplied_migrations(&connection).unwrap();
19-
for migration in to_apply {
20-
migration.apply(&mut connection).unwrap();
21-
}
18+
migrations.migrate(&mut connection).unwrap();
2219
connection
2320
}
2421

examples/getting_started/tests/rollback.rs

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use butane::db::{BackendConnection, Connection};
2-
use butane::migrations::{Migration, Migrations};
2+
use butane::migrations::Migrations;
33
use butane::DataObject;
44
use butane_test_helper::*;
55

@@ -38,22 +38,12 @@ fn migrate_and_rollback(mut connection: Connection) {
3838
// Migrate forward.
3939
let base_dir = std::path::PathBuf::from(".butane");
4040
let migrations = butane_cli::get_migrations(&base_dir).unwrap();
41-
let to_apply = migrations.unapplied_migrations(&connection).unwrap();
42-
for migration in &to_apply {
43-
migration
44-
.apply(&mut connection)
45-
.unwrap_or_else(|err| panic!("migration {} failed: {err}", migration.name()));
46-
eprintln!("Applied {}", migration.name());
47-
}
41+
42+
migrations.migrate(&mut connection).unwrap();
4843

4944
insert_data(&connection);
5045

5146
// Rollback migrations.
52-
for migration in to_apply.iter().rev() {
53-
migration
54-
.downgrade(&mut connection)
55-
.unwrap_or_else(|err| panic!("rollback of {} failed: {err}", migration.name()));
56-
eprintln!("Rolled back {}", migration.name());
57-
}
47+
migrations.unmigrate(&mut connection).unwrap();
5848
}
5949
testall_no_migrate!(migrate_and_rollback);

examples/newtype/src/lib.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ pub mod butane_migrations;
66
pub mod models;
77

88
use butane::db::{Connection, ConnectionSpec};
9-
use butane::migrations::{Migration, Migrations};
9+
use butane::migrations::Migrations;
1010
use butane::prelude::*;
1111
use models::{Blog, Post};
1212

@@ -15,10 +15,7 @@ pub fn establish_connection() -> Connection {
1515
let mut connection =
1616
butane::db::connect(&ConnectionSpec::load(".butane/connection.json").unwrap()).unwrap();
1717
let migrations = butane_migrations::get_migrations().unwrap();
18-
let to_apply = migrations.unapplied_migrations(&connection).unwrap();
19-
for migration in to_apply {
20-
migration.apply(&mut connection).unwrap();
21-
}
18+
migrations.migrate(&mut connection).unwrap();
2219
connection
2320
}
2421

examples/newtype/tests/rollback.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,8 @@ fn migrate_and_rollback(mut connection: Connection) {
3232
let base_dir = std::path::PathBuf::from(".butane");
3333
let migrations = butane_cli::get_migrations(&base_dir).unwrap();
3434
let to_apply = migrations.unapplied_migrations(&connection).unwrap();
35-
for migration in &to_apply {
36-
migration
37-
.apply(&mut connection)
38-
.unwrap_or_else(|err| panic!("migration {} failed: {err}", migration.name()));
39-
eprintln!("Applied {}", migration.name());
40-
}
35+
36+
migrations.migrate(&mut connection).unwrap();
4137

4238
insert_data(&connection);
4339

0 commit comments

Comments
 (0)