switch DbError to tuple type

This commit is contained in:
Damien Elmes 2021-04-01 17:34:03 +10:00
parent 1704f7fe80
commit a250464309
8 changed files with 59 additions and 46 deletions

View file

@ -4,7 +4,7 @@
use crate::{ use crate::{
collection::Collection, collection::Collection,
config::SchedulerVersion, config::SchedulerVersion,
error::{AnkiError, DbErrorKind, Result}, error::{AnkiError, DbError, DbErrorKind, Result},
i18n::I18n, i18n::I18n,
notetype::{ notetype::{
all_stock_notetypes, AlreadyGeneratedCardInfo, CardGenContext, Notetype, NotetypeId, all_stock_notetypes, AlreadyGeneratedCardInfo, CardGenContext, Notetype, NotetypeId,
@ -90,10 +90,10 @@ impl Collection {
debug!(self.log, "quick check"); debug!(self.log, "quick check");
if self.storage.quick_check_corrupt() { if self.storage.quick_check_corrupt() {
debug!(self.log, "quick check failed"); debug!(self.log, "quick check failed");
return Err(AnkiError::DbError { return Err(AnkiError::db_error(
info: self.tr.database_check_corrupt().into(), self.tr.database_check_corrupt(),
kind: DbErrorKind::Corrupt, DbErrorKind::Corrupt,
}); ));
} }
progress_fn(DatabaseCheckProgress::Optimize, false); progress_fn(DatabaseCheckProgress::Optimize, false);
@ -289,10 +289,10 @@ impl Collection {
match self.storage.get_note(nid) { match self.storage.get_note(nid) {
Ok(note) => Ok(note.unwrap()), Ok(note) => Ok(note.unwrap()),
Err(err) => match err { Err(err) => match err {
AnkiError::DbError { AnkiError::DbError(DbError {
kind: DbErrorKind::Utf8, kind: DbErrorKind::Utf8,
.. ..
} => { }) => {
// fix note then fetch again // fix note then fetch again
self.storage.fix_invalid_utf8_in_note(nid)?; self.storage.fix_invalid_utf8_in_note(nid)?;
out.invalid_utf8 += 1; out.invalid_utf8 += 1;

View file

@ -1,11 +1,18 @@
// Copyright: Ankitects Pty Ltd and contributors // Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
use anki_i18n::I18n;
use rusqlite::{types::FromSqlError, Error}; use rusqlite::{types::FromSqlError, Error};
use std::str::Utf8Error; use std::str::Utf8Error;
use super::AnkiError; use super::AnkiError;
#[derive(Debug, PartialEq)]
pub struct DbError {
pub info: String,
pub kind: DbErrorKind,
}
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum DbErrorKind { pub enum DbErrorKind {
FileTooNew, FileTooNew,
@ -17,23 +24,32 @@ pub enum DbErrorKind {
Other, Other,
} }
impl AnkiError {
pub(crate) fn db_error(info: impl Into<String>, kind: DbErrorKind) -> Self {
AnkiError::DbError(DbError {
info: info.into(),
kind,
})
}
}
impl From<Error> for AnkiError { impl From<Error> for AnkiError {
fn from(err: Error) -> Self { fn from(err: Error) -> Self {
if let Error::SqliteFailure(error, Some(reason)) = &err { if let Error::SqliteFailure(error, Some(reason)) = &err {
if error.code == rusqlite::ErrorCode::DatabaseBusy { if error.code == rusqlite::ErrorCode::DatabaseBusy {
return AnkiError::DbError { return AnkiError::DbError(DbError {
info: "".to_string(), info: "".to_string(),
kind: DbErrorKind::Locked, kind: DbErrorKind::Locked,
}; });
} }
if reason.contains("regex parse error") { if reason.contains("regex parse error") {
return AnkiError::InvalidRegex(reason.to_owned()); return AnkiError::InvalidRegex(reason.to_owned());
} }
} }
AnkiError::DbError { AnkiError::DbError(DbError {
info: format!("{:?}", err), info: format!("{:?}", err),
kind: DbErrorKind::Other, kind: DbErrorKind::Other,
} })
} }
} }
@ -41,15 +57,26 @@ impl From<FromSqlError> for AnkiError {
fn from(err: FromSqlError) -> Self { fn from(err: FromSqlError) -> Self {
if let FromSqlError::Other(ref err) = err { if let FromSqlError::Other(ref err) = err {
if let Some(_err) = err.downcast_ref::<Utf8Error>() { if let Some(_err) = err.downcast_ref::<Utf8Error>() {
return AnkiError::DbError { return AnkiError::DbError(DbError {
info: "".to_string(), info: "".to_string(),
kind: DbErrorKind::Utf8, kind: DbErrorKind::Utf8,
}; });
} }
} }
AnkiError::DbError { AnkiError::DbError(DbError {
info: format!("{:?}", err), info: format!("{:?}", err),
kind: DbErrorKind::Other, 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),
} }
} }
} }

View file

@ -6,7 +6,7 @@ mod network;
mod search; mod search;
pub use { pub use {
db::DbErrorKind, db::{DbError, DbErrorKind},
network::{NetworkError, NetworkErrorKind, SyncError, SyncErrorKind}, network::{NetworkError, NetworkErrorKind, SyncError, SyncErrorKind},
search::{ParseError, SearchErrorKind}, search::{ParseError, SearchErrorKind},
}; };
@ -23,7 +23,7 @@ pub enum AnkiError {
TemplateError { info: String }, TemplateError { info: String },
TemplateSaveError { ordinal: usize }, TemplateSaveError { ordinal: usize },
IoError { info: String }, IoError { info: String },
DbError { info: String, kind: DbErrorKind }, DbError(DbError),
NetworkError(NetworkError), NetworkError(NetworkError),
SyncError(SyncError), SyncError(SyncError),
JsonError { info: String }, JsonError { info: String },
@ -52,10 +52,6 @@ impl AnkiError {
AnkiError::InvalidInput { info: s.into() } AnkiError::InvalidInput { info: s.into() }
} }
pub(crate) fn server_message<S: Into<String>>(msg: S) -> AnkiError {
AnkiError::sync_error(msg, SyncErrorKind::ServerMessage)
}
pub fn localized_description(&self, tr: &I18n) -> String { pub fn localized_description(&self, tr: &I18n) -> String {
match self { match self {
AnkiError::SyncError(err) => err.localized_description(tr), AnkiError::SyncError(err) => err.localized_description(tr),
@ -67,11 +63,7 @@ impl AnkiError {
AnkiError::TemplateSaveError { ordinal } => tr AnkiError::TemplateSaveError { ordinal } => tr
.card_templates_invalid_template_number(ordinal + 1) .card_templates_invalid_template_number(ordinal + 1)
.into(), .into(),
AnkiError::DbError { info, kind } => match kind { AnkiError::DbError(err) => err.localized_description(tr),
DbErrorKind::Corrupt => info.clone(),
DbErrorKind::Locked => "Anki already open, or media currently syncing.".into(),
_ => format!("{:?}", self),
},
AnkiError::SearchError(kind) => kind.localized_description(&tr), AnkiError::SearchError(kind) => kind.localized_description(&tr),
AnkiError::InvalidInput { info } => { AnkiError::InvalidInput { info } => {
if info.is_empty() { if info.is_empty() {

View file

@ -47,6 +47,10 @@ impl AnkiError {
kind, kind,
}) })
} }
pub(crate) fn server_message<S: Into<String>>(msg: S) -> AnkiError {
AnkiError::sync_error(msg, SyncErrorKind::ServerMessage)
}
} }
impl From<reqwest::Error> for AnkiError { impl From<reqwest::Error> for AnkiError {

View file

@ -360,12 +360,9 @@ where
self.fire_progress_cb()?; self.fire_progress_cb()?;
} }
let mut note = self.ctx.storage.get_note(nid)?.unwrap(); let mut note = self.ctx.storage.get_note(nid)?.unwrap();
let nt = notetypes let nt = notetypes.get(&note.notetype_id).ok_or_else(|| {
.get(&note.notetype_id) AnkiError::db_error("missing note type", DbErrorKind::MissingEntity)
.ok_or_else(|| AnkiError::DbError { })?;
info: "missing note type".to_string(),
kind: DbErrorKind::MissingEntity,
})?;
if fix_and_extract_media_refs( if fix_and_extract_media_refs(
&mut note, &mut note,
&mut referenced_files, &mut referenced_files,

View file

@ -27,9 +27,11 @@ fn row_to_deck(row: &Row) -> Result<Deck> {
mtime_secs: row.get(2)?, mtime_secs: row.get(2)?,
usn: row.get(3)?, usn: row.get(3)?,
common, common,
kind: kind.kind.ok_or_else(|| AnkiError::DbError { kind: kind.kind.ok_or_else(|| {
kind: DbErrorKind::MissingEntity, AnkiError::db_error(
info: format!("invalid deck kind: {}", id), format!("invalid deck kind: {}", id),
DbErrorKind::MissingEntity,
)
})?, })?,
}) })
} }
@ -382,10 +384,7 @@ impl SqliteStorage {
Ok(v) Ok(v)
})? })?
.next() .next()
.ok_or_else(|| AnkiError::DbError { .ok_or_else(|| AnkiError::db_error("col table empty", DbErrorKind::MissingEntity))??;
info: "col table empty".to_string(),
kind: DbErrorKind::MissingEntity,
})??;
Ok(decks) Ok(decks)
} }

View file

@ -393,10 +393,7 @@ and ord in ",
}, },
)? )?
.next() .next()
.ok_or_else(|| AnkiError::DbError { .ok_or_else(|| AnkiError::db_error("col table empty", DbErrorKind::MissingEntity))??;
info: "col table empty".to_string(),
kind: DbErrorKind::MissingEntity,
})??;
Ok(notetypes) Ok(notetypes)
} }

View file

@ -153,10 +153,7 @@ impl SqliteStorage {
_ => None, _ => None,
}; };
if let Some(kind) = err { if let Some(kind) = err {
return Err(AnkiError::DbError { return Err(AnkiError::db_error("", kind));
info: "".to_string(),
kind,
});
} }
let upgrade = ver != SCHEMA_MAX_VERSION; let upgrade = ver != SCHEMA_MAX_VERSION;