reddb_server/storage/query/executors/
mod.rs1pub mod agg_spill;
14pub mod aggregation;
15pub mod bitmap_scan;
16pub mod cte;
17pub mod gremlin;
18pub mod hybrid;
19pub mod join;
20pub mod natural;
21pub mod parallel_scan;
22pub mod set_ops;
23pub mod sparql;
24pub mod subquery;
25mod value_compare;
26pub mod vector;
27pub mod window;
28
29pub use aggregation::{
30 create_aggregator, execute_group_by, execute_having, AggregationDef, Aggregator, AvgAggregator,
31 CountAggregator, CountDistinctAggregator, GroupConcatAggregator, MaxAggregator, MinAggregator,
32 PercentileAggregator, SampleAggregator, StdDevAggregator, SumAggregator, VarianceAggregator,
33};
34pub use cte::{inline_ctes, split_union_parts, CteContext, CteExecutor, CteStats};
35pub use gremlin::GremlinExecutor;
36pub use hybrid::{HybridExecutor, InMemoryHybridExecutor};
37pub use join::{
38 choose_strategy, execute_join, hash_join, merge_join, nested_loop_join, JoinCondition,
39 JoinStats, JoinStrategy, JoinType,
40};
41pub use natural::NaturalExecutor;
42pub use set_ops::{execute_set_op, set_except, set_intersect, set_union, SetOpStats, SetOpType};
43pub use sparql::SparqlExecutor;
44pub use subquery::{
45 bind_outer_refs, detect_correlation, CompareOp, SubqueryCache, SubqueryDef, SubqueryExecutor,
46 SubqueryType, ValueHash,
47};
48pub use vector::{InMemoryVectorExecutor, VectorExecutor};
49pub use window::{
50 FrameBound, FrameExclude, FrameSpec, FrameType, NullsOrder, SortDirection, WindowDef,
51 WindowExecutor, WindowFunc, WindowFuncType, WindowOrderBy,
52};
53
54use std::sync::Arc;
55
56use super::modes::{detect_mode, parse_multi, QueryMode};
57use super::unified::{ExecutionError, UnifiedExecutor, UnifiedResult};
58use crate::storage::engine::graph_store::GraphStore;
59use crate::storage::engine::graph_table_index::GraphTableIndex;
60
61pub struct MultiModeExecutor {
63 unified: UnifiedExecutor,
65 gremlin: GremlinExecutor,
67 sparql: SparqlExecutor,
69 natural: NaturalExecutor,
71}
72
73impl MultiModeExecutor {
74 pub fn new(graph: Arc<GraphStore>, index: Arc<GraphTableIndex>) -> Self {
76 let unified = UnifiedExecutor::new(Arc::clone(&graph), Arc::clone(&index));
77 let gremlin = GremlinExecutor::new(Arc::clone(&graph));
78 let sparql = SparqlExecutor::new(Arc::clone(&graph));
79 let natural = NaturalExecutor::new(Arc::clone(&graph));
80
81 Self {
82 unified,
83 gremlin,
84 sparql,
85 natural,
86 }
87 }
88
89 pub fn execute(&self, query: &str) -> Result<ExecuteResult, ExecutionError> {
91 let mode = detect_mode(query);
92
93 match mode {
94 QueryMode::Sql | QueryMode::Cypher | QueryMode::Path => {
95 let ast = parse_multi(query).map_err(|e| ExecutionError::new(e.to_string()))?;
97 let result = self.unified.execute(&ast)?;
98 Ok(ExecuteResult {
99 result,
100 mode,
101 explanation: None,
102 })
103 }
104 QueryMode::Gremlin => {
105 let result = self.gremlin.execute(query)?;
106 Ok(ExecuteResult {
107 result,
108 mode,
109 explanation: None,
110 })
111 }
112 QueryMode::Sparql => {
113 let result = self.sparql.execute(query)?;
114 Ok(ExecuteResult {
115 result,
116 mode,
117 explanation: None,
118 })
119 }
120 QueryMode::Natural => {
121 let (result, explanation) = self.natural.execute_with_explanation(query)?;
122 Ok(ExecuteResult {
123 result,
124 mode,
125 explanation: Some(explanation),
126 })
127 }
128 QueryMode::Unknown => Err(ExecutionError::new(format!(
129 "Cannot determine query mode for: {}",
130 if query.len() > 50 {
131 &query[..50]
132 } else {
133 query
134 }
135 ))),
136 }
137 }
138
139 pub fn execute_as(
141 &self,
142 query: &str,
143 mode: QueryMode,
144 ) -> Result<ExecuteResult, ExecutionError> {
145 match mode {
146 QueryMode::Sql | QueryMode::Cypher | QueryMode::Path => {
147 let ast = parse_multi(query).map_err(|e| ExecutionError::new(e.to_string()))?;
148 let result = self.unified.execute(&ast)?;
149 Ok(ExecuteResult {
150 result,
151 mode,
152 explanation: None,
153 })
154 }
155 QueryMode::Gremlin => {
156 let result = self.gremlin.execute(query)?;
157 Ok(ExecuteResult {
158 result,
159 mode,
160 explanation: None,
161 })
162 }
163 QueryMode::Sparql => {
164 let result = self.sparql.execute(query)?;
165 Ok(ExecuteResult {
166 result,
167 mode,
168 explanation: None,
169 })
170 }
171 QueryMode::Natural => {
172 let (result, explanation) = self.natural.execute_with_explanation(query)?;
173 Ok(ExecuteResult {
174 result,
175 mode,
176 explanation: Some(explanation),
177 })
178 }
179 QueryMode::Unknown => Err(ExecutionError::new("Cannot execute unknown query mode")),
180 }
181 }
182}
183
184#[derive(Debug)]
186pub struct ExecuteResult {
187 pub result: UnifiedResult,
189 pub mode: QueryMode,
191 pub explanation: Option<String>,
193}
194
195impl ExecuteResult {
196 pub fn has_explanation(&self) -> bool {
198 self.explanation.is_some()
199 }
200}
201
202#[cfg(test)]
203mod tests {
204 use super::*;
205
206 fn create_test_executor() -> MultiModeExecutor {
207 let graph = Arc::new(GraphStore::new());
208 let index = Arc::new(GraphTableIndex::new());
209 MultiModeExecutor::new(graph, index)
210 }
211
212 #[test]
213 fn test_gremlin_mode_detection() {
214 let executor = create_test_executor();
215 let result = executor.execute("g.V()");
216 assert!(result.is_ok());
217 assert_eq!(result.unwrap().mode, QueryMode::Gremlin);
218 }
219
220 #[test]
221 fn test_sparql_mode_detection() {
222 let executor = create_test_executor();
223 let result = executor.execute("SELECT ?x WHERE { ?x :type :Host }");
224 assert!(result.is_ok());
225 assert_eq!(result.unwrap().mode, QueryMode::Sparql);
226 }
227
228 #[test]
229 fn test_natural_mode_detection() {
230 let executor = create_test_executor();
231 let result = executor.execute("find all hosts with port 22");
232 assert!(result.is_ok());
233 let exec_result = result.unwrap();
234 assert_eq!(exec_result.mode, QueryMode::Natural);
235 assert!(exec_result.explanation.is_some());
236 }
237}