use super::super::*;
pub(in crate::transform::operators) fn eval_array_group_by(
args: &[Expr],
injected: Option<&EvalValue>,
record: &JsonValue,
context: Option<&JsonValue>,
out: &JsonValue,
base_path: &str,
locals: Option<&EvalLocals<'_>>,
) -> Result<EvalValue, TransformError> {
let total_len = args_len(args, injected);
if total_len != 2 {
return Err(TransformError::new(
TransformErrorKind::ExprError,
"expr.args must contain exactly two items",
)
.with_path(format!("{}.args", base_path)));
}
let array = eval_array_arg(0, args, injected, record, context, out, base_path, locals)?;
let expr = arg_expr_at(1, args, injected).ok_or_else(|| {
TransformError::new(
TransformErrorKind::ExprError,
"expr.args index is out of bounds",
)
.with_path(format!("{}.args[1]", base_path))
})?;
let expr_index = if injected.is_some() { 0 } else { 1 };
let expr_path = format!("{}.args[{}]", base_path, expr_index);
let mut results = Map::new();
for (index, item) in array.iter().enumerate() {
let item_locals = locals_with_item(locals, EvalItem { value: item, index });
let key = eval_key_expr_string(expr, record, context, out, &expr_path, Some(&item_locals))?;
let entry = results
.entry(key)
.or_insert_with(|| JsonValue::Array(Vec::new()));
if let JsonValue::Array(items) = entry {
items.push(item.clone());
}
}
Ok(EvalValue::Value(JsonValue::Object(results)))
}
pub(in crate::transform::operators) fn eval_array_key_by(
args: &[Expr],
injected: Option<&EvalValue>,
record: &JsonValue,
context: Option<&JsonValue>,
out: &JsonValue,
base_path: &str,
locals: Option<&EvalLocals<'_>>,
) -> Result<EvalValue, TransformError> {
let total_len = args_len(args, injected);
if total_len != 2 {
return Err(TransformError::new(
TransformErrorKind::ExprError,
"expr.args must contain exactly two items",
)
.with_path(format!("{}.args", base_path)));
}
let array = eval_array_arg(0, args, injected, record, context, out, base_path, locals)?;
let expr = arg_expr_at(1, args, injected).ok_or_else(|| {
TransformError::new(
TransformErrorKind::ExprError,
"expr.args index is out of bounds",
)
.with_path(format!("{}.args[1]", base_path))
})?;
let expr_index = if injected.is_some() { 0 } else { 1 };
let expr_path = format!("{}.args[{}]", base_path, expr_index);
let mut results = Map::new();
for (index, item) in array.iter().enumerate() {
let item_locals = locals_with_item(locals, EvalItem { value: item, index });
let key = eval_key_expr_string(expr, record, context, out, &expr_path, Some(&item_locals))?;
results.insert(key, item.clone());
}
Ok(EvalValue::Value(JsonValue::Object(results)))
}
pub(in crate::transform::operators) fn eval_array_distinct_by(
args: &[Expr],
injected: Option<&EvalValue>,
record: &JsonValue,
context: Option<&JsonValue>,
out: &JsonValue,
base_path: &str,
locals: Option<&EvalLocals<'_>>,
) -> Result<EvalValue, TransformError> {
let total_len = args_len(args, injected);
if total_len != 2 {
return Err(TransformError::new(
TransformErrorKind::ExprError,
"expr.args must contain exactly two items",
)
.with_path(format!("{}.args", base_path)));
}
let array = eval_array_arg(0, args, injected, record, context, out, base_path, locals)?;
let expr = arg_expr_at(1, args, injected).ok_or_else(|| {
TransformError::new(
TransformErrorKind::ExprError,
"expr.args index is out of bounds",
)
.with_path(format!("{}.args[1]", base_path))
})?;
let expr_index = if injected.is_some() { 0 } else { 1 };
let expr_path = format!("{}.args[{}]", base_path, expr_index);
let mut results = Vec::new();
let mut seen = HashSet::new();
for (index, item) in array.iter().enumerate() {
let item_locals = locals_with_item(locals, EvalItem { value: item, index });
let key = eval_key_expr_string(expr, record, context, out, &expr_path, Some(&item_locals))?;
if seen.insert(key) {
results.push(item.clone());
}
}
Ok(EvalValue::Value(JsonValue::Array(results)))
}