1use drasi_query_ast::ast::{self, ProjectionClause, QueryPart};
16use hashers::jenkins::spooky_hash::SpookyHasher;
17use std::collections::BTreeMap;
18use std::hash::{Hash, Hasher};
19use std::sync::Arc;
20
21use crate::evaluation::variable_value::VariableValue;
22use crate::interface::QueryClock;
23use crate::models::{Element, ElementReference, ElementTimestamp};
24use crate::path_solver::solution::SolutionSignature;
25
26pub type QueryVariables = BTreeMap<Box<str>, VariableValue>;
27
28#[derive(Debug, Clone)]
29pub enum SideEffects {
30 Apply,
31 RevertForUpdate,
32 RevertForDelete,
33 Snapshot,
34}
35
36#[derive(Debug, Clone, PartialEq)]
37pub enum QueryPartEvaluationContext {
38 Adding {
39 after: QueryVariables,
40 },
41 Updating {
42 before: QueryVariables,
43 after: QueryVariables,
44 },
45 Removing {
46 before: QueryVariables,
47 },
48 Aggregation {
49 before: Option<QueryVariables>,
50 after: QueryVariables,
51 grouping_keys: Vec<String>,
52 default_before: bool,
53 default_after: bool,
54 },
55 Noop,
56}
57
58impl QueryPartEvaluationContext {}
59
60#[derive(Debug, Clone)]
61pub struct ExpressionEvaluationContext<'a> {
62 variables: &'a QueryVariables,
63 side_effects: SideEffects,
64 output_grouping_key: Option<&'a Vec<ast::Expression>>,
65 input_grouping_hash: u64,
66 clock: Arc<dyn QueryClock>,
67 solution_signature: Option<SolutionSignature>,
68 anchor_element: Option<Arc<Element>>,
69}
70
71impl<'a> ExpressionEvaluationContext<'a> {
72 pub fn new(
73 variables: &'a QueryVariables,
74 clock: Arc<dyn QueryClock>,
75 ) -> ExpressionEvaluationContext<'a> {
76 ExpressionEvaluationContext {
77 variables,
78 side_effects: SideEffects::Apply,
79 output_grouping_key: None,
80 input_grouping_hash: u64::default(),
81 clock,
82 solution_signature: None,
83 anchor_element: None,
84 }
85 }
86
87 pub fn from_slot(
88 variables: &'a QueryVariables,
89 clock: Arc<dyn QueryClock>,
90 element_reference: &ElementReference,
91 ) -> ExpressionEvaluationContext<'a> {
92 ExpressionEvaluationContext {
93 variables,
94 side_effects: SideEffects::Apply,
95 output_grouping_key: None,
96 input_grouping_hash: extract_element_reference_hash(element_reference),
97 clock,
98 solution_signature: None,
99 anchor_element: None,
100 }
101 }
102
103 pub fn from_before_change(
104 variables: &'a QueryVariables,
105 side_effect_directive: SideEffects,
106 change_context: &ChangeContext,
107 query_part: &'a QueryPart,
108 ) -> ExpressionEvaluationContext<'a> {
109 ExpressionEvaluationContext {
110 variables,
111 side_effects: side_effect_directive,
112 input_grouping_hash: change_context.before_grouping_hash,
113 clock: change_context.before_clock.clone(),
114 solution_signature: Some(change_context.solution_signature),
115 anchor_element: change_context.before_anchor_element.clone(),
116 output_grouping_key: match &query_part.return_clause {
117 ProjectionClause::GroupBy { grouping, .. } => Some(grouping),
118 _ => None,
119 },
120 }
121 }
122
123 pub fn from_after_change(
124 variables: &'a QueryVariables,
125 change_context: &ChangeContext,
126 query_part: &'a QueryPart,
127 ) -> ExpressionEvaluationContext<'a> {
128 ExpressionEvaluationContext {
129 variables,
130 side_effects: SideEffects::Apply,
131 input_grouping_hash: change_context.after_grouping_hash,
132 clock: change_context.after_clock.clone(),
133 solution_signature: Some(change_context.solution_signature),
134 anchor_element: change_context.after_anchor_element.clone(),
135 output_grouping_key: match &query_part.return_clause {
136 ProjectionClause::GroupBy { grouping, .. } => Some(grouping),
137 _ => None,
138 },
139 }
140 }
141
142 pub fn replace_variables(&mut self, new_data: &'a QueryVariables) {
143 self.variables = new_data;
144 }
145
146 pub fn get_variable(&self, name: Arc<str>) -> Option<&VariableValue> {
147 self.variables.get(&name.to_string().into_boxed_str())
148 }
149
150 pub fn clone_variables(&self) -> QueryVariables {
151 self.variables.clone()
152 }
153
154 pub fn set_side_effects(&mut self, directive: SideEffects) {
155 self.side_effects = directive;
156 }
157
158 pub fn get_side_effects(&self) -> &SideEffects {
159 &self.side_effects
160 }
161
162 pub fn set_output_grouping_key(&mut self, grouping_key: &'a Vec<ast::Expression>) {
163 self.output_grouping_key = Some(grouping_key);
164 }
165
166 pub fn get_output_grouping_key(&self) -> Option<&Vec<ast::Expression>> {
167 self.output_grouping_key
168 }
169
170 pub fn get_transaction_time(&self) -> ElementTimestamp {
171 self.clock.get_transaction_time()
172 }
173
174 pub fn get_realtime(&self) -> ElementTimestamp {
175 self.clock.get_realtime()
176 }
177
178 pub fn get_clock(&self) -> Arc<dyn QueryClock> {
179 self.clock.clone()
180 }
181
182 pub fn get_solution_signature(&self) -> Option<SolutionSignature> {
183 self.solution_signature
184 }
185
186 pub fn get_anchor_element(&self) -> Option<Arc<Element>> {
187 self.anchor_element.clone()
188 }
189
190 pub fn get_input_grouping_hash(&self) -> u64 {
191 self.input_grouping_hash
192 }
193}
194
195#[derive(Debug, Clone)]
196pub struct ChangeContext {
197 pub solution_signature: SolutionSignature,
198 pub before_anchor_element: Option<Arc<Element>>,
199 pub after_anchor_element: Option<Arc<Element>>,
200 pub before_clock: Arc<dyn QueryClock>,
201 pub after_clock: Arc<dyn QueryClock>,
202 pub is_future_reprocess: bool,
203 pub before_grouping_hash: u64,
204 pub after_grouping_hash: u64,
205}
206
207fn extract_element_reference_hash(element_reference: &ElementReference) -> u64 {
208 let mut hasher = SpookyHasher::default();
209 element_reference.source_id.hash(&mut hasher);
210 element_reference.element_id.hash(&mut hasher);
211 hasher.finish()
212}