akar_processor/physical/write_ops/
foreach.rs1use crate::physical::common::store_value_in_vector;
3use crate::physical::scan_filter::PhysicalScan;
4use crate::physical::types::{OperatorResult, PhysicalOperatorExec};
5use crate::physical::write_ops::ast_constant_to_value;
6use akar_common::types::Value;
7use akar_common::vector::{DataChunk, ValueVector};
8use akar_parser::ast::Expression;
9use akar_storage::table::TableCatalog;
10use std::sync::{Arc, Mutex};
11
12pub struct PhysicalForeach {
16 pub variable: String,
17 pub expression: Expression,
18 pub sub_plans: Vec<Vec<akar_planner::logical_operator::LogicalOperator>>,
19 pub function_registry: Option<Arc<Mutex<akar_function::registry::FunctionRegistry>>>,
20 pub table_catalog: Option<Arc<TableCatalog>>,
21 pub vfs: Option<Arc<akar_common::file_system::VirtualFileSystemRegistry>>,
22}
23
24impl PhysicalOperatorExec for PhysicalForeach {
25 fn operator_type(&self) -> &str {
26 "foreach"
27 }
28
29 fn execute(&self, _input: Vec<DataChunk>) -> OperatorResult {
30 let list_val = match &self.expression {
32 Expression::List(items) => {
33 let mut vals = Vec::with_capacity(items.len());
34 for item in items {
35 if let Expression::Constant(c) = item {
36 vals.push(ast_constant_to_value(c));
37 } else {
38 vals.push(Value::Null);
39 }
40 }
41 Value::List(vals)
42 }
43 _ => {
44 return Err(format!("FOREACH requires a list expression, got: {:?}", self.expression).into());
45 }
46 };
47
48 let list_items = match &list_val {
49 Value::List(items) => items.clone(),
50 _ => return Ok(vec![]),
51 };
52
53 if list_items.is_empty() || self.sub_plans.is_empty() {
54 return Ok(vec![]);
55 }
56
57 for item in &list_items {
61 for sub_plan in &self.sub_plans {
62 let phys_type = PhysicalScan::value_to_physical_type(item);
64 let mut v = ValueVector::new(phys_type, 1);
65 v.resize(1);
66 store_value_in_vector(&mut v, 0, item)?;
67 let _chunk = DataChunk::new(
68 vec![akar_common::arrow_vector::ArrowVector::from_legacy(&v).array],
69 vec![akar_common::types::PhysicalTypeID::Int64],
70 );
71
72 let processor = crate::processor::QueryProcessor::with_catalog(
75 self.function_registry.clone().unwrap(),
76 self.table_catalog.clone().unwrap(),
77 self.vfs.clone().unwrap(),
78 );
79 let _result = processor.execute(sub_plan)?;
80 }
81 }
82
83 Ok(vec![])
85 }
86}