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