codegraph/
error.rs

1//! Error types for codegraph operations.
2//!
3//! All fallible operations return [`Result<T>`] with context-rich error messages.
4
5use std::path::PathBuf;
6use thiserror::Error;
7
8/// Result type alias for codegraph operations.
9pub type Result<T> = std::result::Result<T, GraphError>;
10
11/// Comprehensive error type for all graph operations.
12///
13/// Errors are designed to fail fast and provide clear context about what went wrong.
14#[derive(Error, Debug)]
15pub enum GraphError {
16    /// Storage backend error (RocksDB, file I/O, etc.)
17    #[error("Storage error: {message}")]
18    Storage {
19        /// Detailed error message
20        message: String,
21        /// Optional source error
22        #[source]
23        source: Option<Box<dyn std::error::Error + Send + Sync>>,
24    },
25
26    /// Node not found in the graph
27    #[error("Node not found: {node_id}")]
28    NodeNotFound {
29        /// ID of the missing node
30        node_id: String,
31    },
32
33    /// Edge not found in the graph
34    #[error("Edge not found: {edge_id}")]
35    EdgeNotFound {
36        /// ID of the missing edge
37        edge_id: String,
38    },
39
40    /// File not found in the graph
41    #[error("File not found: {path}")]
42    FileNotFound {
43        /// Path to the missing file
44        path: PathBuf,
45    },
46
47    /// Invalid operation (e.g., adding duplicate node)
48    #[error("Invalid operation: {message}")]
49    InvalidOperation {
50        /// Description of what went wrong
51        message: String,
52    },
53
54    /// Serialization/deserialization error
55    #[error("Serialization error: {message}")]
56    Serialization {
57        /// Error details
58        message: String,
59        /// Optional source error
60        #[source]
61        source: Option<Box<dyn std::error::Error + Send + Sync>>,
62    },
63
64    /// Property not found
65    #[error("Property '{key}' not found on {entity_type} {entity_id}")]
66    PropertyNotFound {
67        /// Entity type (node, edge, etc.)
68        entity_type: String,
69        /// Entity identifier
70        entity_id: String,
71        /// Property key that was missing
72        key: String,
73    },
74
75    /// Type mismatch when retrieving property
76    #[error("Property type mismatch: expected {expected}, got {actual} for key '{key}'")]
77    PropertyTypeMismatch {
78        /// Property key
79        key: String,
80        /// Expected type
81        expected: String,
82        /// Actual type found
83        actual: String,
84    },
85}
86
87impl GraphError {
88    /// Create a storage error from a message and optional source.
89    pub fn storage<E>(message: impl Into<String>, source: Option<E>) -> Self
90    where
91        E: std::error::Error + Send + Sync + 'static,
92    {
93        Self::Storage {
94            message: message.into(),
95            source: source.map(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>),
96        }
97    }
98
99    /// Create a serialization error from a message and optional source.
100    pub fn serialization<E>(message: impl Into<String>, source: Option<E>) -> Self
101    where
102        E: std::error::Error + Send + Sync + 'static,
103    {
104        Self::Serialization {
105            message: message.into(),
106            source: source.map(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>),
107        }
108    }
109}
110
111#[cfg(test)]
112mod tests {
113    use super::*;
114
115    #[test]
116    fn test_node_not_found_error() {
117        let err = GraphError::NodeNotFound {
118            node_id: "test-node-123".to_string(),
119        };
120        assert_eq!(err.to_string(), "Node not found: test-node-123");
121    }
122
123    #[test]
124    fn test_storage_error() {
125        let err = GraphError::storage("Failed to write to disk", None::<std::io::Error>);
126        assert_eq!(err.to_string(), "Storage error: Failed to write to disk");
127    }
128
129    #[test]
130    fn test_invalid_operation_error() {
131        let err = GraphError::InvalidOperation {
132            message: "Cannot add duplicate node".to_string(),
133        };
134        assert_eq!(
135            err.to_string(),
136            "Invalid operation: Cannot add duplicate node"
137        );
138    }
139
140    #[test]
141    fn test_property_not_found_error() {
142        let err = GraphError::PropertyNotFound {
143            entity_type: "node".to_string(),
144            entity_id: "node-123".to_string(),
145            key: "name".to_string(),
146        };
147        assert_eq!(
148            err.to_string(),
149            "Property 'name' not found on node node-123"
150        );
151    }
152}