From 4203b21097fbbb363663ec0634ccb086ff6ecca0 Mon Sep 17 00:00:00 2001 From: Dmitriy Pleshevskiy Date: Sat, 20 Aug 2022 15:24:17 +0300 Subject: [PATCH] repo/sqlite: add migration mechanism --- src/main.rs | 6 +++- src/repo/sqlite.rs | 77 ++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 70 insertions(+), 13 deletions(-) diff --git a/src/main.rs b/src/main.rs index 246456c..1ee17d8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -40,9 +40,13 @@ fn main() { let xdg_dirs = BaseDirectories::with_prefix(env!("CARGO_PKG_NAME")).unwrap(); let repo = match SqliteRepo::new(xdg_dirs) { Ok(repo) => repo, - Err(err) => return eprintln!("Cannot connect to repository: {}", err), + Err(err) => return eprintln!("Cannot connect to repository: {err}"), }; + if let Err(err) = repo.upgrade() { + return eprintln!("Cannot upgrade database: {err}"); + } + match args.command { cli::SubCommand::Add(args) => { cli::add::execute(repo, args); diff --git a/src/repo/sqlite.rs b/src/repo/sqlite.rs index 920824c..89dbb51 100644 --- a/src/repo/sqlite.rs +++ b/src/repo/sqlite.rs @@ -62,18 +62,6 @@ impl SqliteRepo { let file_path = xdg_dirs.get_data_file(SCHEMA_FILE); let conn = Connection::open(file_path).map_err(|_| Error::Connect)?; - /* - conn.execute_batch(&format!( - "BEGIN; {} COMMIT;", - include_str!("../../database/schema.sql") - )) - .map_err(|err| match err { - rusqlite::Error::SqlInputError { .. } => panic!("{}", err), - _ => err, - }) - .ok(); - */ - Ok(Self { conn }) } } @@ -261,3 +249,68 @@ impl SqliteRepo { Ok(row) } } + +macro_rules! run_migration { + ($this:ident, $ver:ident = $version:expr) => { + $this + .conn + .execute_batch(&format!( + "BEGIN; {} COMMIT;", + include_str!(concat!("../../database/migrations/", $version, ".sql")) + )) + .map_err(|_| MigrationError::Upgrade)?; + + $ver.replace($version); + }; +} + +// TODO: move migration to a separate repository. +#[derive(Debug)] +pub enum MigrationError { + Upgrade, + DeleteInfo, + InsertInfo, +} + +impl std::fmt::Display for MigrationError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + MigrationError::Upgrade => f.write_str("Cannot upgrade the migration to a new version"), + MigrationError::DeleteInfo => { + f.write_str("Cannot delete the tas info from the database") + } + MigrationError::InsertInfo => { + f.write_str("Cannot insert a new tas information to the database") + } + } + } +} + +impl std::error::Error for MigrationError {} + +impl SqliteRepo { + pub fn upgrade(&self) -> Result<(), MigrationError> { + let mut version = self.version(); + if version.is_none() { + run_migration!(self, version = 202208162308); + } + + self.conn + .execute("DELETE FROM _tas_info", []) + .map_err(|_| MigrationError::DeleteInfo)?; + self.conn + .execute( + "INSERT INTO _tas_info (version) VALUES (?)", + [version.unwrap()], + ) + .map_err(|_| MigrationError::InsertInfo)?; + + Ok(()) + } + + fn version(&self) -> Option { + self.conn + .query_row("SELECT version FROM _tas_info", [], |r| r.get("version")) + .unwrap_or_default() + } +}