Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add migrate & unmigrate core helpers #250

Merged
merged 5 commits into from
Apr 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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