kanban_persistence/
error.rs1use thiserror::Error;
2
3#[derive(Error, Debug)]
4pub enum PersistenceError {
5 #[error("IO error: {0}")]
6 Io(#[from] std::io::Error),
7
8 #[error("serialization error: {0}")]
9 Serialization(String),
10
11 #[error("database error: {0}")]
12 Database(String),
13
14 #[error("unsupported storage locator {locator:?}; supported: {}", supported.join(", "))]
15 UnsupportedLocator {
16 locator: String,
17 supported: Vec<String>,
18 },
19
20 #[error("file conflict: {path} was modified by another instance")]
21 ConflictDetected {
22 path: String,
23 #[source]
24 source: Option<Box<dyn std::error::Error + Send + Sync>>,
25 },
26
27 #[error("unsupported operation: {0}")]
28 Unsupported(String),
29
30 #[error(
31 "file format v{file_version} is newer than this binary's max v{binary_max}; \
32 please upgrade kanban"
33 )]
34 UnsupportedFutureVersion { file_version: u32, binary_max: u32 },
35}
36
37pub type PersistenceResult<T> = Result<T, PersistenceError>;
38
39impl From<PersistenceError> for kanban_domain::KanbanError {
40 fn from(e: PersistenceError) -> Self {
41 match e {
42 PersistenceError::Io(io) => kanban_domain::KanbanError::Io(io),
43 PersistenceError::Serialization(s) => kanban_domain::KanbanError::Serialization(s),
44 PersistenceError::Database(s) => kanban_domain::KanbanError::Database(s),
45 PersistenceError::UnsupportedLocator { locator, supported } => {
46 kanban_domain::KanbanError::Internal(format!(
47 "No backend registered for {:?}. Available backends: {}",
48 locator,
49 if supported.is_empty() {
50 "none".to_string()
51 } else {
52 supported.join(", ")
53 }
54 ))
55 }
56 PersistenceError::ConflictDetected { path, source } => {
57 kanban_domain::KanbanError::ConflictDetected { path, source }
58 }
59 PersistenceError::Unsupported(s) => kanban_domain::KanbanError::Internal(s),
60 PersistenceError::UnsupportedFutureVersion {
61 file_version,
62 binary_max,
63 } => kanban_domain::KanbanError::UnsupportedFutureVersion {
64 file_version,
65 binary_max,
66 },
67 }
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74 use kanban_domain::KanbanError;
75
76 #[test]
77 fn test_unsupported_future_version_display_mentions_both_versions() {
78 let err = PersistenceError::UnsupportedFutureVersion {
79 file_version: 99,
80 binary_max: 6,
81 };
82 let msg = err.to_string();
83 assert!(msg.contains("99"), "msg: {msg}");
84 assert!(msg.contains('6'), "msg: {msg}");
85 }
86
87 #[test]
88 fn test_persistence_unsupported_future_version_maps_to_kanban_error() {
89 let pe = PersistenceError::UnsupportedFutureVersion {
90 file_version: 99,
91 binary_max: 6,
92 };
93 let ke: KanbanError = pe.into();
94 assert!(
95 matches!(
96 ke,
97 KanbanError::UnsupportedFutureVersion {
98 file_version: 99,
99 binary_max: 6
100 }
101 ),
102 "expected UnsupportedFutureVersion variant"
103 );
104 }
105}