Skip to content

Commit

Permalink
Add migrate & unmigrate core helpers (#250)
Browse files Browse the repository at this point in the history
  • Loading branch information
jayvdb authored Apr 20, 2024
1 parent b2dd985 commit 317fb36
Show file tree
Hide file tree
Showing 9 changed files with 76 additions and 65 deletions.
11 changes: 8 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,18 @@ jobs:
run: cd butane_codegen && cargo +stable test --all-features
- name: Test CLI
run: cd butane_cli && cargo +stable test --all-features
- name: Run example cli tests
run: cd example && cargo +stable test --all-features
- name: Test
run: cd butane && cargo +stable test --all-features
- name: Check example migrations
- name: Check example migrations have been updated
run: |
set -ex
make regenerate-example-migrations
git add -A
git diff --exit-code
- name: Run tests in examples
run: |
cargo +stable test -p example --all-features
cd examples
for dir in *; do
cargo +stable test -p $dir --all-features
done
47 changes: 26 additions & 21 deletions butane/tests/migration-tests.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
use butane::migrations::{
adb::DeferredSqlType, adb::TypeIdentifier, adb::TypeKey, MemMigrations, Migration,
MigrationMut, Migrations, MigrationsMut,
};
use butane::{db::Connection, prelude::*, SqlType, SqlVal};
use butane_core::codegen::{butane_type_with_migrations, model_with_migrations};
use butane_core::db::{BackendConnection, Connection};
use butane_core::migrations::adb::{DeferredSqlType, TypeIdentifier, TypeKey};
use butane_core::migrations::{MemMigrations, Migration, MigrationMut, Migrations, MigrationsMut};
use butane_core::{SqlType, SqlVal};
#[cfg(feature = "pg")]
use butane_test_helper::pg_connection;
#[cfg(feature = "sqlite")]
Expand Down Expand Up @@ -343,18 +342,21 @@ fn test_migrate(
.create_migration(&backends, "v2", ms.latest().as_ref())
.unwrap());

let mut to_apply = ms.unapplied_migrations(conn).unwrap();
let to_apply = ms.unapplied_migrations(conn).unwrap();
assert_eq!(to_apply.len(), 2);
for m in &to_apply {
m.apply(conn).unwrap();
}

ms.migrate(conn).unwrap();

let to_apply = ms.unapplied_migrations(conn).unwrap();
assert_eq!(to_apply.len(), 0);

verify_sql(conn, &ms, expected_up_sql, expected_down_sql);

// Now downgrade, just to make sure we can
to_apply.reverse();
for m in to_apply {
m.downgrade(conn).unwrap();
}
ms.unmigrate(conn).unwrap();

let to_apply = ms.unapplied_migrations(conn).unwrap();
assert_eq!(to_apply.len(), 2);
}

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

let mut to_apply = ms.unapplied_migrations(conn).unwrap();
let to_apply = ms.unapplied_migrations(conn).unwrap();
assert_eq!(to_apply.len(), 2);
for m in &to_apply {
m.apply(conn).unwrap();
}

ms.migrate(conn).unwrap();

let to_apply = ms.unapplied_migrations(conn).unwrap();
assert_eq!(to_apply.len(), 0);

verify_sql(conn, &ms, expected_up_sql, expected_down_sql);

// Now downgrade, just to make sure we can
to_apply.reverse();
for m in to_apply {
m.downgrade(conn).unwrap();
}
ms.unmigrate(conn).unwrap();

let to_apply = ms.unapplied_migrations(conn).unwrap();
assert_eq!(to_apply.len(), 2);
}
30 changes: 29 additions & 1 deletion butane_core/src/migrations/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::path::Path;
use fallible_iterator::FallibleIterator;
use nonempty::NonEmpty;

use crate::db::BackendRows;
use crate::db::{BackendConnection, BackendRows};
use crate::db::{Column, ConnectionMethods};
use crate::sqlval::{FromSql, SqlValRef, ToSql};
use crate::{db, query, DataObject, DataResult, Error, PrimaryKeyType, Result, SqlType};
Expand Down Expand Up @@ -109,6 +109,34 @@ pub trait Migrations {
}
Ok(None)
}

/// Migrate connection forward.
fn migrate(&self, connection: &mut impl BackendConnection) -> Result<()> {
let to_apply = self.unapplied_migrations(connection)?;
for migration in &to_apply {
crate::info!("Applying migration {}", migration.name());
migration.apply(connection)?;
}
Ok(())
}

/// Remove all applied migrations.
fn unmigrate(&self, connection: &mut impl BackendConnection) -> Result<()> {
let mut migration = match self.last_applied_migration(connection)? {
Some(migration) => migration,
None => return Ok(()),
};
migration.downgrade(connection)?;

while let Ok(Some(migration_name)) = migration.migration_from() {
migration = self
.get_migration(&migration_name)
.ok_or(Error::MigrationError("Migration not in chain".to_string()))?;
crate::info!("Rolling back migration {}", migration.name());
migration.downgrade(connection)?;
}
Ok(())
}
}

/// Extension of [`Migrations`] to modify the series of migrations.
Expand Down
6 changes: 1 addition & 5 deletions butane_test_helper/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,11 +209,7 @@ pub fn setup_db(backend: Box<dyn Backend>, conn: &mut Connection, migrate: bool)
"expected to create migration"
);
log::info!("created current migration");
let to_apply = mem_migrations.unapplied_migrations(conn).unwrap();
for m in to_apply {
log::info!("Applying migration {}", m.name());
m.apply(conn).unwrap();
}
mem_migrations.migrate(conn).unwrap();
}

/// Create a sqlite [`Connection`].
Expand Down
7 changes: 2 additions & 5 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -505,14 +505,11 @@ to use these migrations:

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

let mut connection = butane::db::connect(&ConnectionSpec::load(".butane/connection.json").unwrap()).unwrap();
let migrations = butane_migrations::get_migrations().unwrap();
let to_apply = migrations.unapplied_migrations(&connection).unwrap();
for migration in to_apply {
migration.apply(&mut connection).unwrap();
}
migrations.migrate(&mut connection).unwrap();
connection
}
```
Expand Down
7 changes: 2 additions & 5 deletions examples/getting_started/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pub mod butane_migrations;
pub mod models;

use butane::db::{Connection, ConnectionSpec};
use butane::migrations::{Migration, Migrations};
use butane::migrations::Migrations;
use butane::prelude::*;
use models::{Blog, Post};

Expand All @@ -15,10 +15,7 @@ pub fn establish_connection() -> Connection {
let mut connection =
butane::db::connect(&ConnectionSpec::load(".butane/connection.json").unwrap()).unwrap();
let migrations = butane_migrations::get_migrations().unwrap();
let to_apply = migrations.unapplied_migrations(&connection).unwrap();
for migration in to_apply {
migration.apply(&mut connection).unwrap();
}
migrations.migrate(&mut connection).unwrap();
connection
}

Expand Down
18 changes: 4 additions & 14 deletions examples/getting_started/tests/rollback.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use butane::db::{BackendConnection, Connection};
use butane::migrations::{Migration, Migrations};
use butane::migrations::Migrations;
use butane::DataObject;
use butane_test_helper::*;

Expand Down Expand Up @@ -38,22 +38,12 @@ fn migrate_and_rollback(mut connection: Connection) {
// Migrate forward.
let base_dir = std::path::PathBuf::from(".butane");
let migrations = butane_cli::get_migrations(&base_dir).unwrap();
let to_apply = migrations.unapplied_migrations(&connection).unwrap();
for migration in &to_apply {
migration
.apply(&mut connection)
.unwrap_or_else(|err| panic!("migration {} failed: {err}", migration.name()));
eprintln!("Applied {}", migration.name());
}

migrations.migrate(&mut connection).unwrap();

insert_data(&connection);

// Rollback migrations.
for migration in to_apply.iter().rev() {
migration
.downgrade(&mut connection)
.unwrap_or_else(|err| panic!("rollback of {} failed: {err}", migration.name()));
eprintln!("Rolled back {}", migration.name());
}
migrations.unmigrate(&mut connection).unwrap();
}
testall_no_migrate!(migrate_and_rollback);
7 changes: 2 additions & 5 deletions examples/newtype/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pub mod butane_migrations;
pub mod models;

use butane::db::{Connection, ConnectionSpec};
use butane::migrations::{Migration, Migrations};
use butane::migrations::Migrations;
use butane::prelude::*;
use models::{Blog, Post};

Expand All @@ -15,10 +15,7 @@ pub fn establish_connection() -> Connection {
let mut connection =
butane::db::connect(&ConnectionSpec::load(".butane/connection.json").unwrap()).unwrap();
let migrations = butane_migrations::get_migrations().unwrap();
let to_apply = migrations.unapplied_migrations(&connection).unwrap();
for migration in to_apply {
migration.apply(&mut connection).unwrap();
}
migrations.migrate(&mut connection).unwrap();
connection
}

Expand Down
8 changes: 2 additions & 6 deletions examples/newtype/tests/rollback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,8 @@ fn migrate_and_rollback(mut connection: Connection) {
let base_dir = std::path::PathBuf::from(".butane");
let migrations = butane_cli::get_migrations(&base_dir).unwrap();
let to_apply = migrations.unapplied_migrations(&connection).unwrap();
for migration in &to_apply {
migration
.apply(&mut connection)
.unwrap_or_else(|err| panic!("migration {} failed: {err}", migration.name()));
eprintln!("Applied {}", migration.name());
}

migrations.migrate(&mut connection).unwrap();

insert_data(&connection);

Expand Down

0 comments on commit 317fb36

Please sign in to comment.