akar_processor/physical/write_ops/
unwind.rs1use crate::physical::common::store_value_in_vector;
3use crate::physical::types::{OperatorResult, PhysicalOperatorExec};
4use akar_common::types::{PhysicalTypeID, Value};
5use akar_common::vector::{DataChunk, ValueVector};
6
7pub struct PhysicalUnwind {
11 pub expression: akar_parser::ast::Expression,
12 pub variable: String,
13}
14
15impl PhysicalOperatorExec for PhysicalUnwind {
16 fn operator_type(&self) -> &str {
17 "unwind"
18 }
19
20 fn execute(&self, input: Vec<DataChunk>) -> OperatorResult {
21 let list_val = evaluate_unwind_expr(&self.expression);
23 let items = match &list_val {
24 akar_common::types::Value::List(items) => items.clone(),
25 _ => return Err("UNWIND expression must evaluate to a list".into()),
26 };
27
28 if items.is_empty() {
29 return Ok(Vec::new());
30 }
31
32 let first_type = items
36 .first()
37 .map(|v| v.physical_type())
38 .unwrap_or(PhysicalTypeID::Int64);
39 let uw_arrow = crate::expression_evaluator::build_arrow_from_values(&items, first_type, items.len())
40 .map_err(|e| e.to_string())?;
41
42 let mut result_chunks = Vec::new();
43 if let Some(chunk) = input.first() {
45 for row in 0..chunk.size {
46 let mut arrow_fields: Vec<arrow::array::ArrayRef> = Vec::with_capacity(chunk.fields.len() + 1);
47 let mut arrow_field_types: Vec<PhysicalTypeID> = Vec::with_capacity(chunk.fields.len() + 1);
48 for (col_idx, _field) in chunk.fields.iter().enumerate() {
49 let val = chunk.get_value(col_idx, row).unwrap_or(Value::Null);
50 let mut v = ValueVector::new(chunk.field_types[col_idx], items.len());
51 v.resize(items.len());
52 for i in 0..items.len() {
53 store_value_in_vector(&mut v, i, &val)?;
54 }
55 arrow_fields.push(akar_common::arrow_vector::ArrowVector::from_legacy(&v).array);
56 arrow_field_types.push(v.physical_type());
57 }
58 arrow_fields.push(uw_arrow.array.clone());
60 arrow_field_types.push(uw_arrow.physical_type);
61 let mut named_chunk = DataChunk::new(arrow_fields, arrow_field_types);
62 named_chunk.field_names = chunk
63 .field_names
64 .iter()
65 .cloned()
66 .chain([self.variable.clone()])
67 .collect();
68 result_chunks.push(named_chunk);
69 }
70 } else {
71 let mut named_chunk = DataChunk::new(vec![uw_arrow.array.clone()], vec![uw_arrow.physical_type]);
73 named_chunk.field_names = vec![self.variable.clone()];
74 result_chunks.push(named_chunk);
75 }
76
77 Ok(result_chunks)
78 }
79}
80
81fn evaluate_unwind_expr(expr: &akar_parser::ast::Expression) -> Value {
83 match expr {
84 akar_parser::ast::Expression::List(items) => {
85 let values: Vec<Value> = items.iter().map(expr_to_value).collect();
86 Value::List(values)
87 }
88 _ => Value::List(Vec::new()),
89 }
90}
91
92fn expr_to_value(expr: &akar_parser::ast::Expression) -> Value {
95 match expr {
96 akar_parser::ast::Expression::Constant(c) => match c {
97 akar_parser::ast::Constant::Null => Value::Null,
98 akar_parser::ast::Constant::Bool(b) => Value::Bool(*b),
99 akar_parser::ast::Constant::Integer(i) => Value::Int64(*i),
100 akar_parser::ast::Constant::Float(f) => Value::Double(*f),
101 akar_parser::ast::Constant::String(s) => Value::String(s.clone()),
102 },
103 akar_parser::ast::Expression::List(items) => Value::List(items.iter().map(expr_to_value).collect()),
104 akar_parser::ast::Expression::Map(items) => Value::Map(
105 items
106 .iter()
107 .map(|(k, v)| (Value::String(k.clone()), expr_to_value(v)))
108 .collect(),
109 ),
110 _ => Value::Null,
111 }
112}