parsql_migrations/
error.rs1use thiserror::Error;
4
5#[derive(Debug, Error)]
7pub enum MigrationError {
8 #[error("Database error: {0}")]
10 DatabaseError(String),
11
12 #[error("Migration {0} has already been applied")]
14 AlreadyApplied(i64),
15
16 #[error("Migration {0} not found")]
18 NotFound(i64),
19
20 #[error("Checksum mismatch for migration {version}: expected {expected}, got {actual}")]
22 ChecksumMismatch {
23 version: i64,
25 expected: String,
27 actual: String,
29 },
30
31 #[error("Failed to acquire migration lock: {0}")]
33 LockError(String),
34
35 #[error("Migration {0} is in a failed state and must be resolved manually")]
37 FailedState(i64),
38
39 #[error("Invalid migration version: {0}")]
41 InvalidVersion(i64),
42
43 #[error("Migration gap detected: missing version {0}")]
45 MigrationGap(i64),
46
47 #[error("IO error: {0}")]
49 IoError(#[from] std::io::Error),
50
51 #[error("Serialization error: {0}")]
53 SerializationError(#[from] serde_json::Error),
54
55 #[error("{0}")]
57 Custom(String),
58}
59
60impl MigrationError {
61 pub fn database<S: Into<String>>(msg: S) -> Self {
63 Self::DatabaseError(msg.into())
64 }
65
66 pub fn custom<S: Into<String>>(msg: S) -> Self {
68 Self::Custom(msg.into())
69 }
70}
71
72pub type Result<T> = std::result::Result<T, MigrationError>;
74
75#[cfg(any(feature = "postgres", feature = "tokio-postgres"))]
79impl From<postgres::Error> for MigrationError {
80 fn from(err: postgres::Error) -> Self {
81 Self::DatabaseError(err.to_string())
82 }
83}
84
85#[cfg(feature = "sqlite")]
86impl From<rusqlite::Error> for MigrationError {
87 fn from(err: rusqlite::Error) -> Self {
88 Self::DatabaseError(err.to_string())
89 }
90}
91
92#[cfg(feature = "deadpool-postgres")]
93impl From<deadpool_postgres::PoolError> for MigrationError {
94 fn from(err: deadpool_postgres::PoolError) -> Self {
95 Self::DatabaseError(format!("Connection pool error: {}", err))
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102
103 #[test]
104 fn test_error_display() {
105 let err = MigrationError::AlreadyApplied(1);
106 assert_eq!(err.to_string(), "Migration 1 has already been applied");
107
108 let err = MigrationError::ChecksumMismatch {
109 version: 2,
110 expected: "abc123".to_string(),
111 actual: "def456".to_string(),
112 };
113 assert_eq!(
114 err.to_string(),
115 "Checksum mismatch for migration 2: expected abc123, got def456"
116 );
117 }
118
119 #[test]
120 fn test_custom_errors() {
121 let err = MigrationError::database("connection failed");
122 assert_eq!(err.to_string(), "Database error: connection failed");
123
124 let err = MigrationError::custom("something went wrong");
125 assert_eq!(err.to_string(), "something went wrong");
126 }
127}