Skip to content

Commit cf766a8

Browse files
committed
add automatic SQL migrations
1 parent e7b8860 commit cf766a8

File tree

3 files changed

+294
-118
lines changed

3 files changed

+294
-118
lines changed

mithril-common/src/database/db_version.rs

Lines changed: 18 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1-
use std::{cmp::Ordering, collections::HashMap, error::Error, fmt::Display, path::PathBuf};
2-
3-
use chrono::{Local, NaiveDateTime};
1+
use std::{
2+
cmp::Ordering,
3+
collections::HashMap,
4+
error::Error,
5+
fmt::{Debug, Display},
6+
};
7+
8+
use chrono::NaiveDateTime;
49
use semver::Version;
5-
use slog::{debug, warn, Logger};
610
use sqlite::{Connection, Row, Value};
711

812
use crate::sqlite::{HydrationError, Projection, ProjectionField, Provider, SqLiteEntity};
@@ -67,6 +71,16 @@ impl SqLiteEntity for ApplicationVersion {
6771
}
6872
}
6973

74+
impl PartialOrd for ApplicationVersion {
75+
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
76+
if self.application_type != other.application_type {
77+
None
78+
} else {
79+
self.semver.partial_cmp(&other.semver)
80+
}
81+
}
82+
}
83+
7084
/// Projection dedicated to [ApplicationVersion] entities.
7185
struct ApplicationVersionProjection {
7286
fields: Vec<ProjectionField>,
@@ -233,88 +247,6 @@ returning {projection}
233247
}
234248
}
235249

236-
/// Struct to perform application version check in the database.
237-
#[derive(Debug)]
238-
pub struct ApplicationVersionChecker {
239-
/// Pathbuf to the SQLite3 file.
240-
sqlite_file_path: PathBuf,
241-
242-
/// Application type which vesion is verified.
243-
application_type: ApplicationNodeType,
244-
245-
/// logger
246-
logger: Logger,
247-
}
248-
249-
impl ApplicationVersionChecker {
250-
/// constructor
251-
pub fn new(
252-
logger: Logger,
253-
application_type: ApplicationNodeType,
254-
sqlite_file_path: PathBuf,
255-
) -> Self {
256-
Self {
257-
sqlite_file_path,
258-
application_type,
259-
logger,
260-
}
261-
}
262-
263-
/// Performs an actual version check in the database. This method creates a
264-
/// connection to the SQLite3 file and drops it at the end.
265-
pub fn check(&self, current_semver: &str) -> Result<(), Box<dyn Error>> {
266-
debug!(
267-
&self.logger,
268-
"check application version, database file = '{}'",
269-
self.sqlite_file_path.display()
270-
);
271-
let connection = Connection::open(&self.sqlite_file_path)?;
272-
let provider = VersionProvider::new(&connection);
273-
provider.create_table_if_not_exists()?;
274-
let updater = VersionUpdaterProvider::new(&connection);
275-
let maybe_option = provider.get_application_version(&self.application_type)?;
276-
let current_version = ApplicationVersion {
277-
semver: Version::parse(current_semver)?,
278-
application_type: self.application_type.clone(),
279-
updated_at: Local::now().naive_local(),
280-
};
281-
282-
match maybe_option {
283-
None => {
284-
let current_version = updater.save(current_version)?;
285-
debug!(
286-
&self.logger,
287-
"Application version '{}' saved in database.", current_version.semver
288-
);
289-
}
290-
Some(version) => match current_version.semver.cmp(&version.semver) {
291-
Ordering::Greater => {
292-
warn!(
293-
&self.logger,
294-
"Application version '{}' is out of date, new version is '{}'. Upgrading database…",
295-
version.semver, current_version.semver
296-
);
297-
updater.save(current_version)?;
298-
debug!(&self.logger, "database updated");
299-
}
300-
Ordering::Less => {
301-
warn!(
302-
&self.logger,
303-
"Software version '{}' is older than database structure version '{}'.",
304-
current_version.semver,
305-
version.semver
306-
);
307-
}
308-
Ordering::Equal => {
309-
debug!(&self.logger, "database up to date");
310-
}
311-
},
312-
};
313-
314-
Ok(())
315-
}
316-
}
317-
318250
#[cfg(test)]
319251
mod tests {
320252
use super::*;
@@ -361,36 +293,4 @@ returning app_version.semver as semver, app_version.application_type as applicat
361293
provider.get_definition(None)
362294
)
363295
}
364-
365-
fn check_database_version(filepath: &PathBuf, semver: &str) {
366-
let connection = Connection::open(filepath).unwrap();
367-
let provider = VersionProvider::new(&connection);
368-
let version = provider
369-
.get_application_version(&ApplicationNodeType::Aggregator)
370-
.unwrap()
371-
.expect("there should be a version in the database");
372-
373-
assert_eq!(semver, version.semver.to_string());
374-
}
375-
376-
#[test]
377-
fn test_application_version_checker() {
378-
let filepath = std::env::temp_dir().join("test.sqlite3");
379-
380-
if filepath.exists() {
381-
std::fs::remove_file(filepath.as_path()).unwrap();
382-
}
383-
let app_checker = ApplicationVersionChecker::new(
384-
slog_scope::logger(),
385-
ApplicationNodeType::Aggregator,
386-
filepath.clone(),
387-
);
388-
app_checker.check("1.0.0").unwrap();
389-
check_database_version(&filepath, "1.0.0");
390-
app_checker.check("1.0.0").unwrap();
391-
check_database_version(&filepath, "1.0.0");
392-
app_checker.check("1.1.0").unwrap();
393-
check_database_version(&filepath, "1.1.0");
394-
app_checker.check("1.0.1").unwrap();
395-
}
396296
}

mithril-common/src/database/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,7 @@
22
//! This module contains providers and entities shared between all application types.
33
44
mod db_version;
5+
mod version_checker;
56

67
pub use db_version::*;
8+
pub use version_checker::{ApplicationVersionChecker, SqlMigration};

0 commit comments

Comments
 (0)