1use crate::error::GraphError;
6use crate::query::{GraphNode, GraphRelationship, GraphResult};
7use serde::de::DeserializeOwned;
8
9pub struct ResultMapper;
11
12impl ResultMapper {
13 pub fn map_to<T: DeserializeOwned>(results: &[GraphResult]) -> Result<Vec<T>, GraphError> {
15 let values: Vec<serde_json::Value> = results.iter().map(Self::result_to_json).collect();
16 serde_json::from_value(serde_json::Value::Array(values))
17 .map_err(|e| GraphError::MappingError(format!("deserialization failed: {}", e)))
18 }
19
20 fn result_to_json(result: &GraphResult) -> serde_json::Value {
25 match result {
26 GraphResult::Node { node } => node.properties.clone(),
27 GraphResult::Relationship { relationship } => relationship.properties.clone(),
28 GraphResult::Path { path } => {
29 serde_json::to_value(path).unwrap_or(serde_json::Value::Null)
30 }
31 GraphResult::Scalar { value } => value.clone(),
32 }
33 }
34}
35
36pub struct NodeMapper;
38
39impl NodeMapper {
40 pub fn extract_nodes(results: &[GraphResult]) -> Vec<&GraphNode> {
42 results.iter().filter_map(|r| r.as_node()).collect()
43 }
44
45 pub fn map_node<T: DeserializeOwned>(node: &GraphNode) -> Result<T, GraphError> {
47 serde_json::from_value(node.properties.clone()).map_err(|e| {
48 GraphError::MappingError(format!(
49 "node mapping failed: {} (missing field or type mismatch)",
50 e
51 ))
52 })
53 }
54}
55
56pub struct RelationMapper;
58
59impl RelationMapper {
60 pub fn extract_relationships(results: &[GraphResult]) -> Vec<&GraphRelationship> {
62 results.iter().filter_map(|r| r.as_relationship()).collect()
63 }
64
65 pub fn map_relationship<T: DeserializeOwned>(rel: &GraphRelationship) -> Result<T, GraphError> {
67 serde_json::from_value(rel.properties.clone()).map_err(|e| {
68 GraphError::MappingError(format!(
69 "relationship mapping failed: {} (missing field or type mismatch)",
70 e
71 ))
72 })
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79 use serde::Deserialize;
80
81 #[derive(Debug, Deserialize)]
82 struct Person {
83 name: String,
84 age: i64,
85 }
86
87 #[test]
88 fn test_node_mapping() {
89 let node = GraphNode {
90 id: "1".into(),
91 labels: vec!["Person".into()],
92 properties: serde_json::json!({"name": "Alice", "age": 30}),
93 };
94 let result = GraphResult::Node { node };
95 let mapped: Vec<Person> = ResultMapper::map_to(&[result]).unwrap();
96 assert_eq!(mapped.len(), 1);
97 assert_eq!(mapped[0].name, "Alice");
98 assert_eq!(mapped[0].age, 30);
99 }
100
101 #[test]
102 fn test_mapping_error_on_missing_field() {
103 let node = GraphNode {
104 id: "1".into(),
105 labels: vec!["Person".into()],
106 properties: serde_json::json!({"name": "Alice"}),
107 };
108 let result = GraphResult::Node { node };
109 let mapped: Result<Vec<Person>, _> = ResultMapper::map_to(&[result]);
110 assert!(mapped.is_err());
111 let err = mapped.unwrap_err();
112 assert!(err.to_string().contains("mapping"));
113 }
114
115 #[test]
116 fn test_node_mapper_extract_and_map() {
117 let node1 = GraphNode {
118 id: "1".into(),
119 labels: vec!["Person".into()],
120 properties: serde_json::json!({"name": "Alice", "age": 30}),
121 };
122 let node2 = GraphNode {
123 id: "2".into(),
124 labels: vec!["Person".into()],
125 properties: serde_json::json!({"name": "Bob", "age": 25}),
126 };
127 let results = vec![
128 GraphResult::Node { node: node1 },
129 GraphResult::Node { node: node2 },
130 ];
131 let extracted = NodeMapper::extract_nodes(&results);
132 assert_eq!(extracted.len(), 2);
133 let mapped: Person = NodeMapper::map_node(extracted[0]).unwrap();
134 assert_eq!(mapped.name, "Alice");
135 }
136
137 #[test]
138 fn test_relation_mapper_extract_and_map() {
139 let rel = GraphRelationship {
140 id: "r1".into(),
141 rel_type: "KNOWS".into(),
142 start_node_id: "1".into(),
143 end_node_id: "2".into(),
144 properties: serde_json::json!({"name": "Alice", "age": 30}),
145 };
146 let results = vec![GraphResult::Relationship { relationship: rel }];
147 let extracted = RelationMapper::extract_relationships(&results);
148 assert_eq!(extracted.len(), 1);
149 let mapped: Person = RelationMapper::map_relationship(extracted[0]).unwrap();
150 assert_eq!(mapped.name, "Alice");
151 assert_eq!(mapped.age, 30);
152 }
153
154 #[test]
155 fn test_result_mapper_scalar() {
156 let results = vec![
157 GraphResult::Scalar {
158 value: serde_json::json!(1),
159 },
160 GraphResult::Scalar {
161 value: serde_json::json!(2),
162 },
163 ];
164 let mapped: Vec<i64> = ResultMapper::map_to(&results).unwrap();
165 assert_eq!(mapped, vec![1, 2]);
166 }
167}