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