mirror of
https://github.com/ankitects/anki.git
synced 2025-09-24 16:56:36 -04:00
switch DbError to tuple type
This commit is contained in:
parent
1704f7fe80
commit
a250464309
8 changed files with 59 additions and 46 deletions
|
@ -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;
|
||||||
|
|
|
@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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(¬e.notetype_id).ok_or_else(|| {
|
||||||
.get(¬e.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,
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue