rulemorph 0.3.4

YAML-based declarative data transformation engine for CSV/JSON to JSON
Documentation
use super::*;

pub(super) struct LookupArgs {
    pub(super) from_value: EvalValue,
    pub(super) match_key_value: EvalValue,
    pub(super) match_value: EvalValue,
    pub(super) get_field: Option<String>,
}

pub(super) fn resolve_lookup_args<'a>(
    op_step: &V2OpStep,
    pipe_value: EvalValue,
    record: &'a JsonValue,
    context: Option<&'a JsonValue>,
    out: &'a JsonValue,
    path: &str,
    ctx: &V2EvalContext<'a>,
) -> Result<Option<LookupArgs>, TransformError> {
    if op_step.args.len() < 2 {
        return Err(TransformError::new(
            TransformErrorKind::ExprError,
            format!(
                "{} requires at least 2 arguments: match_key, match_value",
                op_step.op
            ),
        )
        .with_path(path));
    }

    let args = &op_step.args;
    let get_path = format!("{}.get", path);
    let resolved = match args.len() {
        0 | 1 => unreachable!("guarded above"),
        2 => {
            let match_key_value = eval_v2_expr(
                &args[0],
                record,
                context,
                out,
                &format!("{}.args[0]", path),
                ctx,
            )?;
            let match_value = eval_v2_expr(
                &args[1],
                record,
                context,
                out,
                &format!("{}.args[1]", path),
                ctx,
            )?;
            LookupArgs {
                from_value: pipe_value,
                match_key_value,
                match_value,
                get_field: None,
            }
        }
        3 => {
            let first_value = eval_v2_expr(
                &args[0],
                record,
                context,
                out,
                &format!("{}.args[0]", path),
                ctx,
            )?;
            if matches!(pipe_value, EvalValue::Missing)
                && !matches!(first_value, EvalValue::Value(JsonValue::Array(_)))
            {
                return Ok(None);
            }

            let use_explicit_from = matches!(
                first_value,
                EvalValue::Value(JsonValue::Array(_)) | EvalValue::Missing
            );
            if use_explicit_from {
                let match_key_value = eval_v2_expr(
                    &args[1],
                    record,
                    context,
                    out,
                    &format!("{}.args[1]", path),
                    ctx,
                )?;
                let match_value = eval_v2_expr(
                    &args[2],
                    record,
                    context,
                    out,
                    &format!("{}.args[2]", path),
                    ctx,
                )?;
                LookupArgs {
                    from_value: first_value,
                    match_key_value,
                    match_value,
                    get_field: None,
                }
            } else {
                let match_value = eval_v2_expr(
                    &args[1],
                    record,
                    context,
                    out,
                    &format!("{}.args[1]", path),
                    ctx,
                )?;
                let get_value = eval_v2_expr(
                    &args[2],
                    record,
                    context,
                    out,
                    &format!("{}.args[2]", path),
                    ctx,
                )?;
                LookupArgs {
                    from_value: pipe_value,
                    match_key_value: first_value,
                    match_value,
                    get_field: Some(eval_value_as_string(&get_value, &get_path)?),
                }
            }
        }
        _ => {
            let from_value = eval_v2_expr(
                &args[0],
                record,
                context,
                out,
                &format!("{}.args[0]", path),
                ctx,
            )?;
            let match_key_value = eval_v2_expr(
                &args[1],
                record,
                context,
                out,
                &format!("{}.args[1]", path),
                ctx,
            )?;
            let match_value = eval_v2_expr(
                &args[2],
                record,
                context,
                out,
                &format!("{}.args[2]", path),
                ctx,
            )?;
            let get_value = eval_v2_expr(
                &args[3],
                record,
                context,
                out,
                &format!("{}.args[3]", path),
                ctx,
            )?;
            LookupArgs {
                from_value,
                match_key_value,
                match_value,
                get_field: Some(eval_value_as_string(&get_value, &get_path)?),
            }
        }
    };

    Ok(Some(resolved))
}