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("failed to apply database migrations")]
49 Migration(#[source] Box<dyn std::error::Error + Send + Sync + 'static>),
50 #[error("schema verification failed")]
51 SchemaVerification(#[from] SchemaVerificationError),
52 #[error("I/O error")]
53 Io(#[from] io::Error),
54 #[error("pool build error")]
55 PoolBuild(#[from] deadpool::managed::BuildError),
56 #[error("Setup deadpool connection pool failed")]
57 Pool(#[from] deadpool::managed::PoolError<deadpool_diesel::Error>),
58}
59
60impl DatabaseError {
61 pub fn interact(msg: &(impl ToString + ?Sized), e: &InteractError) -> Self {
72 let msg = msg.to_string();
73 Self::InteractError(format!("{msg} failed: {e:?}"))
74 }
75
76 pub fn migration(
78 source: impl Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
79 ) -> Self {
80 Self::Migration(source.into())
81 }
82
83 pub fn conversiont_from_sql<RT, E, MaybeE>(err: MaybeE) -> DatabaseError
85 where
86 MaybeE: Into<Option<E>>,
87 E: std::error::Error + Send + Sync + 'static,
88 {
89 DatabaseError::ConversionSqlToRust {
90 inner: err.into().map(|err| Box::new(err) as Box<dyn std::error::Error + Send + Sync>),
91 to: type_name::<RT>(),
92 }
93 }
94
95 pub fn deserialization(
99 context: &'static str,
100 source: impl std::error::Error + Send + Sync + 'static,
101 ) -> Self {
102 Self::ConversionSqlToRust {
103 inner: Some(Box::new(source)),
104 to: context,
105 }
106 }
107}