on main help sign in
Switch `State` struct into enum

With the old fields in the `State` broken out we can now make `State` a proper enum, replacing the nested `Status`. The naming with both `State` and `Status` was a bit confusing.

commit2d04d33b952f9feb8d681b5c2afa89c9aee9a51c authorfabianlindfors <fabian@flapplabs.se> dateFri 14 Jan 2022, 00:10 (5 years ago) parentb1b79e2
6 files changed+51−78
src/lib.rs+19−20 src/state.rs+31−40 tests/add_column.rs−4 tests/alter_column.rs−7 tests/create_table.rs+1−5 tests/failure.rs−2
src/lib.rs+19−20
@@ -15,7 +15,7 @@ pub mod migrations;
1515mod schema;
1616mod state;
1717
18−pub use crate::state::{State, Status};
18+pub use crate::state::State;
1919
2020pub struct Reshape {
2121 pub state: State,
@@ -46,7 +46,7 @@ impl Reshape {
4646
4747 fn new_with_config(config: &Config) -> anyhow::Result<Reshape> {
4848 let mut db = DbConn::connect(config)?;
49− let state = State::load(&mut db);
49+ let state = State::load(&mut db)?;
5050
5151 Ok(Reshape { db, state })
5252 }
@@ -55,15 +55,15 @@ impl Reshape {
5555 where
5656 T: IntoIterator<Item = Migration>,
5757 {
58− self.state = State::load(&mut self.db);
58+ self.state = State::load(&mut self.db)?;
5959
6060 // Make sure no migration is in progress
61− if let state::Status::InProgress { .. } = &self.state.status {
61+ if let State::InProgress { .. } = &self.state {
6262 println!("Migration already in progress, please complete using 'reshape complete'");
6363 return Ok(());
6464 }
6565
66− if let state::Status::Completing { .. } = &self.state.status {
66+ if let State::Completing { .. } = &self.state {
6767 println!(
6868 "Migration already in progress and has started completion, please finish using 'reshape complete'"
6969 );
@@ -83,9 +83,9 @@ impl Reshape {
8383
8484 // If we have already started applying some migrations we need to ensure that
8585 // they are the same ones we want to apply now
86− if let state::Status::Applying {
86+ if let State::Applying {
8787 migrations: existing_migrations,
88− } = &self.state.status
88+ } = &self.state
8989 {
9090 if existing_migrations != &remaining_migrations {
9191 return Err(anyhow!(
@@ -198,8 +198,8 @@ impl Reshape {
198198
199199 pub fn complete_migration(&mut self) -> anyhow::Result<()> {
200200 // Make sure a migration is in progress
201− let (remaining_migrations, starting_migration_index, starting_action_index) = match self.state.status.clone() {
202− state::Status::InProgress { migrations } => {
201+ let (remaining_migrations, starting_migration_index, starting_action_index) = match self.state.clone() {
202+ State::InProgress { migrations } => {
203203 // Move into the Completing state. Once in this state,
204204 // the migration can't be aborted and must be completed.
205205 self.state.completing(migrations.clone(), 0, 0);
@@ -207,18 +207,18 @@ impl Reshape {
207207
208208 (migrations, 0, 0)
209209 },
210− state::Status::Completing {
210+ State::Completing {
211211 migrations,
212212 current_migration_index,
213213 current_action_index
214214 } => (migrations, current_migration_index, current_action_index),
215− state::Status::Aborting { .. } => {
215+ State::Aborting { .. } => {
216216 return Err(anyhow!("migration been aborted and can't be completed. Please finish using `reshape abort`."))
217217 }
218− state::Status::Applying { .. } => {
218+ State::Applying { .. } => {
219219 return Err(anyhow!("a previous migration unexpectedly failed. Please run `reshape migrate` to try applying the migration again."))
220220 }
221− state::Status::Idle => {
221+ State::Idle => {
222222 println!("No migration in progress");
223223 return Ok(());
224224 }
@@ -396,7 +396,7 @@ impl Reshape {
396396 ))?;
397397 }
398398
399− if let Status::InProgress { migrations } = &self.state.status {
399+ if let State::InProgress { migrations } = &self.state {
400400 let target_migration = migrations.last().unwrap().name.to_string();
401401 self.db.run(&format!(
402402 "DROP SCHEMA IF EXISTS {} CASCADE",
@@ -426,10 +426,9 @@ impl Reshape {
426426 pub fn abort(&mut self) -> anyhow::Result<()> {
427427 let (remaining_migrations, last_migration_index, last_action_index) = match self
428428 .state
429− .status
430429 .clone()
431430 {
432− Status::InProgress { migrations } | Status::Applying { migrations } => {
431+ State::InProgress { migrations } | State::Applying { migrations } => {
433432 // Set to the Aborting state. Once this is done, the migration has to
434433 // be fully aborted and can't be completed.
435434 self.state.aborting(migrations.clone(), 0, 0);
@@ -437,15 +436,15 @@ impl Reshape {
437436
438437 (migrations, usize::MAX, usize::MAX)
439438 }
440− Status::Aborting {
439+ State::Aborting {
441440 migrations,
442441 last_migration_index,
443442 last_action_index,
444443 } => (migrations, last_migration_index, last_action_index),
445− Status::Completing { .. } => {
444+ State::Completing { .. } => {
446445 return Err(anyhow!("Migration completion has already been started. Please run `reshape complete` again to finish it."));
447446 }
448− Status::Idle => {
447+ State::Idle => {
449448 println!("No migration is in progress");
450449 return Ok(());
451450 }
@@ -467,7 +466,7 @@ impl Reshape {
467466
468467 helpers::tear_down_helpers(&mut self.db).context("failed to tear down helpers")?;
469468
470− self.state.status = state::Status::Idle;
469+ self.state = State::Idle;
471470 self.state
472471 .save(&mut self.db)
473472 .context("failed to save state")?;
src/state.rs+31−40
@@ -4,14 +4,9 @@ use anyhow::anyhow;
44use serde::{Deserialize, Serialize};
55use version::version;
66
7−#[derive(Serialize, Deserialize, Debug)]
8−pub struct State {
9− pub status: Status,
10−}
11−
127#[derive(Serialize, Deserialize, Clone, Debug)]
13−#[serde(tag = "status")]
14−pub enum Status {
8+#[serde(tag = "state")]
9+pub enum State {
1510 #[serde(rename = "idle")]
1611 Idle,
1712
@@ -37,24 +32,23 @@ pub enum Status {
3732}
3833
3934impl State {
40− pub fn load(db: &mut impl Conn) -> State {
41− Self::ensure_schema_and_table(db);
35+ pub fn load(db: &mut impl Conn) -> anyhow::Result<State> {
36+ Self::ensure_schema_and_table(db)?;
4237
43− let results = db
44− .query("SELECT value FROM reshape.data WHERE key = 'state'")
45− .unwrap();
38+ let results = db.query("SELECT value FROM reshape.data WHERE key = 'state'")?;
4639
47− match results.first() {
40+ let state = match results.first() {
4841 Some(row) => {
4942 let json: serde_json::Value = row.get(0);
50− serde_json::from_value(json).unwrap()
43+ serde_json::from_value(json)?
5144 }
5245 None => Default::default(),
53− }
46+ };
47+ Ok(state)
5448 }
5549
5650 pub fn save(&self, db: &mut impl Conn) -> anyhow::Result<()> {
57− Self::ensure_schema_and_table(db);
51+ Self::ensure_schema_and_table(db)?;
5852
5953 let json = serde_json::to_value(self)?;
6054 db.query_with_params(
@@ -67,17 +61,17 @@ impl State {
6761 pub fn clear(&mut self, db: &mut impl Conn) -> anyhow::Result<()> {
6862 db.run("DROP SCHEMA reshape CASCADE")?;
6963
70− let default = Self::default();
71− self.status = default.status;
64+ *self = Self::default();
7265
7366 Ok(())
7467 }
7568
76− // Complete will change the status from Completing to Idle
69+ // Complete will change the state from Completing to Idle
7770 pub fn complete(&mut self, db: &mut impl Conn) -> anyhow::Result<()> {
78− let current_status = std::mem::replace(&mut self.status, Status::Idle);
79− match current_status {
80− Status::Completing { migrations, .. } => {
71+ let current_state = std::mem::replace(self, Self::Idle);
72+
73+ match current_state {
74+ Self::Completing { migrations, .. } => {
8175 // Add migrations and update state in a transaction to ensure atomicity
8276 let mut transaction = db.transaction()?;
8377 save_migrations(&mut transaction, &migrations)?;
@@ -85,8 +79,8 @@ impl State {
8579 transaction.commit()?;
8680 }
8781 _ => {
88− // Move old status back
89− self.status = current_status;
82+ // Move old state back
83+ *self = current_state;
9084
9185 return Err(anyhow!(
9286 "couldn't update state to be completed, not in Completing state"
@@ -98,13 +92,13 @@ impl State {
9892 }
9993
10094 pub fn applying(&mut self, new_migrations: Vec<Migration>) {
101− self.status = Status::Applying {
95+ *self = Self::Applying {
10296 migrations: new_migrations,
10397 };
10498 }
10599
106100 pub fn in_progress(&mut self, new_migrations: Vec<Migration>) {
107− self.status = Status::InProgress {
101+ *self = Self::InProgress {
108102 migrations: new_migrations,
109103 };
110104 }
@@ -115,7 +109,7 @@ impl State {
115109 current_migration_index: usize,
116110 current_action_index: usize,
117111 ) {
118− self.status = Status::Completing {
112+ *self = Self::Completing {
119113 migrations,
120114 current_migration_index,
121115 current_action_index,
@@ -128,20 +122,19 @@ impl State {
128122 last_migration_index: usize,
129123 last_action_index: usize,
130124 ) {
131− self.status = Status::Aborting {
125+ *self = Self::Aborting {
132126 migrations,
133127 last_migration_index,
134128 last_action_index,
135129 }
136130 }
137131
138− fn ensure_schema_and_table(db: &mut impl Conn) {
139− db.run("CREATE SCHEMA IF NOT EXISTS reshape").unwrap();
132+ fn ensure_schema_and_table(db: &mut impl Conn) -> anyhow::Result<()> {
133+ db.run("CREATE SCHEMA IF NOT EXISTS reshape")?;
140134
141135 // Create data table which will be a key-value table containing
142136 // the version and current state.
143− db.run("CREATE TABLE IF NOT EXISTS reshape.data (key TEXT PRIMARY KEY, value JSONB)")
144− .unwrap();
137+ db.run("CREATE TABLE IF NOT EXISTS reshape.data (key TEXT PRIMARY KEY, value JSONB)")?;
145138
146139 // Create migrations table which will store all completed migrations
147140 db.run(
@@ -154,11 +147,10 @@ impl State {
154147 completed_at TIMESTAMP DEFAULT NOW()
155148 )
156149 ",
157− )
158− .unwrap();
150+ )?;
159151
160152 // Update the current version
161− let encoded_version = serde_json::to_value(version!().to_string()).unwrap();
153+ let encoded_version = serde_json::to_value(version!().to_string())?;
162154 db.query_with_params(
163155 "
164156 INSERT INTO reshape.data (key, value)
@@ -166,16 +158,15 @@ impl State {
166158 ON CONFLICT (key) DO UPDATE SET value = $1
167159 ",
168160 &[&encoded_version],
169− )
170− .unwrap();
161+ )?;
162+
163+ Ok(())
171164 }
172165}
173166
174167impl Default for State {
175168 fn default() -> Self {
176− State {
177− status: Status::Idle,
178− }
169+ Self::Idle
179170 }
180171}
181172
tests/add_column.rs−4
@@ -1,5 +1,4 @@
11use reshape::migrations::{AddColumn, Column, ColumnBuilder, CreateTableBuilder, Migration};
2−use reshape::Status;
32
43mod common;
54
@@ -59,7 +58,6 @@ fn add_column() {
5958
6059 // Run first migration, should automatically finish
6160 reshape.migrate(first_migrations.clone()).unwrap();
62− assert!(matches!(reshape.state.status, Status::Idle));
6361
6462 // Update search paths
6563 old_db
@@ -151,7 +149,6 @@ fn add_column_nullable() {
151149
152150 // Run first migration, should automatically finish
153151 reshape.migrate(first_migrations.clone()).unwrap();
154− assert!(matches!(reshape.state.status, Status::Idle));
155152
156153 // Update search paths
157154 old_db
@@ -246,7 +243,6 @@ fn add_column_with_default() {
246243
247244 // Run first migration, should automatically finish
248245 reshape.migrate(first_migrations.clone()).unwrap();
249− assert!(matches!(reshape.state.status, Status::Idle));
250246
251247 // Update search paths
252248 old_db
tests/alter_column.rs−7
@@ -1,7 +1,6 @@
11use reshape::migrations::{
22 AddIndex, AlterColumn, ColumnBuilder, ColumnChanges, CreateTableBuilder, Migration,
33};
4−use reshape::Status;
54
65mod common;
76
@@ -46,7 +45,6 @@ fn alter_column_data() {
4645
4746 // Run first migration, should automatically finish
4847 reshape.migrate(first_migrations.clone()).unwrap();
49− assert!(matches!(reshape.state.status, Status::Idle));
5048
5149 // Update search paths
5250 old_db
@@ -146,7 +144,6 @@ fn alter_column_set_not_null() {
146144
147145 // Run first migration, should automatically finish
148146 reshape.migrate(first_migrations.clone()).unwrap();
149− assert!(matches!(reshape.state.status, Status::Idle));
150147
151148 // Update search paths
152149 old_db
@@ -247,7 +244,6 @@ fn alter_column_rename() {
247244
248245 // Run first migration, should automatically finish
249246 reshape.migrate(first_migrations.clone()).unwrap();
250− assert!(matches!(reshape.state.status, Status::Idle));
251247
252248 // Update search paths
253249 old_db
@@ -343,7 +339,6 @@ fn alter_column_multiple() {
343339
344340 // Run first migration, should automatically finish
345341 reshape.migrate(first_migrations.clone()).unwrap();
346− assert!(matches!(reshape.state.status, Status::Idle));
347342
348343 // Update search paths
349344 old_db
@@ -455,7 +450,6 @@ fn alter_column_default() {
455450
456451 // Run first migration, should automatically finish
457452 reshape.migrate(first_migrations.clone()).unwrap();
458− assert!(matches!(reshape.state.status, Status::Idle));
459453
460454 // Update search paths
461455 old_db
@@ -564,7 +558,6 @@ fn alter_column_with_index() {
564558
565559 // Run first migration, should automatically finish
566560 reshape.migrate(first_migrations.clone()).unwrap();
567− assert!(matches!(reshape.state.status, Status::Idle));
568561
569562 // Run second migration
570563 reshape.migrate(second_migrations.clone()).unwrap();
tests/create_table.rs+1−5
@@ -1,7 +1,4 @@
1−use reshape::{
2− migrations::{ColumnBuilder, CreateTableBuilder, ForeignKey, Migration},
3− Status,
4−};
1+use reshape::migrations::{ColumnBuilder, CreateTableBuilder, ForeignKey, Migration};
52
63mod common;
74
@@ -40,7 +37,6 @@ fn create_table() {
4037 reshape
4138 .migrate(vec![create_table_migration.clone()])
4239 .unwrap();
43− assert!(matches!(reshape.state.status, Status::Idle));
4440
4541 // Ensure table was created
4642 let result = db
tests/failure.rs−2
@@ -1,5 +1,4 @@
11use reshape::migrations::{AddColumn, Column, CreateTable, Migration};
2−use reshape::Status;
32
43mod common;
54
@@ -45,7 +44,6 @@ fn invalid_migration() {
4544
4645 // Run first migration, should automatically finish
4746 reshape.migrate(first_migrations.clone()).unwrap();
48− assert!(matches!(reshape.state.status, Status::Idle));
4947
5048 // Update search paths
5149 old_db