Skip to main content

linkrs_query/executor/expression/evaluation_context/
default_context.rs

1//! Implementation of the default expression evaluation context
2//!
3//! Provide context management during the evaluation of expressions.
4//!
5//! Note: This context is used for the evaluation of runtime expressions.
6//! For compilation-time analysis, please use `ExpressionAnalysisContext`.
7
8use crate::executor::expression::evaluation_context::graph_storage::GraphStorageRef;
9use crate::executor::expression::functions::global_registry_ref;
10use crate::storage::StorageReader;
11use linkrs_core::Value;
12use parking_lot::RwLock;
13use std::collections::HashMap;
14use std::sync::Arc;
15
16/// The evaluation context of the default expression
17///
18/// Provide the contextual environment required for evaluating the expression, including:
19/// Variable storage
20/// Function registration (using a global function registry)
21/// Optional graph storage accessor for graph algorithm functions
22///
23/// Note: This context is used for the evaluation of runtime expressions.
24/// For compilation-time analysis, please use `ExpressionAnalysisContext`.
25#[derive(Debug)]
26pub struct DefaultExpressionContext {
27    /// Variable storage
28    variables: HashMap<String, Value>,
29    /// Query parameter name → value map (resolves `Expression::Parameter`).
30    parameters: Option<Arc<HashMap<String, Value>>>,
31    /// Session variable name → value snapshot (resolves
32    /// `Expression::SessionVariable`).
33    session_variables: Option<Arc<HashMap<String, Value>>>,
34    /// Optional graph storage for graph algorithm functions
35    storage: Option<Arc<RwLock<dyn StorageReader>>>,
36    /// Space name for graph storage access
37    space: String,
38    /// Sequence catalog manager for `curr_val` / `next_val`.
39    sequence_manager: Option<Arc<linkrs_core::metadata::SequenceManager>>,
40}
41
42impl DefaultExpressionContext {
43    /// Create a new context without graph storage access.
44    pub fn new() -> Self {
45        Self {
46            variables: HashMap::new(),
47            parameters: None,
48            session_variables: None,
49            storage: None,
50            space: String::new(),
51            sequence_manager: None,
52        }
53    }
54
55    /// Create a new context with graph storage access.
56    pub fn with_storage(storage: Arc<RwLock<dyn StorageReader>>, space: String) -> Self {
57        Self {
58            variables: HashMap::new(),
59            parameters: None,
60            session_variables: None,
61            storage: Some(storage),
62            space,
63            sequence_manager: None,
64        }
65    }
66
67    /// Attach a parameter name → value map so `Expression::Parameter`
68    /// references resolve at evaluation time.
69    pub fn with_parameters(mut self, parameters: Arc<HashMap<String, Value>>) -> Self {
70        self.parameters = Some(parameters);
71        self
72    }
73
74    /// Attach a session variable snapshot so `Expression::SessionVariable`
75    /// references resolve at evaluation time.
76    pub fn with_session_variables(mut self, variables: Arc<HashMap<String, Value>>) -> Self {
77        self.session_variables = Some(variables);
78        self
79    }
80
81    /// Add a variable
82    pub fn add_variable(mut self, name: String, value: Value) -> Self {
83        self.variables.insert(name, value);
84        self
85    }
86
87    /// Add variables in batches
88    pub fn with_variables<I>(mut self, variables: I) -> Self
89    where
90        I: IntoIterator<Item = (String, Value)>,
91    {
92        for (name, value) in variables {
93            self.variables.insert(name, value);
94        }
95        self
96    }
97
98    /// Create a DefaultExpressionContext from the ExecutionContext.
99    ///
100    /// Copy all variables from the ExecutionContext to the new DefaultExpressionContext.
101    pub fn from_execution_context(ctx: &crate::executor::base::ExecutionContext) -> Self {
102        Self {
103            variables: ctx.variables.read().clone(),
104            parameters: None,
105            session_variables: None,
106            storage: None,
107            space: String::new(),
108            sequence_manager: ctx.sequence_manager.clone(),
109        }
110    }
111
112    /// Synchronize the variable back to the ExecutionContext.
113    ///
114    /// Synchronize all variables from the current DefaultExpressionContext to the ExecutionContext.
115    pub fn sync_to_execution_context(self, ctx: &crate::executor::base::ExecutionContext) {
116        for (name, value) in self.variables {
117            ctx.set_variable(name, value);
118        }
119    }
120
121    /// Get all variables for debugging
122    pub fn get_all_variables(&self) -> &HashMap<String, Value> {
123        &self.variables
124    }
125}
126
127impl Default for DefaultExpressionContext {
128    fn default() -> Self {
129        Self::new()
130    }
131}
132
133impl crate::executor::expression::evaluator::traits::ExpressionContext
134    for DefaultExpressionContext
135{
136    fn get_variable(&self, name: &str) -> Option<Value> {
137        self.variables.get(name).cloned()
138    }
139
140    fn set_variable(&mut self, name: String, value: Value) {
141        self.variables.insert(name, value);
142    }
143
144    fn get_parameter(&self, name: &str) -> Option<Value> {
145        self.parameters
146            .as_ref()
147            .and_then(|params| params.get(name).cloned())
148    }
149
150    fn get_session_variable(
151        &self,
152        name: &str,
153    ) -> Result<Value, crate::executor::expression::ExpressionError> {
154        self.session_variables
155            .as_ref()
156            .and_then(|vars| vars.get(name).cloned())
157            .ok_or_else(|| {
158                crate::executor::expression::ExpressionError::type_error(format!(
159                    "Session variable `{}` is not defined",
160                    name
161                ))
162            })
163    }
164
165    fn get_function(
166        &self,
167        name: &str,
168    ) -> Option<crate::executor::expression::functions::OwnedFunctionRef> {
169        let registry = global_registry_ref();
170        registry
171            .get_builtin(name)
172            .map(|f| crate::executor::expression::functions::OwnedFunctionRef::Builtin(f.clone()))
173            .or_else(|| {
174                registry.get_custom(name).map(|f| {
175                    crate::executor::expression::functions::OwnedFunctionRef::Custom(f.clone())
176                })
177            })
178    }
179
180    fn get_graph_storage(&self) -> Option<GraphStorageRef> {
181        self.storage
182            .as_ref()
183            .map(|s| GraphStorageRef::new(s.clone(), self.space.clone()))
184    }
185
186    fn get_sequence_manager(&self) -> Option<Arc<linkrs_core::metadata::SequenceManager>> {
187        self.sequence_manager.clone()
188    }
189}