Skip to content

Commit 056f03f

Browse files
committed
refactor(persistence): apply PR review comments
- add `check_minimum_required_version` documentation - extract error message creation in a dedicated function - enhance test readability and maintainability
1 parent 62cddb9 commit 056f03f

File tree

1 file changed

+70
-101
lines changed

1 file changed

+70
-101
lines changed

internal/mithril-persistence/src/database/version_checker.rs

Lines changed: 70 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ use chrono::Utc;
33
use slog::{debug, error, info, Logger};
44
use std::{cmp::Ordering, collections::BTreeSet};
55

6-
use mithril_common::logging::LoggerExtensions;
7-
use mithril_common::StdResult;
6+
use mithril_common::{logging::LoggerExtensions, StdError, StdResult};
87

98
use super::{
109
ApplicationNodeType, DatabaseVersion, DbVersion, GetDatabaseVersionQuery,
@@ -155,6 +154,10 @@ insert into db_version (application_type, version, updated_at) values ('{applica
155154
Ok(())
156155
}
157156

157+
/// Checks if the database version meets the minimum required version to apply a squashed migration.
158+
/// If the database version 0 or if the migration doesn't specify a fallback distribution version, the check passes.
159+
/// For migrations with a fallback distribution version, the check passes if the database version is exactly
160+
/// one less than the migration version (i.e., there's no gap between them).
158161
fn check_minimum_required_version(
159162
&self,
160163
db_version: DbVersion,
@@ -167,29 +170,40 @@ insert into db_version (application_type, version, updated_at) values ('{applica
167170
if let Some(fallback_distribution_version) = &migration.fallback_distribution_version {
168171
let min_required_version = migration.version - 1;
169172
if db_version < min_required_version {
170-
return Err(anyhow!(
171-
r#"
172-
Minimum required database version is not met to apply migration '{}'.
173-
Please migrate your {} node database with the minimum node version compatible available in the distribution: '{}'.
174-
175-
First, download the required node version in your current directory by running the following command:
176-
curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/input-output-hk/mithril/refs/heads/main/mithril-install.sh | sh -s -- -c mithril-{} -d {} -p $(pwd)
177-
178-
Then run the database migrate command:
179-
mithril-{} database migrate --stores-directory /path/to/stores-directory
180-
"#,
173+
return Err(self.generate_fallback_migration_error(
181174
migration.version,
182-
self.application_type.to_string(),
183-
fallback_distribution_version,
184-
self.application_type.to_string(),
185175
fallback_distribution_version,
186-
self.application_type.to_string()
187176
));
188177
}
189178
}
190179

191180
Ok(())
192181
}
182+
183+
fn generate_fallback_migration_error(
184+
&self,
185+
migration_version: i64,
186+
fallback_distribution_version: &str,
187+
) -> StdError {
188+
anyhow!(
189+
r#"
190+
Minimum required database version is not met to apply migration '{}'.
191+
Please migrate your {} node database with the minimum node version compatible available in the distribution: '{}'.
192+
193+
First, download the required node version in your current directory by running the following command:
194+
curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/input-output-hk/mithril/refs/heads/main/mithril-install.sh | sh -s -- -c mithril-{} -d {} -p $(pwd)
195+
196+
Then run the database migrate command:
197+
mithril-{} database migrate --stores-directory /path/to/stores-directory
198+
"#,
199+
migration_version,
200+
self.application_type.to_string(),
201+
fallback_distribution_version,
202+
self.application_type.to_string(),
203+
fallback_distribution_version,
204+
self.application_type.to_string()
205+
)
206+
}
193207
}
194208

195209
/// Represent a file containing SQL structure or data alterations.
@@ -253,12 +267,15 @@ impl Eq for SqlMigration {}
253267
mod tests {
254268
use anyhow::Context;
255269
use mithril_common::test_utils::TempDir;
256-
use mithril_common::StdResult;
257-
use sqlite::Connection;
270+
use mithril_common::{current_function, StdResult};
271+
use sqlite::{Connection, ConnectionThreadSafe};
258272
use std::path::PathBuf;
259273

260274
use super::*;
261275

276+
const CREATE_TABLE_SQL_REQUEST: &str = "create table whatever (thing_id integer); insert into whatever (thing_id) values (1), (2), (3), (4);";
277+
const ALTER_TABLE_SQL_REQUEST: &str = "alter table whatever add column thing_content text; update whatever set thing_content = 'some content'";
278+
262279
fn discard_logger() -> Logger {
263280
Logger::root(slog::Discard, slog::o!())
264281
}
@@ -298,15 +315,18 @@ mod tests {
298315
column_count
299316
}
300317

301-
#[test]
302-
fn test_upgrade_with_migration() {
303-
let (_filepath, connection) =
304-
create_sqlite_file("test_upgrade_with_migration.sqlite3").unwrap();
305-
let mut db_checker = DatabaseVersionChecker::new(
318+
fn create_db_checker(connection: &ConnectionThreadSafe) -> DatabaseVersionChecker {
319+
DatabaseVersionChecker::new(
306320
discard_logger(),
307321
ApplicationNodeType::Aggregator,
308-
&connection,
309-
);
322+
connection,
323+
)
324+
}
325+
326+
#[test]
327+
fn test_upgrade_with_migration() {
328+
let (_filepath, connection) = create_sqlite_file(current_function!()).unwrap();
329+
let mut db_checker = create_db_checker(&connection);
310330

311331
db_checker.apply().unwrap();
312332
assert_eq!(0, get_table_whatever_column_count(&connection));
@@ -364,13 +384,8 @@ mod tests {
364384

365385
#[test]
366386
fn test_upgrade_with_migration_with_a_version_gap() {
367-
let (_filepath, connection) =
368-
create_sqlite_file("test_upgrade_with_migration_with_a_version_gap.sqlite3").unwrap();
369-
let mut db_checker = DatabaseVersionChecker::new(
370-
discard_logger(),
371-
ApplicationNodeType::Aggregator,
372-
&connection,
373-
);
387+
let (_filepath, connection) = create_sqlite_file(current_function!()).unwrap();
388+
let mut db_checker = create_db_checker(&connection);
374389

375390
let alterations = "create table whatever (thing_id integer); insert into whatever (thing_id) values (1), (2), (3), (4);";
376391
let migration = SqlMigration {
@@ -397,12 +412,8 @@ mod tests {
397412

398413
#[test]
399414
fn starting_with_migration() {
400-
let (_filepath, connection) = create_sqlite_file("starting_with_migration").unwrap();
401-
let mut db_checker = DatabaseVersionChecker::new(
402-
discard_logger(),
403-
ApplicationNodeType::Aggregator,
404-
&connection,
405-
);
415+
let (_filepath, connection) = create_sqlite_file(current_function!()).unwrap();
416+
let mut db_checker = create_db_checker(&connection);
406417

407418
let alterations = "create table whatever (thing_id integer); insert into whatever (thing_id) values (1), (2), (3), (4);";
408419
let migration = SqlMigration {
@@ -421,12 +432,8 @@ mod tests {
421432
/// * previous migrations are ok and the database version is updated
422433
/// * further migrations are not played.
423434
fn test_failing_migration() {
424-
let (_filepath, connection) = create_sqlite_file("test_failing_migration").unwrap();
425-
let mut db_checker = DatabaseVersionChecker::new(
426-
discard_logger(),
427-
ApplicationNodeType::Aggregator,
428-
&connection,
429-
);
435+
let (_filepath, connection) = create_sqlite_file(current_function!()).unwrap();
436+
let mut db_checker = create_db_checker(&connection);
430437
// Table whatever does not exist, this should fail with error.
431438
let alterations = "create table whatever (thing_id integer); insert into whatever (thing_id) values (1), (2), (3), (4);";
432439
let migration = SqlMigration {
@@ -455,28 +462,19 @@ mod tests {
455462

456463
#[test]
457464
fn test_fail_downgrading() {
458-
let (_filepath, connection) = create_sqlite_file("test_fail_downgrading").unwrap();
459-
let mut db_checker = DatabaseVersionChecker::new(
460-
discard_logger(),
461-
ApplicationNodeType::Aggregator,
462-
&connection,
463-
);
464-
let alterations = "create table whatever (thing_id integer); insert into whatever (thing_id) values (1), (2), (3), (4);";
465+
let (_filepath, connection) = create_sqlite_file(current_function!()).unwrap();
466+
let mut db_checker = create_db_checker(&connection);
465467
let migration = SqlMigration {
466468
version: 1,
467-
alterations: alterations.to_string(),
469+
alterations: CREATE_TABLE_SQL_REQUEST.to_string(),
468470
fallback_distribution_version: None,
469471
};
470472
db_checker.add_migration(migration);
471473
db_checker.apply().unwrap();
472474
check_database_version(&connection, 1);
473475

474476
// re instantiate a new checker with no migration registered (version 0).
475-
let db_checker = DatabaseVersionChecker::new(
476-
discard_logger(),
477-
ApplicationNodeType::Aggregator,
478-
&connection,
479-
);
477+
let db_checker = create_db_checker(&connection);
480478
assert!(
481479
db_checker.apply().is_err(),
482480
"using an old version with an up to date database should fail"
@@ -486,17 +484,10 @@ mod tests {
486484

487485
#[test]
488486
fn check_minimum_required_version_does_not_fail_when_no_fallback_distribution_version() {
489-
let (_filepath, connection) = create_sqlite_file(
490-
"check_minimum_required_version_does_not_fail_when_no_fallback_distribution_version",
491-
)
492-
.unwrap();
493-
let db_checker = DatabaseVersionChecker::new(
494-
discard_logger(),
495-
ApplicationNodeType::Aggregator,
496-
&connection,
497-
);
487+
let (_filepath, connection) = create_sqlite_file(current_function!()).unwrap();
488+
let db_checker = create_db_checker(&connection);
498489

499-
let alterations = "create table whatever (thing_id integer); insert into whatever (thing_id) values (1), (2), (3), (4);";
490+
let alterations = CREATE_TABLE_SQL_REQUEST;
500491
let migration = SqlMigration {
501492
version: 3,
502493
alterations: alterations.to_string(),
@@ -513,17 +504,10 @@ mod tests {
513504
#[test]
514505
fn check_minimum_required_version_does_not_fail_when_fallback_distribution_version_with_fresh_database(
515506
) {
516-
let (_filepath, connection) = create_sqlite_file(
517-
"check_minimum_required_version_does_not_fail_when_fallback_distribution_version_with_fresh_database",
518-
)
519-
.unwrap();
520-
let db_checker = DatabaseVersionChecker::new(
521-
discard_logger(),
522-
ApplicationNodeType::Aggregator,
523-
&connection,
524-
);
507+
let (_filepath, connection) = create_sqlite_file(current_function!()).unwrap();
508+
let db_checker = create_db_checker(&connection);
525509

526-
let alterations = "create table whatever (thing_id integer); insert into whatever (thing_id) values (1), (2), (3), (4);";
510+
let alterations = CREATE_TABLE_SQL_REQUEST;
527511
let migration = SqlMigration {
528512
version: 2,
529513
alterations: alterations.to_string(),
@@ -538,20 +522,12 @@ mod tests {
538522
#[test]
539523
fn check_minimum_required_version_does_not_fail_when_no_gap_between_db_version_and_migration_version(
540524
) {
541-
let (_filepath, connection) = create_sqlite_file(
542-
"check_minimum_required_version_does_not_fail_when_no_gap_between_db_version_and_migration_version",
543-
)
544-
.unwrap();
545-
let db_checker = DatabaseVersionChecker::new(
546-
discard_logger(),
547-
ApplicationNodeType::Aggregator,
548-
&connection,
549-
);
525+
let (_filepath, connection) = create_sqlite_file(current_function!()).unwrap();
526+
let db_checker = create_db_checker(&connection);
550527

551-
let alterations = "alter table whatever add column thing_content text; update whatever set thing_content = 'some content'";
552528
let migration = SqlMigration {
553529
version: 2,
554-
alterations: alterations.to_string(),
530+
alterations: CREATE_TABLE_SQL_REQUEST.to_string(),
555531
fallback_distribution_version: Some("2511.0".to_string()),
556532
};
557533

@@ -562,20 +538,16 @@ mod tests {
562538

563539
#[test]
564540
fn check_minimum_required_version_fails_when_gap_between_db_version_and_migration_version() {
565-
let (_filepath, connection) = create_sqlite_file(
566-
"check_minimum_required_version_fails_when_gap_between_db_version_and_migration_version",
567-
)
568-
.unwrap();
541+
let (_filepath, connection) = create_sqlite_file(current_function!()).unwrap();
569542
let db_checker = DatabaseVersionChecker::new(
570543
discard_logger(),
571544
ApplicationNodeType::Aggregator,
572545
&connection,
573546
);
574547

575-
let alterations = "alter table whatever add column thing_content text; update whatever set thing_content = 'some content'";
576548
let migration = SqlMigration {
577549
version: 3,
578-
alterations: alterations.to_string(),
550+
alterations: CREATE_TABLE_SQL_REQUEST.to_string(),
579551
fallback_distribution_version: Some("2511.0".to_string()),
580552
};
581553

@@ -588,28 +560,25 @@ mod tests {
588560

589561
#[test]
590562
fn apply_fails_when_trying_to_apply_squashed_migration_on_old_database() {
591-
let (_filepath, connection) =
592-
create_sqlite_file("apply_fails_with_squashed_migration").unwrap();
563+
let (_filepath, connection) = create_sqlite_file(current_function!()).unwrap();
593564
let mut db_checker = DatabaseVersionChecker::new(
594565
discard_logger(),
595566
ApplicationNodeType::Aggregator,
596567
&connection,
597568
);
598569

599-
let alterations = "create table whatever (thing_id integer); insert into whatever (thing_id) values (1), (2), (3), (4);";
600570
let migration = SqlMigration {
601571
version: 1,
602-
alterations: alterations.to_string(),
572+
alterations: CREATE_TABLE_SQL_REQUEST.to_string(),
603573
fallback_distribution_version: None,
604574
};
605575
db_checker.add_migration(migration);
606576
db_checker.apply().unwrap();
607577
check_database_version(&connection, 1);
608578

609-
let alterations = "alter table whatever add column thing_content text; update whatever set thing_content = 'some content'";
610579
let squashed_migration = SqlMigration {
611580
version: 3,
612-
alterations: alterations.to_string(),
581+
alterations: ALTER_TABLE_SQL_REQUEST.to_string(),
613582
fallback_distribution_version: Some("2511.0".to_string()),
614583
};
615584
db_checker.add_migration(squashed_migration);

0 commit comments

Comments
 (0)