lora_database/
database.rs1use std::collections::BTreeMap;
2use std::sync::{Arc, Mutex, MutexGuard};
3
4use anyhow::Result;
5use lora_analyzer::Analyzer;
6use lora_ast::Document;
7use lora_compiler::{CompiledQuery, Compiler};
8use lora_executor::{
9 ExecuteOptions, LoraValue, MutableExecutionContext, MutableExecutor, QueryResult,
10};
11use lora_parser::parse_query;
12use lora_store::{GraphStorage, GraphStorageMut, InMemoryGraph};
13
14pub trait QueryRunner: Send + Sync + 'static {
16 fn execute(&self, query: &str, options: Option<ExecuteOptions>) -> Result<QueryResult>;
17}
18
19pub struct Database<S> {
21 store: Arc<Mutex<S>>,
22}
23
24impl Database<InMemoryGraph> {
25 pub fn in_memory() -> Self {
27 Self::from_graph(InMemoryGraph::new())
28 }
29}
30
31impl<S> Database<S>
32where
33 S: GraphStorage + GraphStorageMut,
34{
35 pub fn new(store: Arc<Mutex<S>>) -> Self {
37 Self { store }
38 }
39
40 pub fn from_graph(graph: S) -> Self {
42 Self::new(Arc::new(Mutex::new(graph)))
43 }
44
45 pub fn store(&self) -> &Arc<Mutex<S>> {
48 &self.store
49 }
50
51 pub fn parse(&self, query: &str) -> Result<Document> {
53 Ok(parse_query(query)?)
54 }
55
56 fn lock_store(&self) -> MutexGuard<'_, S> {
57 self.store
58 .lock()
59 .unwrap_or_else(|poisoned| poisoned.into_inner())
60 }
61
62 fn compile_query(&self, query: &str) -> Result<(MutexGuard<'_, S>, CompiledQuery)> {
63 let document = self.parse(query)?;
64 let store = self.lock_store();
65
66 let resolved = {
67 let mut analyzer = Analyzer::new(&*store);
68 analyzer.analyze(&document)?
69 };
70
71 let compiled = Compiler::compile(&resolved);
72 Ok((store, compiled))
73 }
74
75 pub fn execute(&self, query: &str, options: Option<ExecuteOptions>) -> Result<QueryResult> {
77 self.execute_with_params(query, options, BTreeMap::new())
78 }
79
80 pub fn execute_with_params(
82 &self,
83 query: &str,
84 options: Option<ExecuteOptions>,
85 params: BTreeMap<String, LoraValue>,
86 ) -> Result<QueryResult> {
87 let (mut store, compiled) = self.compile_query(query)?;
88
89 let mut executor = MutableExecutor::new(MutableExecutionContext {
90 storage: &mut *store,
91 params,
92 });
93
94 Ok(executor.execute_compiled(&compiled, options)?)
95 }
96}
97
98impl<S> QueryRunner for Database<S>
99where
100 S: GraphStorage + GraphStorageMut + Send + 'static,
101{
102 fn execute(&self, query: &str, options: Option<ExecuteOptions>) -> Result<QueryResult> {
103 Database::execute(self, query, options)
104 }
105}