hypertune 0.6.2

Hypertune SDK for type safe configuration
Documentation
use serde_json::Map;
use serde_json::Number;
use serde_json::Value;
use thiserror::Error;

use crate::constants;
use crate::expression::*;

#[derive(Error, Debug)]
pub enum EvaluationError {
    #[error("expression can not be evaluated because it is not fully reduced into normal form")]
    ComplexFormExpression,
    #[error("could not convert float into JSON (because it's NaN or infinity)")]
    InvalidFloat,
    #[error("expression could not be evaluated because it is missing")]
    MissingExpression,
}

impl Expression {
    pub fn evaluate(&self) -> Result<(Value, Option<Logs>), EvaluationError> {
        let this_logs =
            Logs::merge(self.get_logs(), &Logs::evaluation_logs(self));

        match self {
            Expression::NoOp(_) => Ok((Value::Bool(true), this_logs)),
            Expression::Enum(EnumExpression { value, .. }) => {
                Ok((Value::String(value.clone()), this_logs))
            }
            Expression::Boolean(BooleanExpression { value, .. }) => {
                Ok((Value::Bool(*value), this_logs))
            }
            Expression::Int(IntExpression { value, .. }) => {
                Ok((Value::Number((*value).into()), this_logs))
            }
            Expression::Float(FloatExpression { value, .. }) => Ok((
                Value::Number(
                    Number::from_f64((*value).into_inner()).ok_or(EvaluationError::InvalidFloat)?,
                ),
                this_logs,
            )),
            Expression::String(StringExpression { value, .. }) => {
                Ok((Value::String(value.clone()), this_logs))
            }
            Expression::Regex(RegexExpression { value, .. }) => {
                Ok((Value::String(value.clone()), this_logs))
            }
            Expression::Object(ObjectExpression {
                fields,
                object_type_name,
                ..
            }) => {
                let evaluations: Vec<((String, Value), Option<Logs>)> = fields
                    .iter()
                    .map(|(key, value)| match value.evaluate() {
                        Ok((value, logs)) => Ok(((key.clone(), value), logs)),
                        Err(error) => Err(error),
                    })
                    .collect::<Result<_, _>>()?;

                let (mut fields, logs): (Map<String, Value>, Vec<Option<Logs>>) =
                    evaluations.into_iter().unzip();

                fields.insert(
                    constants::GRAPHQL_TYPE_NAME_KEY.to_string(),
                    Value::String(object_type_name.to_string()),
                );

                let logs = logs
                    .into_iter()
                    .fold(this_logs, |acc, l| Logs::merge(&acc, &l));

                Ok((Value::Object(fields), logs))
            }
            Expression::List(ListExpression { items, .. }) => {
                let evaluations: Vec<(Value, Option<Logs>)> = items
                    .iter()
                    .map(|expr| expr.evaluate())
                    .collect::<Result<_, _>>()?;

                let (items, logs): (Vec<Value>, Vec<Option<Logs>>) =
                    evaluations.into_iter().unzip();

                let logs = logs
                    .into_iter()
                    .fold(this_logs, |acc, l| Logs::merge(&acc, &l));

                Ok((Value::Array(items), logs))
            }
            Expression::GetField(_) => Err(EvaluationError::ComplexFormExpression),
            Expression::Function(_) => Err(EvaluationError::ComplexFormExpression),
            Expression::Switch(_) => Err(EvaluationError::ComplexFormExpression),
            Expression::Comparison(_) => Err(EvaluationError::ComplexFormExpression),
            Expression::Variable(_) => Err(EvaluationError::ComplexFormExpression),
            Expression::Application(_) => Err(EvaluationError::ComplexFormExpression),
            Expression::LogEvent(_) => Err(EvaluationError::ComplexFormExpression),
            Expression::Split(_) => Err(EvaluationError::ComplexFormExpression),
            Expression::EnumSwitch(_) => Err(EvaluationError::ComplexFormExpression),
            Expression::Arithmetic(_) => Err(EvaluationError::ComplexFormExpression),
            Expression::UpdateObject(_) => Err(EvaluationError::ComplexFormExpression),
            Expression::RoundNumber(_) => Err(EvaluationError::ComplexFormExpression),
            Expression::StringifyNumber(_) => Err(EvaluationError::ComplexFormExpression),
            Expression::StringConcat(_) => Err(EvaluationError::ComplexFormExpression),
            Expression::GetUrlQueryParameter(_) => Err(EvaluationError::ComplexFormExpression),
        }
    }
}