Skip to main content

miden_node_db/
errors.rs

1use std::any::type_name;
2use std::io;
3
4use deadpool_sync::InteractError;
5use thiserror::Error;
6
7// SCHEMA VERIFICATION ERROR
8// =================================================================================================
9
10/// Errors that can occur during schema verification.
11#[derive(Debug, Error)]
12pub enum SchemaVerificationError {
13    #[error("failed to create in-memory reference database")]
14    InMemoryDbCreation(#[source] diesel::ConnectionError),
15    #[error("failed to apply migrations to reference database")]
16    MigrationApplication(#[source] Box<dyn std::error::Error + Send + Sync + 'static>),
17    #[error("failed to extract schema from database")]
18    SchemaExtraction(#[source] diesel::result::Error),
19    #[error(
20        "schema mismatch: expected {expected_count} objects, found {actual_count} \
21         ({missing_count} missing, {extra_count} unexpected)"
22    )]
23    Mismatch {
24        expected_count: usize,
25        actual_count: usize,
26        missing_count: usize,
27        extra_count: usize,
28    },
29}
30
31// DATABASE ERROR
32// =================================================================================================
33
34#[derive(Debug, Error)]
35pub enum DatabaseError {
36    #[error("SQLite pool interaction failed: {0}")]
37    InteractError(String),
38    #[error("setup deadpool connection pool failed")]
39    ConnectionPoolObtainError(#[from] Box<dyn std::error::Error + Send + Sync + 'static>),
40    #[error("conversion from SQL to rust type {to} failed")]
41    ConversionSqlToRust {
42        #[source]
43        inner: Option<Box<dyn std::error::Error + Send + Sync + 'static>>,
44        to: &'static str,
45    },
46    #[error(transparent)]
47    Diesel(#[from] diesel::result::Error),
48    #[error(transparent)]
49    Rusqlite(#[from] rusqlite::Error),
50    #[error("failed to apply database migrations")]
51    Migration(#[source] Box<dyn std::error::Error + Send + Sync + 'static>),
52    #[error("schema verification failed")]
53    SchemaVerification(#[from] SchemaVerificationError),
54    #[error("I/O error")]
55    Io(#[from] io::Error),
56    #[error("pool build error")]
57    PoolBuild(#[from] deadpool::managed::BuildError),
58    #[error("Setup deadpool connection pool failed")]
59    Pool(#[from] deadpool::managed::PoolError<deadpool_diesel::Error>),
60}
61
62impl DatabaseError {
63    /// Converts from `InteractError`
64    ///
65    /// Note: Required since `InteractError` has at least one enum
66    /// variant that is _not_ `Send + Sync` and hence prevents the
67    /// `Sync` auto implementation.
68    /// This does an internal conversion to string while maintaining
69    /// convenience.
70    ///
71    /// Using `MSG` as const so it can be called as
72    /// `.map_err(DatabaseError::interact::<"Your message">)`
73    pub fn interact(msg: &(impl ToString + ?Sized), e: &InteractError) -> Self {
74        let msg = msg.to_string();
75        Self::InteractError(format!("{msg} failed: {e:?}"))
76    }
77
78    /// Creates a database migration error with the original source error.
79    pub fn migration(
80        source: impl Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
81    ) -> Self {
82        Self::Migration(source.into())
83    }
84
85    /// Failed to convert an SQL entry to a rust representation
86    pub fn conversiont_from_sql<RT, E, MaybeE>(err: MaybeE) -> DatabaseError
87    where
88        MaybeE: Into<Option<E>>,
89        E: std::error::Error + Send + Sync + 'static,
90    {
91        DatabaseError::ConversionSqlToRust {
92            inner: err.into().map(|err| Box::new(err) as Box<dyn std::error::Error + Send + Sync>),
93            to: type_name::<RT>(),
94        }
95    }
96
97    /// Creates a deserialization error with a static context string and the original error.
98    ///
99    /// This is a convenience wrapper around [`ConversionSqlToRust`](Self::ConversionSqlToRust).
100    pub fn deserialization(
101        context: &'static str,
102        source: impl std::error::Error + Send + Sync + 'static,
103    ) -> Self {
104        Self::ConversionSqlToRust {
105            inner: Some(Box::new(source)),
106            to: context,
107        }
108    }
109}