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