mixtape_tools/sqlite/
error.rs1use mixtape_core::ToolError;
4use std::path::PathBuf;
5use thiserror::Error;
6
7#[derive(Debug, Error)]
9pub enum SqliteToolError {
10 #[error("Database not found: {0}")]
12 DatabaseNotFound(String),
13
14 #[error("No default database set. Open a database first or specify one explicitly.")]
16 NoDefaultDatabase,
17
18 #[error("Failed to connect to database '{path}': {message}")]
20 ConnectionFailed { path: PathBuf, message: String },
21
22 #[error("Database does not exist: {0}")]
24 DatabaseDoesNotExist(PathBuf),
25
26 #[error("Query error: {0}")]
28 QueryError(String),
29
30 #[error("Invalid query: {0}")]
32 InvalidQuery(String),
33
34 #[error("Transaction error: {0}")]
36 TransactionError(String),
37
38 #[error("Path error: {0}")]
40 PathError(String),
41
42 #[error("Serialization error: {0}")]
44 SerializationError(String),
45
46 #[error("Table not found: {0}")]
48 TableNotFound(String),
49
50 #[error("Migration not found: {0}")]
52 MigrationNotFound(String),
53
54 #[error("Migration checksum mismatch for '{version}': expected {expected}, got {actual}")]
56 MigrationChecksumMismatch {
57 version: String,
58 expected: String,
59 actual: String,
60 },
61
62 #[error("SQLite error: {0}")]
64 Sqlite(#[from] rusqlite::Error),
65
66 #[error("IO error: {0}")]
68 Io(#[from] std::io::Error),
69}
70
71impl From<SqliteToolError> for ToolError {
72 fn from(err: SqliteToolError) -> Self {
73 ToolError::Custom(err.to_string())
74 }
75}
76
77impl From<serde_json::Error> for SqliteToolError {
78 fn from(err: serde_json::Error) -> Self {
79 SqliteToolError::SerializationError(err.to_string())
80 }
81}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86
87 #[test]
88 fn test_database_not_found_display() {
89 let err = SqliteToolError::DatabaseNotFound("test.db".to_string());
90 assert_eq!(err.to_string(), "Database not found: test.db");
91 }
92
93 #[test]
94 fn test_no_default_database_display() {
95 let err = SqliteToolError::NoDefaultDatabase;
96 assert!(err.to_string().contains("No default database set"));
97 }
98
99 #[test]
100 fn test_connection_failed_display() {
101 let err = SqliteToolError::ConnectionFailed {
102 path: PathBuf::from("/tmp/test.db"),
103 message: "permission denied".to_string(),
104 };
105 let msg = err.to_string();
106 assert!(msg.contains("/tmp/test.db"));
107 assert!(msg.contains("permission denied"));
108 }
109
110 #[test]
111 fn test_database_does_not_exist_display() {
112 let err = SqliteToolError::DatabaseDoesNotExist(PathBuf::from("/missing.db"));
113 assert!(err.to_string().contains("/missing.db"));
114 }
115
116 #[test]
117 fn test_query_error_display() {
118 let err = SqliteToolError::QueryError("syntax error".to_string());
119 assert_eq!(err.to_string(), "Query error: syntax error");
120 }
121
122 #[test]
123 fn test_invalid_query_display() {
124 let err = SqliteToolError::InvalidQuery("SELECT not allowed".to_string());
125 assert_eq!(err.to_string(), "Invalid query: SELECT not allowed");
126 }
127
128 #[test]
129 fn test_transaction_error_display() {
130 let err = SqliteToolError::TransactionError("no active transaction".to_string());
131 assert_eq!(err.to_string(), "Transaction error: no active transaction");
132 }
133
134 #[test]
135 fn test_path_error_display() {
136 let err = SqliteToolError::PathError("invalid path".to_string());
137 assert_eq!(err.to_string(), "Path error: invalid path");
138 }
139
140 #[test]
141 fn test_serialization_error_display() {
142 let err = SqliteToolError::SerializationError("invalid JSON".to_string());
143 assert_eq!(err.to_string(), "Serialization error: invalid JSON");
144 }
145
146 #[test]
147 fn test_table_not_found_display() {
148 let err = SqliteToolError::TableNotFound("users".to_string());
149 assert_eq!(err.to_string(), "Table not found: users");
150 }
151
152 #[test]
153 fn test_from_sqlite_error() {
154 let conn = rusqlite::Connection::open_in_memory().unwrap();
156 let sqlite_err = conn.prepare("INVALID SQL SYNTAX").unwrap_err();
157 let err: SqliteToolError = sqlite_err.into();
158 assert!(err.to_string().contains("SQLite error"));
159 }
160
161 #[test]
162 fn test_from_io_error() {
163 let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
164 let err: SqliteToolError = io_err.into();
165 assert!(err.to_string().contains("IO error"));
166 assert!(err.to_string().contains("file not found"));
167 }
168
169 #[test]
170 fn test_from_serde_json_error() {
171 let json_err = serde_json::from_str::<serde_json::Value>("invalid json").unwrap_err();
172 let err: SqliteToolError = json_err.into();
173 assert!(err.to_string().contains("Serialization error"));
174 }
175
176 #[test]
177 fn test_into_tool_error() {
178 let err = SqliteToolError::DatabaseNotFound("test.db".to_string());
179 let tool_err: ToolError = err.into();
180 match tool_err {
181 ToolError::Custom(msg) => assert!(msg.contains("test.db")),
182 _ => panic!("Expected ToolError::Custom"),
183 }
184 }
185}