Skip to main content

reddb_server/storage/unified/dsl/builders/
graph.rs

1//! Graph traversal query builder
2//!
3//! Builder for graph pattern matching and traversal queries.
4
5use std::collections::HashMap;
6use std::sync::Arc;
7
8use crate::storage::query::unified::ExecutionError;
9use crate::storage::schema::Value;
10
11use super::super::super::entity::EntityId;
12use super::super::super::store::UnifiedStore;
13use super::super::execution::execute_graph_query;
14use super::super::filters::{Filter, FilterAcceptor, WhereClause};
15use super::super::types::QueryResult;
16
17/// Builder for graph traversal queries
18#[derive(Debug, Clone)]
19pub struct GraphQueryBuilder {
20    pub(crate) start: GraphStartPoint,
21    pub(crate) traversals: Vec<TraversalStep>,
22    pub(crate) filters: Vec<Filter>,
23    pub(crate) max_depth: u32,
24    pub(crate) ranking_vector: Option<Vec<f32>>,
25    pub(crate) limit: Option<usize>,
26}
27
28#[derive(Debug, Clone)]
29pub enum GraphStartPoint {
30    NodeLabel(String),
31    EntityId(EntityId),
32    Pattern(NodePatternDsl),
33}
34
35#[derive(Debug, Clone)]
36pub struct TraversalStep {
37    pub edge_label: Option<String>,
38    pub direction: TraversalDirection,
39    pub node_filter: Option<NodePatternDsl>,
40}
41
42#[derive(Debug, Clone, Copy)]
43pub enum TraversalDirection {
44    Out,
45    In,
46    Both,
47}
48
49#[derive(Debug, Clone, Default)]
50pub struct NodePatternDsl {
51    pub labels: Vec<String>,
52    pub properties: HashMap<String, Value>,
53}
54
55impl GraphQueryBuilder {
56    pub fn from_node(label: impl Into<String>) -> Self {
57        Self {
58            start: GraphStartPoint::NodeLabel(label.into()),
59            traversals: Vec::new(),
60            filters: Vec::new(),
61            max_depth: 3,
62            ranking_vector: None,
63            limit: None,
64        }
65    }
66
67    pub fn from_id(id: EntityId) -> Self {
68        Self {
69            start: GraphStartPoint::EntityId(id),
70            traversals: Vec::new(),
71            filters: Vec::new(),
72            max_depth: 3,
73            ranking_vector: None,
74            limit: None,
75        }
76    }
77
78    /// Traverse outgoing edges with given label
79    pub fn traverse(mut self, edge_label: impl Into<String>) -> Self {
80        self.traversals.push(TraversalStep {
81            edge_label: Some(edge_label.into()),
82            direction: TraversalDirection::Out,
83            node_filter: None,
84        });
85        self
86    }
87
88    /// Traverse outgoing edges (any label)
89    pub fn out(mut self) -> Self {
90        self.traversals.push(TraversalStep {
91            edge_label: None,
92            direction: TraversalDirection::Out,
93            node_filter: None,
94        });
95        self
96    }
97
98    /// Traverse incoming edges (any label)
99    pub fn in_(mut self) -> Self {
100        self.traversals.push(TraversalStep {
101            edge_label: None,
102            direction: TraversalDirection::In,
103            node_filter: None,
104        });
105        self
106    }
107
108    /// Traverse in both directions
109    pub fn both(mut self) -> Self {
110        self.traversals.push(TraversalStep {
111            edge_label: None,
112            direction: TraversalDirection::Both,
113            node_filter: None,
114        });
115        self
116    }
117
118    /// Set maximum traversal depth
119    pub fn depth(mut self, depth: u32) -> Self {
120        self.max_depth = depth;
121        self
122    }
123
124    /// Add a filter condition
125    pub fn where_(self, field: impl Into<String>) -> WhereClause<Self> {
126        WhereClause::new(self, field.into())
127    }
128
129    /// Rank results by vector similarity
130    pub fn ranked_by(mut self, vector: &[f32]) -> Self {
131        self.ranking_vector = Some(vector.to_vec());
132        self
133    }
134
135    /// Limit results
136    pub fn limit(mut self, n: usize) -> Self {
137        self.limit = Some(n);
138        self
139    }
140
141    /// Execute the query
142    pub fn execute(self, store: &Arc<UnifiedStore>) -> Result<QueryResult, ExecutionError> {
143        execute_graph_query(self, store)
144    }
145}
146
147impl FilterAcceptor for GraphQueryBuilder {
148    fn add_filter(&mut self, filter: Filter) {
149        self.filters.push(filter);
150    }
151}