1use crate::migration::{Migration, MigrationId};
3use crate::runner::{MigrationResult, Report};
4
5use std::error::Error as StdError;
6
7pub type TernResult<T> = Result<T, Error>;
9type BoxDynError = Box<dyn StdError + Send + Sync + 'static>;
10
11#[derive(Debug, thiserror::Error)]
14#[non_exhaustive]
15pub enum Error {
16 #[error("error applying migrations {0}")]
18 Execute(#[source] BoxDynError),
19 #[error("error applying migration: {{name: {1}, no_tx: {2}}}: {0}")]
21 ExecuteMigration(#[source] BoxDynError, MigrationId, bool),
22 #[error("runtime could not resolve query: {0}")]
26 ResolveQuery(String),
27 #[error("could not parse migration query: {0}")]
29 Sql(#[from] std::fmt::Error),
30 #[error("missing source: {local} migrations found but {history} have been applied: {msg}")]
32 MissingSource {
33 local: i64,
34 history: i64,
35 msg: String,
36 },
37 #[error("inconsistent source: {msg}: {at_issue:?}")]
40 OutOfSync {
41 at_issue: Vec<MigrationId>,
42 msg: String,
43 },
44 #[error("invalid parameter for the operation requested: {0}")]
46 Invalid(String),
47 #[error("migration could not complete: {source}, partial report: {report}")]
49 Partial { source: BoxDynError, report: Report },
50}
51
52impl Error {
53 pub fn to_resolve_query_error<E>(e: E) -> Self
54 where
55 E: std::fmt::Display,
56 {
57 Self::ResolveQuery(e.to_string())
58 }
59}
60
61pub trait DatabaseError<T, E> {
70 fn tern_result(self) -> TernResult<T>;
72
73 fn void_tern_result(self) -> TernResult<()>;
75
76 fn tern_migration_result<M: Migration + ?Sized>(self, migration: &M) -> TernResult<T>;
79
80 fn void_tern_migration_result<M: Migration + ?Sized>(self, migration: &M) -> TernResult<()>;
82
83 fn with_report(self, report: &[MigrationResult]) -> TernResult<T>;
86}
87
88impl<T, E> DatabaseError<T, E> for Result<T, E>
89where
90 E: StdError + Send + Sync + 'static,
91{
92 fn void_tern_result(self) -> TernResult<()> {
93 match self {
94 Err(e) => Err(Error::Execute(Box::new(e))),
95 _ => Ok(()),
96 }
97 }
98
99 fn void_tern_migration_result<M: Migration + ?Sized>(self, migration: &M) -> TernResult<()> {
100 match self {
101 Err(e) => Err(Error::ExecuteMigration(
102 Box::new(e),
103 migration.migration_id(),
104 migration.no_tx(),
105 )),
106 _ => Ok(()),
107 }
108 }
109
110 fn tern_result(self) -> TernResult<T> {
111 match self {
112 Ok(v) => Ok(v),
113 Err(e) => Err(Error::Execute(Box::new(e))),
114 }
115 }
116
117 fn tern_migration_result<M: Migration + ?Sized>(self, migration: &M) -> TernResult<T> {
118 match self {
119 Ok(v) => Ok(v),
120 Err(e) => Err(Error::ExecuteMigration(
121 Box::new(e),
122 migration.migration_id(),
123 migration.no_tx(),
124 )),
125 }
126 }
127
128 fn with_report(self, migrations: &[MigrationResult]) -> TernResult<T> {
129 match self {
130 Ok(v) => Ok(v),
131 Err(e) => Err(Error::Partial {
132 source: Box::new(e),
133 report: Report::new(migrations.to_vec()),
134 }),
135 }
136 }
137}