Skip to main content

sz_orm_core/
graph_adapter.rs

1//! # Graph Adapter — sz-orm-core 图数据库适配层
2//!
3//! v5.0.0:将 sz-orm-graph 的 InMemoryGraphEngine 接入 sz-orm-core,
4//! 提供 `graph_query` / `graph_add_node` / `graph_add_relationship` 三个入口,
5//! 使图数据库能力从"幻影交付"变为"生产可达"。
6//!
7//! ## 设计
8//!
9//! - 全局引擎:`OnceLock<parking_lot::RwLock<InMemoryGraphEngine>>`
10//! - 首次调用时惰性初始化空引擎
11//! - 读操作(graph_query)取读锁,写操作(add_node/add_relationship)取写锁
12//! - Cypher 参数化校验由 sz-orm-graph::CypherValidator 负责
13
14use std::sync::OnceLock;
15
16use parking_lot::RwLock;
17use sz_orm_graph::{CypherQuery, GraphNode, GraphRelationship, GraphResult, InMemoryGraphEngine};
18
19static GRAPH_ENGINE: OnceLock<RwLock<InMemoryGraphEngine>> = OnceLock::new();
20
21fn engine() -> &'static RwLock<InMemoryGraphEngine> {
22    GRAPH_ENGINE.get_or_init(|| RwLock::new(InMemoryGraphEngine::new()))
23}
24
25/// 执行 Cypher 查询(只读)
26///
27/// 内部取读锁,调用 `InMemoryGraphEngine::execute`。
28/// Cypher 参数化校验由引擎内部完成。
29pub fn graph_query(query: &CypherQuery) -> Result<Vec<GraphResult>, sz_orm_graph::GraphError> {
30    let engine = engine().read();
31    engine.execute(query)
32}
33
34/// 添加节点(写操作)
35///
36/// 内部取写锁,调用 `InMemoryGraphEngine::add_node`。
37pub fn graph_add_node(node: GraphNode) -> Result<(), sz_orm_graph::GraphError> {
38    let mut engine = engine().write();
39    engine.add_node(node)
40}
41
42/// 添加关系(写操作)
43///
44/// 内部取写锁,调用 `InMemoryGraphEngine::add_relationship`。
45pub fn graph_add_relationship(rel: GraphRelationship) -> Result<(), sz_orm_graph::GraphError> {
46    let mut engine = engine().write();
47    engine.add_relationship(rel)
48}
49
50/// 获取当前引擎中的查询计数(用于测试验证真实执行)
51pub fn graph_query_count() -> u64 {
52    let engine = engine().read();
53    engine.query_count()
54}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59
60    #[test]
61    fn test_graph_add_and_query() {
62        let node = GraphNode {
63            id: "1".into(),
64            labels: vec!["Person".into()],
65            properties: serde_json::json!({"name": "Alice"}),
66        };
67        graph_add_node(node).unwrap();
68
69        let q = CypherQuery::new("MATCH (n:Person) RETURN n");
70        let result = graph_query(&q).unwrap();
71        assert!(!result.is_empty());
72        assert!(result[0].as_node().is_some());
73    }
74
75    #[test]
76    fn test_graph_query_count_increments() {
77        let before = graph_query_count();
78        let q = CypherQuery::new("MATCH (n:Person) RETURN n");
79        let _ = graph_query(&q).unwrap();
80        let after = graph_query_count();
81        assert!(after > before);
82    }
83}