use std::path::PathBuf;
use thiserror::Error;
pub type Result<T> = std::result::Result<T, GraphError>;
#[derive(Error, Debug)]
pub enum GraphError {
#[error("Storage error: {message}")]
Storage {
message: String,
#[source]
source: Option<Box<dyn std::error::Error + Send + Sync>>,
},
#[error("Node not found: {node_id}")]
NodeNotFound {
node_id: String,
},
#[error("Edge not found: {edge_id}")]
EdgeNotFound {
edge_id: String,
},
#[error("File not found: {path}")]
FileNotFound {
path: PathBuf,
},
#[error("Invalid operation: {message}")]
InvalidOperation {
message: String,
},
#[error("Serialization error: {message}")]
Serialization {
message: String,
#[source]
source: Option<Box<dyn std::error::Error + Send + Sync>>,
},
#[error("Property '{key}' not found on {entity_type} {entity_id}")]
PropertyNotFound {
entity_type: String,
entity_id: String,
key: String,
},
#[error("Property type mismatch: expected {expected}, got {actual} for key '{key}'")]
PropertyTypeMismatch {
key: String,
expected: String,
actual: String,
},
}
impl GraphError {
pub fn storage<E>(message: impl Into<String>, source: Option<E>) -> Self
where
E: std::error::Error + Send + Sync + 'static,
{
Self::Storage {
message: message.into(),
source: source.map(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>),
}
}
pub fn serialization<E>(message: impl Into<String>, source: Option<E>) -> Self
where
E: std::error::Error + Send + Sync + 'static,
{
Self::Serialization {
message: message.into(),
source: source.map(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_node_not_found_error() {
let err = GraphError::NodeNotFound {
node_id: "test-node-123".to_string(),
};
assert_eq!(err.to_string(), "Node not found: test-node-123");
}
#[test]
fn test_storage_error() {
let err = GraphError::storage("Failed to write to disk", None::<std::io::Error>);
assert_eq!(err.to_string(), "Storage error: Failed to write to disk");
}
#[test]
fn test_invalid_operation_error() {
let err = GraphError::InvalidOperation {
message: "Cannot add duplicate node".to_string(),
};
assert_eq!(
err.to_string(),
"Invalid operation: Cannot add duplicate node"
);
}
#[test]
fn test_property_not_found_error() {
let err = GraphError::PropertyNotFound {
entity_type: "node".to_string(),
entity_id: "node-123".to_string(),
key: "name".to_string(),
};
assert_eq!(
err.to_string(),
"Property 'name' not found on node node-123"
);
}
}