jsonbuilder 0.1.0

A json builder used to create JSON structures using a simple DSL
Documentation
use crate::{
    context::Context,
    error::*,
    parser::{Expression as ExpressionAST, Statement as StatementAST},
};
use serde_json::{Map, Value};

use super::{
    block,
    error::{BuilderError, BuilderErrorKind},
    expression,
};

pub fn run(ast: StatementAST, context: &Context, value: &mut Value) -> Result<()> {
    match ast {
        StatementAST::Declare { left, right } => {
            let right = expression::evaluate(right, context)?;

            let left = match left {
                ExpressionAST::Identifier(identifier) => vec![identifier],
                ExpressionAST::Namespace(namespace) => namespace,
                ExpressionAST::Current => {
                    *value = right;

                    return Ok(());
                }
            };

            insert(value, left, right);
        }

        StatementAST::ArrayMap {
            left,
            placeholder,
            arg,
            block,
        } => {
            let left = match left {
                ExpressionAST::Identifier(identifier) => vec![identifier],
                ExpressionAST::Namespace(namespace) => namespace,
                ExpressionAST::Current => {
                    return Err(JsonBuilderError::BuilderError(BuilderError::from_error(
                        BuilderErrorKind::InvalidType(format!("{:?}", left)),
                    )))
                }
            };

            let arg = match arg {
                ExpressionAST::Identifier(identifier) => identifier,
                _ => {
                    return Err(JsonBuilderError::BuilderError(BuilderError::from_error(
                        BuilderErrorKind::InvalidType(format!("{:?}", arg)),
                    )))
                }
            };

            let placeholder = match expression::evaluate(placeholder.clone(), context)? {
                Value::Array(array) => array,
                _ => {
                    return Err(JsonBuilderError::BuilderError(BuilderError::from_error(
                        BuilderErrorKind::InvalidType(format!("{:?}", placeholder)),
                    )))
                }
            };

            let mut array = Vec::new();

            for array_values in placeholder {
                let mut context = context.clone();
                context.insert(arg.clone(), array_values);

                let mut block_value = Value::Object(Map::new());

                block::run(block.clone(), &context, &mut block_value)?;

                array.push(block_value);
            }

            insert(value, left, Value::Array(array));
        }

        StatementAST::Object { left, block } => {
            let left = match left {
                ExpressionAST::Identifier(identifier) => vec![identifier],
                ExpressionAST::Namespace(namespace) => namespace,
                ExpressionAST::Current => {
                    return Err(JsonBuilderError::BuilderError(BuilderError::from_error(
                        BuilderErrorKind::InvalidType(format!("{:?}", left)),
                    )))
                }
            };

            let mut block_value = Value::Object(Map::new());

            block::run(block, context, &mut block_value)?;

            insert(value, left, block_value);
        }
    }

    Ok(())
}

fn insert(value: &mut Value, mut keys: Vec<String>, right: Value) {
    let mut current = value;
    let last = keys.pop().unwrap();

    for key in keys.iter() {
        let entry = current
            .as_object_mut()
            .unwrap()
            .entry(key.clone())
            .or_insert_with(|| Value::Object(Map::new()));

        current = entry;
    }

    current.as_object_mut().unwrap().insert(last, right);
}