Add remove_index action

This commit is contained in:
fabianlindfors 2022-01-12 01:12:08 +01:00
parent 8e08941007
commit 480bcf8af1
4 changed files with 176 additions and 0 deletions

View File

@ -26,6 +26,7 @@ Reshape is designed for Postgres 12 and later.
- [Remove column](#remove-column)
- [Indices](#indices)
- [Add index](#add-index)
- [Remove index](#remove-index)
- [Commands and options](#commands-and-options)
- [`reshape migrate`](#reshape-migrate)
- [`reshape complete`](#reshape-complete)
@ -391,6 +392,18 @@ name = "name_idx"
columns = ["name"]
```
#### Remove index
The `remove_index` action will remove an existing index. The index won't actually be removed until the migration is completed.
*Example: remove the `name_idx` index*
```toml
[[actions]]
type = "remove_index"
index = "name_idx"
```
## Commands and options
### `reshape migrate`

View File

@ -24,6 +24,9 @@ pub use remove_column::RemoveColumn;
mod add_index;
pub use add_index::AddIndex;
mod remove_index;
pub use remove_index::RemoveIndex;
mod remove_table;
pub use remove_table::RemoveTable;

View File

@ -0,0 +1,51 @@
use super::{Action, MigrationContext};
use crate::{
db::{Conn, Transaction},
schema::Schema,
};
use anyhow::Context;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
pub struct RemoveIndex {
pub index: String,
}
#[typetag::serde(name = "remove_index")]
impl Action for RemoveIndex {
fn describe(&self) -> String {
format!("Removing index \"{}\"", self.index)
}
fn run(
&self,
_ctx: &MigrationContext,
_db: &mut dyn Conn,
_schema: &Schema,
) -> anyhow::Result<()> {
// Do nothing, the index isn't removed until completion
Ok(())
}
fn complete<'a>(
&self,
_ctx: &MigrationContext,
db: &'a mut dyn Conn,
) -> anyhow::Result<Option<Transaction<'a>>> {
db.run(&format!(
"
DROP INDEX CONCURRENTLY IF EXISTS {}
",
self.index
))
.context("failed to drop index")?;
Ok(None)
}
fn update_schema(&self, _ctx: &MigrationContext, _schema: &mut Schema) {}
fn abort(&self, _ctx: &MigrationContext, _db: &mut dyn Conn) -> anyhow::Result<()> {
Ok(())
}
}

109
tests/remove_index.rs Normal file
View File

@ -0,0 +1,109 @@
use reshape::migrations::{AddIndex, ColumnBuilder, CreateTableBuilder, Migration, RemoveIndex};
mod common;
#[test]
fn remove_index() {
let (mut reshape, _, mut db) = common::setup();
let create_table_migration = Migration::new("create_user_table", None)
.with_action(
CreateTableBuilder::default()
.name("users")
.primary_key(vec!["id".to_string()])
.columns(vec![
ColumnBuilder::default()
.name("id")
.data_type("INTEGER")
.build()
.unwrap(),
ColumnBuilder::default()
.name("name")
.data_type("TEXT")
.build()
.unwrap(),
])
.build()
.unwrap(),
)
.with_action(AddIndex {
table: "users".to_string(),
name: "name_idx".to_string(),
columns: vec!["name".to_string()],
});
let remove_index_migration =
Migration::new("remove_name_index", None).with_action(RemoveIndex {
index: "name_idx".to_string(),
});
let first_migrations = vec![create_table_migration.clone()];
let second_migrations = vec![
create_table_migration.clone(),
remove_index_migration.clone(),
];
// Run migrations
reshape.migrate(first_migrations.clone()).unwrap();
// Ensure index is valid and ready
let result: Vec<(bool, bool)> = db
.query(
"
SELECT pg_index.indisready, pg_index.indisvalid
FROM pg_catalog.pg_index
JOIN pg_catalog.pg_class ON pg_index.indexrelid = pg_class.oid
WHERE pg_class.relname = 'name_idx'
",
&[],
)
.unwrap()
.iter()
.map(|row| (row.get("indisready"), row.get("indisvalid")))
.collect();
assert_eq!(vec![(true, true)], result);
// Run migration to remove index
reshape.migrate(second_migrations.clone()).unwrap();
// Ensure index is still valid and ready during the migration
let result: Vec<(bool, bool)> = db
.query(
"
SELECT pg_index.indisready, pg_index.indisvalid
FROM pg_catalog.pg_index
JOIN pg_catalog.pg_class ON pg_index.indexrelid = pg_class.oid
WHERE pg_class.relname = 'name_idx'
",
&[],
)
.unwrap()
.iter()
.map(|row| (row.get("indisready"), row.get("indisvalid")))
.collect();
assert_eq!(vec![(true, true)], result);
reshape.complete_migration().unwrap();
// Ensure index has been removed after the migration is complete
let count: i64 = db
.query(
"
SELECT COUNT(*)
FROM pg_catalog.pg_index
JOIN pg_catalog.pg_class ON pg_index.indexrelid = pg_class.oid
WHERE pg_class.relname = 'name_idx'
",
&[],
)
.unwrap()
.first()
.map(|row| row.get(0))
.unwrap();
assert_eq!(0, count, "expected index to not exist");
common::assert_cleaned_up(&mut db);
}