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 apply migrations to reference database")]
16 MigrationApplication(#[source] Box<dyn std::error::Error + Send + Sync + 'static>),
17 #[error(
18 "schema mismatch: expected {expected_count} objects, found {actual_count} \
19 ({missing_count} missing, {extra_count} unexpected)"
20 )]
21 Mismatch {
22 expected_count: usize,
23 actual_count: usize,
24 missing_count: usize,
25 extra_count: usize,
26 },
27}
28
29#[derive(Debug, Error)]
33pub enum DatabaseError {
34 #[error("SQLite pool interaction failed: {0}")]
35 InteractError(String),
36 #[error("setup deadpool connection pool failed")]
37 ConnectionPoolObtainError(#[from] Box<dyn std::error::Error + Send + Sync + 'static>),
38 #[error("conversion from SQL to rust type {to} failed")]
39 ConversionSqlToRust {
40 #[source]
41 inner: Option<Box<dyn std::error::Error + Send + Sync + 'static>>,
42 to: &'static str,
43 },
44 #[error(transparent)]
45 Rusqlite(#[from] rusqlite::Error),
46 #[error("failed to apply database migrations")]
47 Migration(#[source] Box<dyn std::error::Error + Send + Sync + 'static>),
48 #[error("schema verification failed")]
49 SchemaVerification(#[from] SchemaVerificationError),
50 #[error("I/O error")]
51 Io(#[from] io::Error),
52 #[error("pool build error")]
53 PoolBuild(#[from] deadpool::managed::BuildError),
54 #[error("failed to cast")]
55 ConversionError(#[from] DatabaseTypeConversionError),
56}
57
58impl DatabaseError {
59 pub fn interact(msg: &(impl ToString + ?Sized), e: &InteractError) -> Self {
70 let msg = msg.to_string();
71 Self::InteractError(format!("{msg} failed: {e:?}"))
72 }
73
74 pub fn migration(
76 source: impl Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
77 ) -> Self {
78 Self::Migration(source.into())
79 }
80
81 pub fn conversiont_from_sql<RT, E, MaybeE>(err: MaybeE) -> DatabaseError
83 where
84 MaybeE: Into<Option<E>>,
85 E: std::error::Error + Send + Sync + 'static,
86 {
87 DatabaseError::ConversionSqlToRust {
88 inner: err.into().map(|err| Box::new(err) as Box<dyn std::error::Error + Send + Sync>),
89 to: type_name::<RT>(),
90 }
91 }
92
93 pub fn deserialization(
97 context: &'static str,
98 source: impl std::error::Error + Send + Sync + 'static,
99 ) -> Self {
100 Self::ConversionSqlToRust {
101 inner: Some(Box::new(source)),
102 to: context,
103 }
104 }
105}