use super::Connection;
use crate::connection::substitute::substitute_foreach_var;
use crate::connection::utils::ast_constant_to_value;
use crate::query_result::QueryResult;
impl Connection {
pub(crate) fn handle_foreach(
&self,
fc: &akar_binder::bound_statement::BoundForeachClause,
mut txn_opt: Option<&mut akar_transaction::Transaction>,
) -> Result<Option<QueryResult>, String> {
tracing::info!("FOREACH '{}'", fc.variable);
let list_val = match &fc.expression {
akar_parser::ast::Expression::List(items) => {
let mut vals = Vec::with_capacity(items.len());
for item in items {
if let akar_parser::ast::Expression::Constant(c) = item {
vals.push(ast_constant_to_value(c));
} else {
vals.push(akar_common::types::Value::Null);
}
}
akar_common::types::Value::List(vals)
}
_ => {
return Err("FOREACH requires a list expression".to_string());
}
};
let list_items = match &list_val {
akar_common::types::Value::List(items) => items.clone(),
_ => return Ok(Some(QueryResult::success_message("FOREACH: empty list".into()))),
};
if list_items.is_empty() {
return Ok(Some(QueryResult::success_message("FOREACH: empty list".into())));
}
for item_val in &list_items {
for sub_stmt in &fc.sub_statements {
let substituted = substitute_foreach_var(sub_stmt, &fc.variable, item_val)?;
tracing::info!("FOREACH executing sub-statement for item={:?}", item_val);
match self.handle_ddl(&substituted, txn_opt.as_deref_mut())? {
Some(result) => {
self.database.persist_catalog()?;
tracing::info!("FOREACH sub-statement result: {:?}", result);
}
None => {
let result = self.execute_query_inner(&substituted, txn_opt.as_deref_mut(), None)?;
tracing::info!("FOREACH DML sub-statement result: {:?}", result);
}
}
}
}
Ok(Some(QueryResult::success_message(format!(
"FOREACH: processed {} items with {} statements",
list_items.len(),
fc.sub_statements.len()
))))
}
}