use serde_json::Value as JsonValue;
use crate::error::{TransformError, TransformErrorKind};
use crate::v2_eval::{
EvalItem, EvalValue, V2EvalContext, eval_v2_if_step, eval_v2_let_step, eval_v2_op_step,
eval_v2_ref,
};
use crate::v2_model::{V2MapStep, V2Step};
pub fn eval_v2_map_step<'a>(
map_step: &V2MapStep,
pipe_value: EvalValue,
record: &'a JsonValue,
context: Option<&'a JsonValue>,
out: &'a JsonValue,
path: &str,
ctx: &V2EvalContext<'a>,
) -> Result<EvalValue, TransformError> {
let arr = match &pipe_value {
EvalValue::Missing => {
return Ok(EvalValue::Missing);
}
EvalValue::Value(JsonValue::Array(arr)) => arr,
EvalValue::Value(other) => {
return Err(TransformError::new(
TransformErrorKind::ExprError,
format!("map step requires array, got {:?}", other),
)
.with_path(path));
}
};
let mut results = Vec::with_capacity(arr.len());
for (index, item_value) in arr.iter().enumerate() {
let item_path = format!("{}[{}]", path, index);
let item_ctx = ctx
.clone()
.with_pipe_value(EvalValue::Value(item_value.clone()))
.with_item(EvalItem {
value: item_value,
index,
});
let mut current = EvalValue::Value(item_value.clone());
let mut step_ctx = item_ctx.clone();
for (step_idx, step) in map_step.steps.iter().enumerate() {
let step_path = format!("{}.step[{}]", item_path, step_idx);
step_ctx = step_ctx.clone().with_pipe_value(current.clone());
match step {
V2Step::Op(op_step) => {
current = eval_v2_op_step(
op_step, current, record, context, out, &step_path, &step_ctx,
)?;
}
V2Step::Let(let_step) => {
step_ctx = eval_v2_let_step(
let_step,
current.clone(),
record,
context,
out,
&step_path,
&step_ctx,
)?;
current = step_ctx.get_pipe_value().cloned().unwrap_or(current);
}
V2Step::If(if_step) => {
current = eval_v2_if_step(
if_step, current, record, context, out, &step_path, &step_ctx,
)?;
}
V2Step::Map(nested_map) => {
current = eval_v2_map_step(
nested_map, current, record, context, out, &step_path, &step_ctx,
)?;
}
V2Step::Ref(v2_ref) => {
current = eval_v2_ref(v2_ref, record, context, out, &step_path, &step_ctx)?;
}
};
}
if let EvalValue::Value(v) = current {
results.push(v);
}
}
Ok(EvalValue::Value(JsonValue::Array(results)))
}