1#[derive(thiserror::Error, Debug)]
5pub enum CypherLiteError {
6 #[error("I/O error: {0}")]
8 IoError(#[from] std::io::Error),
9
10 #[error("Corrupted page {page_id}: {reason}")]
12 CorruptedPage {
13 page_id: u32,
15 reason: String,
17 },
18
19 #[error("Transaction conflict: write lock unavailable")]
21 TransactionConflict,
22
23 #[error("Out of space: buffer pool or disk full")]
25 OutOfSpace,
26
27 #[error("Invalid magic number")]
29 InvalidMagicNumber,
30
31 #[error("Unsupported version: found {found}, supported {supported}")]
33 UnsupportedVersion {
34 found: u32,
36 supported: u32,
38 },
39
40 #[error("Checksum mismatch: expected {expected}, found {found}")]
42 ChecksumMismatch {
43 expected: u64,
45 found: u64,
47 },
48
49 #[error("Serialization error: {0}")]
51 SerializationError(String),
52
53 #[error("Node not found: {0}")]
55 NodeNotFound(u64),
56
57 #[error("Edge not found: {0}")]
59 EdgeNotFound(u64),
60
61 #[error("Parse error at line {line}, column {column}: {message}")]
63 ParseError {
64 line: usize,
66 column: usize,
68 message: String,
70 },
71
72 #[error("Semantic error: {0}")]
74 SemanticError(String),
75
76 #[error("Execution error: {0}")]
78 ExecutionError(String),
79
80 #[error("Unsupported syntax: {0}")]
82 UnsupportedSyntax(String),
83
84 #[error("Constraint violation: {0}")]
86 ConstraintViolation(String),
87
88 #[error("Invalid datetime format: {0}")]
90 InvalidDateTimeFormat(String),
91
92 #[error("System property is read-only: {0}")]
94 SystemPropertyReadOnly(String),
95
96 #[error("Database is locked: {0}")]
98 DatabaseLocked(String),
99
100 #[error("Feature incompatible: database requires flags 0x{db_flags:08X}, compiled with 0x{compiled_flags:08X}")]
102 FeatureIncompatible {
103 db_flags: u32,
105 compiled_flags: u32,
107 },
108
109 #[cfg(feature = "subgraph")]
111 #[error("Subgraph not found: {0}")]
112 SubgraphNotFound(u64),
113
114 #[cfg(feature = "subgraph")]
116 #[error("Feature requires subgraph support (compile with --features subgraph)")]
117 FeatureRequiresSubgraph,
118
119 #[cfg(feature = "hypergraph")]
121 #[error("Hyperedge not found: {0}")]
122 HyperEdgeNotFound(u64),
123
124 #[cfg(feature = "plugin")]
126 #[error("Plugin error: {0}")]
127 PluginError(String),
128
129 #[cfg(feature = "plugin")]
131 #[error("Function not found: {0}")]
132 FunctionNotFound(String),
133
134 #[cfg(feature = "plugin")]
136 #[error("Unsupported index type: {0}")]
137 UnsupportedIndexType(String),
138
139 #[cfg(feature = "plugin")]
141 #[error("Unsupported format: {0}")]
142 UnsupportedFormat(String),
143
144 #[cfg(feature = "plugin")]
146 #[error("Trigger error: {0}")]
147 TriggerError(String),
148}
149
150pub type Result<T> = std::result::Result<T, CypherLiteError>;
152
153#[cfg(test)]
154mod tests {
155 use super::*;
156
157 #[test]
159 fn test_invalid_magic_number_error() {
160 let err = CypherLiteError::InvalidMagicNumber;
161 assert_eq!(format!("{err}"), "Invalid magic number");
162 }
163
164 #[test]
166 fn test_unsupported_version_error() {
167 let err = CypherLiteError::UnsupportedVersion {
168 found: 99,
169 supported: 1,
170 };
171 assert_eq!(
172 format!("{err}"),
173 "Unsupported version: found 99, supported 1"
174 );
175 }
176
177 #[test]
179 fn test_checksum_mismatch_error() {
180 let err = CypherLiteError::ChecksumMismatch {
181 expected: 100,
182 found: 200,
183 };
184 assert_eq!(
185 format!("{err}"),
186 "Checksum mismatch: expected 100, found 200"
187 );
188 }
189
190 #[test]
192 fn test_transaction_conflict_error() {
193 let err = CypherLiteError::TransactionConflict;
194 assert_eq!(
195 format!("{err}"),
196 "Transaction conflict: write lock unavailable"
197 );
198 }
199
200 #[test]
202 fn test_out_of_space_error() {
203 let err = CypherLiteError::OutOfSpace;
204 assert_eq!(format!("{err}"), "Out of space: buffer pool or disk full");
205 }
206
207 #[test]
208 fn test_corrupted_page_error() {
209 let err = CypherLiteError::CorruptedPage {
210 page_id: 5,
211 reason: "bad header".to_string(),
212 };
213 assert_eq!(format!("{err}"), "Corrupted page 5: bad header");
214 }
215
216 #[test]
217 fn test_io_error_conversion() {
218 let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file missing");
219 let err: CypherLiteError = io_err.into();
220 assert!(matches!(err, CypherLiteError::IoError(_)));
221 assert!(format!("{err}").contains("file missing"));
222 }
223
224 #[test]
225 fn test_error_is_send_sync() {
226 fn assert_send<T: Send>() {}
227 fn assert_sync<T: Sync>() {}
228 assert_send::<CypherLiteError>();
229 assert_sync::<CypherLiteError>();
230 }
231
232 #[test]
233 fn test_node_not_found_error() {
234 let err = CypherLiteError::NodeNotFound(42);
235 assert_eq!(format!("{err}"), "Node not found: 42");
236 }
237
238 #[test]
239 fn test_edge_not_found_error() {
240 let err = CypherLiteError::EdgeNotFound(99);
241 assert_eq!(format!("{err}"), "Edge not found: 99");
242 }
243
244 #[test]
246 fn test_parse_error() {
247 let err = CypherLiteError::ParseError {
248 line: 3,
249 column: 10,
250 message: "unexpected token".to_string(),
251 };
252 assert_eq!(
253 format!("{err}"),
254 "Parse error at line 3, column 10: unexpected token"
255 );
256 }
257
258 #[test]
260 fn test_semantic_error() {
261 let err = CypherLiteError::SemanticError("unknown label".to_string());
262 assert_eq!(format!("{err}"), "Semantic error: unknown label");
263 }
264
265 #[test]
267 fn test_execution_error() {
268 let err = CypherLiteError::ExecutionError("division by zero".to_string());
269 assert_eq!(format!("{err}"), "Execution error: division by zero");
270 }
271
272 #[test]
274 fn test_unsupported_syntax_error() {
275 let err = CypherLiteError::UnsupportedSyntax("MERGE".to_string());
276 assert_eq!(format!("{err}"), "Unsupported syntax: MERGE");
277 }
278
279 #[test]
281 fn test_constraint_violation_error() {
282 let err = CypherLiteError::ConstraintViolation("unique key violated".to_string());
283 assert_eq!(
284 format!("{err}"),
285 "Constraint violation: unique key violated"
286 );
287 }
288
289 #[test]
291 fn test_system_property_read_only_error() {
292 let err = CypherLiteError::SystemPropertyReadOnly("_created_at".to_string());
293 assert_eq!(
294 format!("{err}"),
295 "System property is read-only: _created_at"
296 );
297 }
298
299 #[test]
301 fn test_invalid_datetime_format_error() {
302 let err = CypherLiteError::InvalidDateTimeFormat("bad input".to_string());
303 assert_eq!(format!("{err}"), "Invalid datetime format: bad input");
304 }
305
306 #[test]
308 fn test_feature_incompatible_error() {
309 let err = CypherLiteError::FeatureIncompatible {
310 db_flags: 0x03,
311 compiled_flags: 0x01,
312 };
313 assert_eq!(
314 format!("{err}"),
315 "Feature incompatible: database requires flags 0x00000003, compiled with 0x00000001"
316 );
317 }
318
319 #[test]
321 fn test_database_locked_error() {
322 let err = CypherLiteError::DatabaseLocked("/tmp/test.cyl".to_string());
323 assert_eq!(format!("{err}"), "Database is locked: /tmp/test.cyl");
324 }
325
326 #[test]
327 fn test_database_locked_error_is_not_io_error() {
328 let err = CypherLiteError::DatabaseLocked("/tmp/test.cyl".to_string());
329 assert!(matches!(err, CypherLiteError::DatabaseLocked(_)));
330 }
331
332 #[cfg(feature = "subgraph")]
337 #[test]
338 fn test_subgraph_not_found_error() {
339 let err = CypherLiteError::SubgraphNotFound(42);
340 assert_eq!(format!("{err}"), "Subgraph not found: 42");
341 }
342
343 #[cfg(feature = "subgraph")]
344 #[test]
345 fn test_feature_requires_subgraph_error() {
346 let err = CypherLiteError::FeatureRequiresSubgraph;
347 assert_eq!(
348 format!("{err}"),
349 "Feature requires subgraph support (compile with --features subgraph)"
350 );
351 }
352}