From a25046430931a96f592ad91695bb4f963954ce2a Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Thu, 1 Apr 2021 17:34:03 +1000 Subject: [PATCH] switch DbError to tuple type --- rslib/src/dbcheck.rs | 14 +++++------ rslib/src/error/db.rs | 41 +++++++++++++++++++++++++------ rslib/src/error/mod.rs | 14 +++-------- rslib/src/error/network.rs | 4 +++ rslib/src/media/check.rs | 9 +++---- rslib/src/storage/deck/mod.rs | 13 +++++----- rslib/src/storage/notetype/mod.rs | 5 +--- rslib/src/storage/sqlite.rs | 5 +--- 8 files changed, 59 insertions(+), 46 deletions(-) diff --git a/rslib/src/dbcheck.rs b/rslib/src/dbcheck.rs index 1e56db5ea..701ab0896 100644 --- a/rslib/src/dbcheck.rs +++ b/rslib/src/dbcheck.rs @@ -4,7 +4,7 @@ use crate::{ collection::Collection, config::SchedulerVersion, - error::{AnkiError, DbErrorKind, Result}, + error::{AnkiError, DbError, DbErrorKind, Result}, i18n::I18n, notetype::{ all_stock_notetypes, AlreadyGeneratedCardInfo, CardGenContext, Notetype, NotetypeId, @@ -90,10 +90,10 @@ impl Collection { debug!(self.log, "quick check"); if self.storage.quick_check_corrupt() { debug!(self.log, "quick check failed"); - return Err(AnkiError::DbError { - info: self.tr.database_check_corrupt().into(), - kind: DbErrorKind::Corrupt, - }); + return Err(AnkiError::db_error( + self.tr.database_check_corrupt(), + DbErrorKind::Corrupt, + )); } progress_fn(DatabaseCheckProgress::Optimize, false); @@ -289,10 +289,10 @@ impl Collection { match self.storage.get_note(nid) { Ok(note) => Ok(note.unwrap()), Err(err) => match err { - AnkiError::DbError { + AnkiError::DbError(DbError { kind: DbErrorKind::Utf8, .. - } => { + }) => { // fix note then fetch again self.storage.fix_invalid_utf8_in_note(nid)?; out.invalid_utf8 += 1; diff --git a/rslib/src/error/db.rs b/rslib/src/error/db.rs index 7cef5c6ac..555fcd69e 100644 --- a/rslib/src/error/db.rs +++ b/rslib/src/error/db.rs @@ -1,11 +1,18 @@ // Copyright: Ankitects Pty Ltd and contributors // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html +use anki_i18n::I18n; use rusqlite::{types::FromSqlError, Error}; use std::str::Utf8Error; use super::AnkiError; +#[derive(Debug, PartialEq)] +pub struct DbError { + pub info: String, + pub kind: DbErrorKind, +} + #[derive(Debug, PartialEq)] pub enum DbErrorKind { FileTooNew, @@ -17,23 +24,32 @@ pub enum DbErrorKind { Other, } +impl AnkiError { + pub(crate) fn db_error(info: impl Into, kind: DbErrorKind) -> Self { + AnkiError::DbError(DbError { + info: info.into(), + kind, + }) + } +} + impl From for AnkiError { fn from(err: Error) -> Self { if let Error::SqliteFailure(error, Some(reason)) = &err { if error.code == rusqlite::ErrorCode::DatabaseBusy { - return AnkiError::DbError { + return AnkiError::DbError(DbError { info: "".to_string(), kind: DbErrorKind::Locked, - }; + }); } if reason.contains("regex parse error") { return AnkiError::InvalidRegex(reason.to_owned()); } } - AnkiError::DbError { + AnkiError::DbError(DbError { info: format!("{:?}", err), kind: DbErrorKind::Other, - } + }) } } @@ -41,15 +57,26 @@ impl From for AnkiError { fn from(err: FromSqlError) -> Self { if let FromSqlError::Other(ref err) = err { if let Some(_err) = err.downcast_ref::() { - return AnkiError::DbError { + return AnkiError::DbError(DbError { info: "".to_string(), kind: DbErrorKind::Utf8, - }; + }); } } - AnkiError::DbError { + AnkiError::DbError(DbError { info: format!("{:?}", err), kind: DbErrorKind::Other, + }) + } +} + +impl DbError { + pub fn localized_description(&self, _tr: &I18n) -> String { + match self.kind { + DbErrorKind::Corrupt => self.info.clone(), + // fixme: i18n + DbErrorKind::Locked => "Anki already open, or media currently syncing.".into(), + _ => format!("{:?}", self), } } } diff --git a/rslib/src/error/mod.rs b/rslib/src/error/mod.rs index b7fea4ac4..6aeaba8de 100644 --- a/rslib/src/error/mod.rs +++ b/rslib/src/error/mod.rs @@ -6,7 +6,7 @@ mod network; mod search; pub use { - db::DbErrorKind, + db::{DbError, DbErrorKind}, network::{NetworkError, NetworkErrorKind, SyncError, SyncErrorKind}, search::{ParseError, SearchErrorKind}, }; @@ -23,7 +23,7 @@ pub enum AnkiError { TemplateError { info: String }, TemplateSaveError { ordinal: usize }, IoError { info: String }, - DbError { info: String, kind: DbErrorKind }, + DbError(DbError), NetworkError(NetworkError), SyncError(SyncError), JsonError { info: String }, @@ -52,10 +52,6 @@ impl AnkiError { AnkiError::InvalidInput { info: s.into() } } - pub(crate) fn server_message>(msg: S) -> AnkiError { - AnkiError::sync_error(msg, SyncErrorKind::ServerMessage) - } - pub fn localized_description(&self, tr: &I18n) -> String { match self { AnkiError::SyncError(err) => err.localized_description(tr), @@ -67,11 +63,7 @@ impl AnkiError { AnkiError::TemplateSaveError { ordinal } => tr .card_templates_invalid_template_number(ordinal + 1) .into(), - AnkiError::DbError { info, kind } => match kind { - DbErrorKind::Corrupt => info.clone(), - DbErrorKind::Locked => "Anki already open, or media currently syncing.".into(), - _ => format!("{:?}", self), - }, + AnkiError::DbError(err) => err.localized_description(tr), AnkiError::SearchError(kind) => kind.localized_description(&tr), AnkiError::InvalidInput { info } => { if info.is_empty() { diff --git a/rslib/src/error/network.rs b/rslib/src/error/network.rs index 7524d477e..ee3303cd8 100644 --- a/rslib/src/error/network.rs +++ b/rslib/src/error/network.rs @@ -47,6 +47,10 @@ impl AnkiError { kind, }) } + + pub(crate) fn server_message>(msg: S) -> AnkiError { + AnkiError::sync_error(msg, SyncErrorKind::ServerMessage) + } } impl From for AnkiError { diff --git a/rslib/src/media/check.rs b/rslib/src/media/check.rs index 9de433df0..13ec9f236 100644 --- a/rslib/src/media/check.rs +++ b/rslib/src/media/check.rs @@ -360,12 +360,9 @@ where self.fire_progress_cb()?; } let mut note = self.ctx.storage.get_note(nid)?.unwrap(); - let nt = notetypes - .get(¬e.notetype_id) - .ok_or_else(|| AnkiError::DbError { - info: "missing note type".to_string(), - kind: DbErrorKind::MissingEntity, - })?; + let nt = notetypes.get(¬e.notetype_id).ok_or_else(|| { + AnkiError::db_error("missing note type", DbErrorKind::MissingEntity) + })?; if fix_and_extract_media_refs( &mut note, &mut referenced_files, diff --git a/rslib/src/storage/deck/mod.rs b/rslib/src/storage/deck/mod.rs index 75c635638..30d52a4a3 100644 --- a/rslib/src/storage/deck/mod.rs +++ b/rslib/src/storage/deck/mod.rs @@ -27,9 +27,11 @@ fn row_to_deck(row: &Row) -> Result { mtime_secs: row.get(2)?, usn: row.get(3)?, common, - kind: kind.kind.ok_or_else(|| AnkiError::DbError { - kind: DbErrorKind::MissingEntity, - info: format!("invalid deck kind: {}", id), + kind: kind.kind.ok_or_else(|| { + AnkiError::db_error( + format!("invalid deck kind: {}", id), + DbErrorKind::MissingEntity, + ) })?, }) } @@ -382,10 +384,7 @@ impl SqliteStorage { Ok(v) })? .next() - .ok_or_else(|| AnkiError::DbError { - info: "col table empty".to_string(), - kind: DbErrorKind::MissingEntity, - })??; + .ok_or_else(|| AnkiError::db_error("col table empty", DbErrorKind::MissingEntity))??; Ok(decks) } diff --git a/rslib/src/storage/notetype/mod.rs b/rslib/src/storage/notetype/mod.rs index 476388942..e341da63e 100644 --- a/rslib/src/storage/notetype/mod.rs +++ b/rslib/src/storage/notetype/mod.rs @@ -393,10 +393,7 @@ and ord in ", }, )? .next() - .ok_or_else(|| AnkiError::DbError { - info: "col table empty".to_string(), - kind: DbErrorKind::MissingEntity, - })??; + .ok_or_else(|| AnkiError::db_error("col table empty", DbErrorKind::MissingEntity))??; Ok(notetypes) } diff --git a/rslib/src/storage/sqlite.rs b/rslib/src/storage/sqlite.rs index 62457bdec..cbfe67c26 100644 --- a/rslib/src/storage/sqlite.rs +++ b/rslib/src/storage/sqlite.rs @@ -153,10 +153,7 @@ impl SqliteStorage { _ => None, }; if let Some(kind) = err { - return Err(AnkiError::DbError { - info: "".to_string(), - kind, - }); + return Err(AnkiError::db_error("", kind)); } let upgrade = ver != SCHEMA_MAX_VERSION;