vibesql_executor/pipeline/
context.rs1use std::collections::HashMap;
8
9use crate::{
10 evaluator::CombinedExpressionEvaluator, procedural, schema::CombinedSchema,
11 select::cte::CteResult,
12};
13
14pub struct ExecutionContext<'a> {
30 pub schema: &'a CombinedSchema,
32 pub database: &'a vibesql_storage::Database,
34 pub outer_row: Option<&'a vibesql_storage::Row>,
36 pub outer_schema: Option<&'a CombinedSchema>,
38 pub procedural_context: Option<&'a procedural::ExecutionContext>,
40 pub cte_context: Option<&'a HashMap<String, CteResult>>,
42 pub window_mapping: Option<&'a HashMap<crate::select::WindowFunctionKey, usize>>,
44}
45
46impl<'a> ExecutionContext<'a> {
47 pub fn new(schema: &'a CombinedSchema, database: &'a vibesql_storage::Database) -> Self {
53 Self {
54 schema,
55 database,
56 outer_row: None,
57 outer_schema: None,
58 procedural_context: None,
59 cte_context: None,
60 window_mapping: None,
61 }
62 }
63
64 #[must_use]
70 pub fn with_outer_context(
71 mut self,
72 outer_row: &'a vibesql_storage::Row,
73 outer_schema: &'a CombinedSchema,
74 ) -> Self {
75 self.outer_row = Some(outer_row);
76 self.outer_schema = Some(outer_schema);
77 self
78 }
79
80 #[must_use]
85 pub fn with_procedural_context(mut self, proc_ctx: &'a procedural::ExecutionContext) -> Self {
86 self.procedural_context = Some(proc_ctx);
87 self
88 }
89
90 #[must_use]
95 pub fn with_cte_context(mut self, cte_ctx: &'a HashMap<String, CteResult>) -> Self {
96 self.cte_context = Some(cte_ctx);
97 self
98 }
99
100 #[must_use]
105 pub fn with_window_mapping(
106 mut self,
107 window_mapping: &'a HashMap<crate::select::WindowFunctionKey, usize>,
108 ) -> Self {
109 self.window_mapping = Some(window_mapping);
110 self
111 }
112
113 pub fn create_evaluator(&self) -> CombinedExpressionEvaluator<'a> {
127 match (
131 self.outer_row,
132 self.outer_schema,
133 self.procedural_context,
134 self.cte_context,
135 self.window_mapping,
136 ) {
137 (Some(outer_row), Some(outer_schema), None, Some(cte_ctx), None) => {
139 CombinedExpressionEvaluator::with_database_and_outer_context_and_cte(
140 self.schema,
141 self.database,
142 outer_row,
143 outer_schema,
144 cte_ctx,
145 )
146 }
147 (Some(outer_row), Some(outer_schema), None, None, None) => {
149 CombinedExpressionEvaluator::with_database_and_outer_context(
150 self.schema,
151 self.database,
152 outer_row,
153 outer_schema,
154 )
155 }
156 (None, None, Some(proc_ctx), Some(cte_ctx), None) => {
158 CombinedExpressionEvaluator::with_database_and_procedural_context_and_cte(
159 self.schema,
160 self.database,
161 proc_ctx,
162 cte_ctx,
163 )
164 }
165 (None, None, Some(proc_ctx), None, None) => {
167 CombinedExpressionEvaluator::with_database_and_procedural_context(
168 self.schema,
169 self.database,
170 proc_ctx,
171 )
172 }
173 (None, None, None, Some(cte_ctx), None) => {
175 CombinedExpressionEvaluator::with_database_and_cte(
176 self.schema,
177 self.database,
178 cte_ctx,
179 )
180 }
181 (None, None, None, Some(cte_ctx), Some(window_map)) => {
183 CombinedExpressionEvaluator::with_database_and_windows_and_cte(
184 self.schema,
185 self.database,
186 window_map,
187 cte_ctx,
188 )
189 }
190 (None, None, None, None, Some(window_map)) => {
192 CombinedExpressionEvaluator::with_database_and_windows(
193 self.schema,
194 self.database,
195 window_map,
196 )
197 }
198 (None, None, None, None, None) => {
200 CombinedExpressionEvaluator::with_database(self.schema, self.database)
201 }
202 _ => CombinedExpressionEvaluator::with_database(self.schema, self.database),
205 }
206 }
207
208 #[inline]
210 pub fn has_outer_context(&self) -> bool {
211 self.outer_row.is_some() && self.outer_schema.is_some()
212 }
213
214 #[inline]
216 pub fn has_cte_context(&self) -> bool {
217 self.cte_context.is_some()
218 }
219
220 #[inline]
222 pub fn has_procedural_context(&self) -> bool {
223 self.procedural_context.is_some()
224 }
225}
226
227#[cfg(test)]
228mod tests {
229 use super::*;
230 use crate::schema::CombinedSchema;
231 use vibesql_catalog::TableSchema;
232
233 struct ExecutionContextBuilder<'a> {
238 schema: &'a CombinedSchema,
239 database: &'a vibesql_storage::Database,
240 outer_row: Option<&'a vibesql_storage::Row>,
241 outer_schema: Option<&'a CombinedSchema>,
242 procedural_context: Option<&'a procedural::ExecutionContext>,
243 cte_context: Option<&'a HashMap<String, CteResult>>,
244 executor_cte_context: Option<&'a HashMap<String, CteResult>>,
245 }
246
247 impl<'a> ExecutionContextBuilder<'a> {
248 fn new(schema: &'a CombinedSchema, database: &'a vibesql_storage::Database) -> Self {
250 Self {
251 schema,
252 database,
253 outer_row: None,
254 outer_schema: None,
255 procedural_context: None,
256 cte_context: None,
257 executor_cte_context: None,
258 }
259 }
260
261 #[must_use]
263 fn cte_from_query(mut self, cte_results: &'a HashMap<String, CteResult>) -> Self {
264 if !cte_results.is_empty() {
265 self.cte_context = Some(cte_results);
266 }
267 self
268 }
269
270 fn build(self) -> ExecutionContext<'a> {
274 let mut ctx = ExecutionContext::new(self.schema, self.database);
275
276 if let (Some(outer_row), Some(outer_schema)) = (self.outer_row, self.outer_schema) {
278 ctx = ctx.with_outer_context(outer_row, outer_schema);
279 }
280
281 if let Some(proc_ctx) = self.procedural_context {
283 ctx = ctx.with_procedural_context(proc_ctx);
284 }
285
286 if let Some(cte_ctx) = self.cte_context {
288 ctx = ctx.with_cte_context(cte_ctx);
289 } else if let Some(executor_cte) = self.executor_cte_context {
290 ctx = ctx.with_cte_context(executor_cte);
291 }
292
293 ctx
294 }
295 }
296
297 fn create_test_schema() -> CombinedSchema {
298 let table_schema = TableSchema::new("test".to_string(), vec![]);
299 CombinedSchema::from_table("test".to_string(), table_schema)
300 }
301
302 #[test]
303 fn test_execution_context_builder_basic() {
304 let schema = create_test_schema();
305 let database = vibesql_storage::Database::new();
306
307 let ctx = ExecutionContext::new(&schema, &database);
308
309 assert!(!ctx.has_outer_context());
310 assert!(!ctx.has_cte_context());
311 assert!(!ctx.has_procedural_context());
312 }
313
314 #[test]
315 fn test_execution_context_with_cte() {
316 let schema = create_test_schema();
317 let database = vibesql_storage::Database::new();
318 let cte_results: HashMap<String, CteResult> = HashMap::new();
319
320 let ctx = ExecutionContext::new(&schema, &database).with_cte_context(&cte_results);
321
322 assert!(ctx.has_cte_context());
323 }
324
325 #[test]
326 fn test_execution_context_builder_chain() {
327 let schema = create_test_schema();
328 let database = vibesql_storage::Database::new();
329 let cte_results: HashMap<String, CteResult> = HashMap::new();
330
331 let ctx =
332 ExecutionContextBuilder::new(&schema, &database).cte_from_query(&cte_results).build();
333
334 assert!(!ctx.has_cte_context());
336 }
337}