zen-engine 2.0.1

Business rules engine
Documentation
use std::sync::Arc;

use serde_json::{Map, Value};
use zen_expression::variable::VariableType;

use crate::workspace::db::Db;
use crate::workspace::types::ScopeRequest;

impl Db {
    pub fn input_skeleton(&self, req: &ScopeRequest) -> Value {
        let mut builder = SkeletonBuilder::new();
        for input in self.inputs(req) {
            builder.insert(&input.path, &input.resolved_type);
        }
        builder.into_value()
    }
}

struct SkeletonBuilder {
    root: Map<String, Value>,
}

impl SkeletonBuilder {
    fn new() -> Self {
        Self { root: Map::new() }
    }

    fn into_value(self) -> Value {
        Value::Object(self.root)
    }

    fn insert(&mut self, path: &Arc<str>, ty: &VariableType) {
        let value = Self::default_for(ty);
        let mut segments = path.split('.').peekable();
        let mut current = &mut self.root;
        while let Some(seg) = segments.next() {
            if segments.peek().is_none() {
                current.insert(seg.to_string(), value);
                return;
            }
            let entry = current
                .entry(seg.to_string())
                .or_insert_with(|| Value::Object(Map::new()));
            if !entry.is_object() {
                *entry = Value::Object(Map::new());
            }
            current = entry.as_object_mut().expect("just ensured object");
        }
    }

    fn default_for(ty: &VariableType) -> Value {
        match ty {
            VariableType::String | VariableType::Date | VariableType::Interval => {
                Value::String(String::new())
            }
            VariableType::Number => Value::Number(0u64.into()),
            VariableType::Bool => Value::Bool(false),
            VariableType::Null | VariableType::Any => Value::Null,
            VariableType::Nullable(_) => Value::Null,
            VariableType::Array(inner) => Value::Array(vec![Self::default_for(inner)]),
            VariableType::Const(c) => Value::String(c.to_string()),
            VariableType::Enum(_, values) => values
                .first()
                .map(|v| Value::String(v.to_string()))
                .unwrap_or(Value::Null),
            VariableType::Object(obj) => {
                let mut out = Map::new();
                for (k, v) in obj.borrow().iter() {
                    out.insert(k.to_string(), Self::default_for(v));
                }
                Value::Object(out)
            }
        }
    }
}