Skip to main content

sz_orm_graph/
mapping.rs

1//! # Mapping — 结果类型化映射
2//!
3//! ResultMapper + NodeMapper + RelationMapper
4
5use crate::error::GraphError;
6use crate::query::{GraphNode, GraphRelationship, GraphResult};
7use serde::de::DeserializeOwned;
8
9/// 结果映射器
10pub struct ResultMapper;
11
12impl ResultMapper {
13    /// 将 GraphResult 列表反序列化到用户结构
14    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    /// 将单个 GraphResult 转为 JSON Value
21    ///
22    /// 对于 Node/Relationship,返回 properties 字段(用户通常需要属性而非元数据)。
23    /// 对于 Scalar,直接返回值。
24    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
36/// 节点映射器
37pub struct NodeMapper;
38
39impl NodeMapper {
40    /// 从结果列表提取所有节点
41    pub fn extract_nodes(results: &[GraphResult]) -> Vec<&GraphNode> {
42        results.iter().filter_map(|r| r.as_node()).collect()
43    }
44
45    /// 将节点属性反序列化到用户结构
46    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
56/// 关系映射器
57pub struct RelationMapper;
58
59impl RelationMapper {
60    /// 从结果列表提取所有关系
61    pub fn extract_relationships(results: &[GraphResult]) -> Vec<&GraphRelationship> {
62        results.iter().filter_map(|r| r.as_relationship()).collect()
63    }
64
65    /// 将关系属性反序列化到用户结构
66    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}