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::{
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;

View File

@ -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<String>, kind: DbErrorKind) -> Self {
AnkiError::DbError(DbError {
info: info.into(),
kind,
})
}
}
impl From<Error> 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<FromSqlError> for AnkiError {
fn from(err: FromSqlError) -> Self {
if let FromSqlError::Other(ref err) = err {
if let Some(_err) = err.downcast_ref::<Utf8Error>() {
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),
}
}
}

View File

@ -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<S: Into<String>>(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() {

View File

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

View File

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

View File

@ -27,9 +27,11 @@ fn row_to_deck(row: &Row) -> Result<Deck> {
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)
}

View File

@ -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)
}

View File

@ -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;