1use std::any::type_name;
2use std::io;
3
4use deadpool_sync::InteractError;
5use thiserror::Error;
6
7#[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#[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 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 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 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 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}