1use std::fmt;

What can go wrong with the database. What the adapters report to their ports is only a sentence for the log (the ports' own errors say whether to retry); this keeps the cause.

5#[derive(Debug)]
6pub enum DbError {

SQLite refused or failed.

8    Sqlite(rusqlite::Error),

The database was written by a newer build than this one.

10    Newer { found: u32, known: u32 },

Something another connection holds stopped a checkpoint.

12    Busy,

What is stored does not read back as what it should be.

14    Damaged(String),
15}
17impl fmt::Display for DbError {
18    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19        match self {
20            DbError::Sqlite(e) => write!(f, "database error: {e}"),
21            DbError::Newer { found, known } => write!(f, "the database is at version {found}, newer than this build's {known}"),
22            DbError::Busy => write!(f, "the database is busy"),
23            DbError::Damaged(what) => write!(f, "the database is damaged: {what}"),
24        }
25    }
26}
27
28impl DbError {

Whether what is stored is not a database at all, or is broken beyond reading: the file is damaged and not merely busy, full or from a newer build.

31    pub fn is_unreadable(&self) -> bool {
32        match self {
33            DbError::Sqlite(rusqlite::Error::SqliteFailure(e, _)) => matches!(e.code, rusqlite::ErrorCode::NotADatabase | rusqlite::ErrorCode::DatabaseCorrupt),
34            DbError::Damaged(_) => true,
35            _ => false,
36        }
37    }

Whether the database was written by a newer build.

40    pub fn is_newer(&self) -> bool {
41        matches!(self, DbError::Newer { .. })
42    }
43}
45impl std::error::Error for DbError {}
46
47impl From<rusqlite::Error> for DbError {
48    fn from(e: rusqlite::Error) -> Self {
49        DbError::Sqlite(e)
50    }
51}