1use std::collections::HashMap;
7use std::sync::Arc;
8use async_trait::async_trait;
9use anyhow::Result;
10
11use kotoba_storage::KeyValueStore;
12
13pub mod parser;
14pub mod ast;
15pub mod planner;
16pub mod executor;
17pub mod optimizer;
18
19pub use ast::*;
21pub use parser::*;
22pub use planner::*;
23pub use executor::*;
24pub use optimizer::*;
25
26pub mod types;
28
29pub use types::{QueryResult, StatementResult, VertexId, EdgeId, Vertex, Edge, VertexFilter, EdgeFilter, Path};
31pub use serde_json::Value;
32
33pub use types::PathPattern;
35
36#[derive(Debug, Clone)]
38pub struct QueryContext {
39 pub user_id: Option<String>,
40 pub database: String,
41 pub timeout: std::time::Duration,
42 pub parameters: HashMap<String, serde_json::Value>,
43}
44
45pub struct GqlQueryEngine<T: KeyValueStore> {
47 storage: Arc<T>,
48 optimizer: QueryOptimizer<T>,
49 planner: QueryPlanner<T>,
50}
51
52impl<T: KeyValueStore + 'static> GqlQueryEngine<T> {
53 pub fn new(storage: Arc<T>) -> Self {
54 let optimizer = QueryOptimizer::new(storage.clone());
55 let planner = QueryPlanner::new(storage.clone());
56
57 Self {
58 storage,
59 optimizer,
60 planner,
61 }
62 }
63
64 pub async fn execute_query(
66 &self,
67 query: &str,
68 context: QueryContext,
69 ) -> Result<QueryResult> {
70 let parsed_query = GqlParser::parse(query)?;
72
73 let optimized_query = self.optimizer.optimize(parsed_query).await?;
75
76 let execution_plan = self.planner.plan(optimized_query).await?;
78
79 let executor = QueryExecutor::new(self.storage.clone());
81
82 executor.execute(execution_plan, context).await
83 }
84
85 pub async fn execute_statement(
87 &self,
88 statement: &str,
89 context: QueryContext,
90 ) -> Result<StatementResult> {
91 let parsed_statement = GqlParser::parse_statement(statement)?;
93
94 let executor = StatementExecutor::new(self.storage.clone());
96
97 executor.execute(parsed_statement, context).await
98 }
99}
100
101#[async_trait]
103pub trait ProjectionPort: Send + Sync {
104 async fn get_vertex(&self, id: &VertexId) -> Result<Option<Vertex>>;
105 async fn get_edge(&self, id: &EdgeId) -> Result<Option<Edge>>;
106 async fn scan_vertices(&self, filter: Option<VertexFilter>) -> Result<Vec<Vertex>>;
107 async fn scan_edges(&self, filter: Option<EdgeFilter>) -> Result<Vec<Edge>>;
108 async fn traverse(&self, start: &VertexId, pattern: &PathPattern) -> Result<Vec<Path>>;
109}
110
111#[async_trait]
113pub trait IndexManagerPort: Send + Sync {
114 async fn lookup_vertices(&self, property: &str, value: &Value) -> Result<Vec<VertexId>>;
115 async fn lookup_edges(&self, property: &str, value: &Value) -> Result<Vec<EdgeId>>;
116 async fn range_scan(&self, property: &str, start: &Value, end: &Value) -> Result<Vec<VertexId>>;
117 async fn has_vertex_index(&self, property: &str) -> Result<bool>;
118 async fn has_edge_index(&self, property: &str) -> Result<bool>;
119}
120
121#[async_trait]
123pub trait CachePort: Send + Sync {
124 async fn get(&self, key: &str) -> Result<Option<serde_json::Value>>;
125 async fn set(&self, key: &str, value: serde_json::Value, ttl: Option<std::time::Duration>) -> Result<()>;
126 async fn delete(&self, key: &str) -> Result<()>;
127}
128
129pub use types::*;
131
132#[cfg(test)]
133mod tests {
134 use super::*;
135 use std::collections::HashMap;
136 use std::sync::Arc;
137
138 struct MockKeyValueStore {
140 data: HashMap<Vec<u8>, Vec<u8>>,
141 }
142
143 impl MockKeyValueStore {
144 fn new() -> Self {
145 Self {
146 data: HashMap::new(),
147 }
148 }
149 }
150
151 #[async_trait::async_trait]
152 impl KeyValueStore for MockKeyValueStore {
153 async fn put(&self, key: &[u8], value: &[u8]) -> anyhow::Result<()> {
154 Ok(())
155 }
156
157 async fn get(&self, key: &[u8]) -> anyhow::Result<Option<Vec<u8>>> {
158 Ok(None)
159 }
160
161 async fn delete(&self, key: &[u8]) -> anyhow::Result<()> {
162 Ok(())
163 }
164
165 async fn scan(&self, prefix: &[u8]) -> anyhow::Result<Vec<(Vec<u8>, Vec<u8>)>> {
166 Ok(vec![])
167 }
168 }
169
170 struct MockProjectionPort;
172
173 #[async_trait::async_trait]
174 impl ProjectionPort for MockProjectionPort {
175 async fn get_vertex(&self, _id: &VertexId) -> Result<Option<Vertex>> {
176 Ok(None)
177 }
178
179 async fn get_edge(&self, _id: &EdgeId) -> Result<Option<Edge>> {
180 Ok(None)
181 }
182
183 async fn scan_vertices(&self, _filter: Option<VertexFilter>) -> Result<Vec<Vertex>> {
184 Ok(vec![])
185 }
186
187 async fn scan_edges(&self, _filter: Option<EdgeFilter>) -> Result<Vec<Edge>> {
188 Ok(vec![])
189 }
190
191 async fn traverse(&self, _start: &VertexId, _pattern: &PathPattern) -> Result<Vec<Path>> {
192 Ok(vec![])
193 }
194 }
195
196 struct MockIndexManagerPort;
198
199 #[async_trait::async_trait]
200 impl IndexManagerPort for MockIndexManagerPort {
201 async fn lookup_vertices(&self, _property: &str, _value: &Value) -> Result<Vec<VertexId>> {
202 Ok(vec![])
203 }
204
205 async fn lookup_edges(&self, _property: &str, _value: &Value) -> Result<Vec<EdgeId>> {
206 Ok(vec![])
207 }
208
209 async fn range_scan(&self, _property: &str, _start: &Value, _end: &Value) -> Result<Vec<VertexId>> {
210 Ok(vec![])
211 }
212
213 async fn has_vertex_index(&self, _property: &str) -> Result<bool> {
214 Ok(false)
215 }
216
217 async fn has_edge_index(&self, _property: &str) -> Result<bool> {
218 Ok(false)
219 }
220 }
221
222 struct MockCachePort;
224
225 #[async_trait::async_trait]
226 impl CachePort for MockCachePort {
227 async fn get(&self, _key: &str) -> Result<Option<serde_json::Value>> {
228 Ok(None)
229 }
230
231 async fn set(&self, _key: &str, _value: serde_json::Value, _ttl: Option<std::time::Duration>) -> Result<()> {
232 Ok(())
233 }
234
235 async fn delete(&self, _key: &str) -> Result<()> {
236 Ok(())
237 }
238 }
239
240 #[test]
241 fn test_query_context_creation() {
242 let mut parameters = HashMap::new();
243 parameters.insert("limit".to_string(), serde_json::json!(10));
244 parameters.insert("offset".to_string(), serde_json::json!(0));
245
246 let context = QueryContext {
247 user_id: Some("user123".to_string()),
248 database: "test_db".to_string(),
249 timeout: std::time::Duration::from_secs(30),
250 parameters,
251 };
252
253 assert_eq!(context.user_id, Some("user123".to_string()));
254 assert_eq!(context.database, "test_db");
255 assert_eq!(context.timeout, std::time::Duration::from_secs(30));
256 assert_eq!(context.parameters.get("limit"), Some(&serde_json::json!(10)));
257 assert_eq!(context.parameters.get("offset"), Some(&serde_json::json!(0)));
258 }
259
260 #[test]
261 fn test_query_context_creation_minimal() {
262 let context = QueryContext {
263 user_id: None,
264 database: "default".to_string(),
265 timeout: std::time::Duration::from_millis(5000),
266 parameters: HashMap::new(),
267 };
268
269 assert_eq!(context.user_id, None);
270 assert_eq!(context.database, "default");
271 assert_eq!(context.timeout, std::time::Duration::from_millis(5000));
272 assert!(context.parameters.is_empty());
273 }
274
275 #[test]
276 fn test_query_context_clone() {
277 let original = QueryContext {
278 user_id: Some("test_user".to_string()),
279 database: "test_db".to_string(),
280 timeout: std::time::Duration::from_secs(60),
281 parameters: HashMap::new(),
282 };
283
284 let cloned = original.clone();
285
286 assert_eq!(original.user_id, cloned.user_id);
287 assert_eq!(original.database, cloned.database);
288 assert_eq!(original.timeout, cloned.timeout);
289 assert_eq!(original.parameters, cloned.parameters);
290 }
291
292 #[test]
293 fn test_query_context_debug() {
294 let context = QueryContext {
295 user_id: Some("debug_user".to_string()),
296 database: "debug_db".to_string(),
297 timeout: std::time::Duration::from_secs(10),
298 parameters: HashMap::new(),
299 };
300
301 let debug_str = format!("{:?}", context);
302 assert!(debug_str.contains("debug_user"));
303 assert!(debug_str.contains("debug_db"));
304 assert!(debug_str.contains("10"));
305 }
306
307 #[test]
308 fn test_query_context_serialization() {
309 let mut parameters = HashMap::new();
310 parameters.insert("name".to_string(), serde_json::json!("test"));
311
312 let context = QueryContext {
313 user_id: Some("user_001".to_string()),
314 database: "test_database".to_string(),
315 timeout: std::time::Duration::from_secs(45),
316 parameters,
317 };
318
319 let json_result = serde_json::to_string(&context);
321 assert!(json_result.is_ok());
322
323 let json_str = json_result.unwrap();
324 assert!(json_str.contains("user_001"));
325 assert!(json_str.contains("test_database"));
326 assert!(json_str.contains("45"));
327
328 let deserialized_result: serde_json::Result<QueryContext> = serde_json::from_str(&json_str);
330 assert!(deserialized_result.is_ok());
331
332 let deserialized = deserialized_result.unwrap();
333 assert_eq!(deserialized.user_id, Some("user_001".to_string()));
334 assert_eq!(deserialized.database, "test_database");
335 assert_eq!(deserialized.timeout, std::time::Duration::from_secs(45));
336 }
337
338 #[tokio::test]
339 async fn test_gql_query_engine_creation() {
340 let mock_storage = Arc::new(MockKeyValueStore::new());
341 let engine = GqlQueryEngine::new(mock_storage);
342
343 assert!(true); }
346
347 #[tokio::test]
348 async fn test_gql_query_engine_execute_query() {
349 let mock_storage = Arc::new(MockKeyValueStore::new());
350 let engine = GqlQueryEngine::new(mock_storage);
351
352 let context = QueryContext {
353 user_id: Some("test_user".to_string()),
354 database: "test_db".to_string(),
355 timeout: std::time::Duration::from_secs(10),
356 parameters: HashMap::new(),
357 };
358
359 let query = "MATCH (n) RETURN n";
362 let result = engine.execute_query(query, context).await;
363
364 assert!(result.is_err());
367 }
368
369 #[tokio::test]
370 async fn test_gql_query_engine_execute_statement() {
371 let mock_storage = Arc::new(MockKeyValueStore::new());
372 let engine = GqlQueryEngine::new(mock_storage);
373
374 let context = QueryContext {
375 user_id: Some("test_user".to_string()),
376 database: "test_db".to_string(),
377 timeout: std::time::Duration::from_secs(10),
378 parameters: HashMap::new(),
379 };
380
381 let statement = "CREATE GRAPH test_graph";
383 let result = engine.execute_statement(statement, context).await;
384
385 assert!(result.is_err());
387 }
388
389 #[tokio::test]
390 async fn test_projection_port_mock() {
391 let projection = MockProjectionPort;
392 let vertex_id = VertexId("test_vertex".to_string());
393
394 let result = projection.get_vertex(&vertex_id).await;
396 assert!(result.is_ok());
397 assert!(result.unwrap().is_none());
398
399 let result = projection.scan_vertices(None).await;
401 assert!(result.is_ok());
402 assert!(result.unwrap().is_empty());
403
404 let result = projection.scan_edges(None).await;
406 assert!(result.is_ok());
407 assert!(result.unwrap().is_empty());
408
409 let pattern = PathPattern::default();
411 let result = projection.traverse(&vertex_id, &pattern).await;
412 assert!(result.is_ok());
413 assert!(result.unwrap().is_empty());
414 }
415
416 #[tokio::test]
417 async fn test_index_manager_port_mock() {
418 let index_manager = MockIndexManagerPort;
419 let value = serde_json::json!("test_value");
420
421 let result = index_manager.lookup_vertices("name", &value).await;
423 assert!(result.is_ok());
424 assert!(result.unwrap().is_empty());
425
426 let result = index_manager.lookup_edges("type", &value).await;
428 assert!(result.is_ok());
429 assert!(result.unwrap().is_empty());
430
431 let start = serde_json::json!("a");
433 let end = serde_json::json!("z");
434 let result = index_manager.range_scan("name", &start, &end).await;
435 assert!(result.is_ok());
436 assert!(result.unwrap().is_empty());
437
438 let result = index_manager.has_vertex_index("name").await;
440 assert!(result.is_ok());
441 assert!(!result.unwrap());
442
443 let result = index_manager.has_edge_index("type").await;
445 assert!(result.is_ok());
446 assert!(!result.unwrap());
447 }
448
449 #[tokio::test]
450 async fn test_cache_port_mock() {
451 let cache = MockCachePort;
452 let value = serde_json::json!({"key": "value"});
453
454 let result = cache.get("test_key").await;
456 assert!(result.is_ok());
457 assert!(result.unwrap().is_none());
458
459 let result = cache.set("test_key", value.clone(), Some(std::time::Duration::from_secs(60))).await;
461 assert!(result.is_ok());
462
463 let result = cache.delete("test_key").await;
465 assert!(result.is_ok());
466 }
467
468 #[test]
469 fn test_projection_port_trait() {
470 fn assert_send_sync<T: Send + Sync>() {}
472 assert_send_sync::<MockProjectionPort>();
473 }
474
475 #[test]
476 fn test_index_manager_port_trait() {
477 fn assert_send_sync<T: Send + Sync>() {}
479 assert_send_sync::<MockIndexManagerPort>();
480 }
481
482 #[test]
483 fn test_cache_port_trait() {
484 fn assert_send_sync<T: Send + Sync>() {}
486 assert_send_sync::<MockCachePort>();
487 }
488
489 #[test]
490 fn test_query_result_types() {
491 let _query_result_type_exists = std::any::TypeId::of::<QueryResult>();
495 assert!(true);
496 }
497
498 #[test]
499 fn test_statement_result_types() {
500 let _statement_result_type_exists = std::any::TypeId::of::<StatementResult>();
502 assert!(true);
503 }
504
505 #[test]
506 fn test_vertex_edge_types() {
507 let vertex_id = VertexId("test".to_string());
509 assert_eq!(vertex_id.0, "test");
510
511 let edge_id = EdgeId("test_edge".to_string());
512 assert_eq!(edge_id.0, "test_edge");
513 }
514
515 #[test]
516 fn test_filter_types() {
517 let _vertex_filter_exists = std::any::TypeId::of::<VertexFilter>();
519 let _edge_filter_exists = std::any::TypeId::of::<EdgeFilter>();
520 assert!(true);
521 }
522
523 #[test]
524 fn test_path_pattern_type() {
525 let _path_pattern_exists = std::any::TypeId::of::<PathPattern>();
527 assert!(true);
528 }
529
530 #[test]
531 fn test_path_type() {
532 let _path_exists = std::any::TypeId::of::<Path>();
534 assert!(true);
535 }
536
537 #[test]
538 fn test_gql_query_engine_with_different_storage() {
539 let mock_storage = Arc::new(MockKeyValueStore::new());
541 let _engine: GqlQueryEngine<MockKeyValueStore> = GqlQueryEngine::new(mock_storage);
542 assert!(true);
543 }
544
545 #[test]
546 fn test_query_context_with_parameters() {
547 let mut parameters = HashMap::new();
548 parameters.insert("limit".to_string(), serde_json::json!(100));
549 parameters.insert("sort".to_string(), serde_json::json!("name"));
550 parameters.insert("filter".to_string(), serde_json::json!({"active": true}));
551
552 let context = QueryContext {
553 user_id: Some("admin".to_string()),
554 database: "analytics".to_string(),
555 timeout: std::time::Duration::from_millis(30000),
556 parameters,
557 };
558
559 assert_eq!(context.parameters.len(), 3);
560 assert_eq!(context.parameters.get("limit"), Some(&serde_json::json!(100)));
561 assert_eq!(context.parameters.get("sort"), Some(&serde_json::json!("name")));
562
563 let filter_value = context.parameters.get("filter").unwrap();
564 assert_eq!(filter_value.get("active"), Some(&serde_json::json!(true)));
565 }
566
567 #[test]
568 fn test_query_context_equality() {
569 let context1 = QueryContext {
570 user_id: Some("user1".to_string()),
571 database: "db1".to_string(),
572 timeout: std::time::Duration::from_secs(30),
573 parameters: HashMap::new(),
574 };
575
576 let context2 = QueryContext {
577 user_id: Some("user1".to_string()),
578 database: "db1".to_string(),
579 timeout: std::time::Duration::from_secs(30),
580 parameters: HashMap::new(),
581 };
582
583 assert!(true);
586 }
587}