use crate::error::GraphError;
use crate::query::{GraphNode, GraphRelationship, GraphResult};
use serde::de::DeserializeOwned;
pub struct ResultMapper;
impl ResultMapper {
pub fn map_to<T: DeserializeOwned>(results: &[GraphResult]) -> Result<Vec<T>, GraphError> {
let values: Vec<serde_json::Value> = results.iter().map(Self::result_to_json).collect();
serde_json::from_value(serde_json::Value::Array(values))
.map_err(|e| GraphError::MappingError(format!("deserialization failed: {}", e)))
}
fn result_to_json(result: &GraphResult) -> serde_json::Value {
match result {
GraphResult::Node { node } => node.properties.clone(),
GraphResult::Relationship { relationship } => relationship.properties.clone(),
GraphResult::Path { path } => {
serde_json::to_value(path).unwrap_or(serde_json::Value::Null)
}
GraphResult::Scalar { value } => value.clone(),
}
}
}
pub struct NodeMapper;
impl NodeMapper {
pub fn extract_nodes(results: &[GraphResult]) -> Vec<&GraphNode> {
results.iter().filter_map(|r| r.as_node()).collect()
}
pub fn map_node<T: DeserializeOwned>(node: &GraphNode) -> Result<T, GraphError> {
serde_json::from_value(node.properties.clone()).map_err(|e| {
GraphError::MappingError(format!(
"node mapping failed: {} (missing field or type mismatch)",
e
))
})
}
}
pub struct RelationMapper;
impl RelationMapper {
pub fn extract_relationships(results: &[GraphResult]) -> Vec<&GraphRelationship> {
results.iter().filter_map(|r| r.as_relationship()).collect()
}
pub fn map_relationship<T: DeserializeOwned>(rel: &GraphRelationship) -> Result<T, GraphError> {
serde_json::from_value(rel.properties.clone()).map_err(|e| {
GraphError::MappingError(format!(
"relationship mapping failed: {} (missing field or type mismatch)",
e
))
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde::Deserialize;
#[derive(Debug, Deserialize)]
struct Person {
name: String,
age: i64,
}
#[test]
fn test_node_mapping() {
let node = GraphNode {
id: "1".into(),
labels: vec!["Person".into()],
properties: serde_json::json!({"name": "Alice", "age": 30}),
};
let result = GraphResult::Node { node };
let mapped: Vec<Person> = ResultMapper::map_to(&[result]).unwrap();
assert_eq!(mapped.len(), 1);
assert_eq!(mapped[0].name, "Alice");
assert_eq!(mapped[0].age, 30);
}
#[test]
fn test_mapping_error_on_missing_field() {
let node = GraphNode {
id: "1".into(),
labels: vec!["Person".into()],
properties: serde_json::json!({"name": "Alice"}),
};
let result = GraphResult::Node { node };
let mapped: Result<Vec<Person>, _> = ResultMapper::map_to(&[result]);
assert!(mapped.is_err());
let err = mapped.unwrap_err();
assert!(err.to_string().contains("mapping"));
}
}