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),
}
}
}