use serde_json::Value;
use crate::{
expression::{self, Expression},
operators::Operator,
};
pub type ValidationResult = Result<(), ValidationError>;
#[derive(Debug, PartialEq)]
pub struct ValidationError {
pub message: String,
pub path: String,
}
impl ValidationError {
pub fn new(message: &str, path: &str) -> Self {
ValidationError {
message: message.to_string(),
path: path.to_string(),
}
}
}
pub struct ValidationConfig {
pub require_and_wrapper: Option<RequireAndWrapper>,
}
#[derive(Debug, Clone, Copy)]
pub struct RequireAndWrapper {
pub allow_empty: bool,
}
impl Default for ValidationConfig {
fn default() -> Self {
ValidationConfig {
require_and_wrapper: None,
}
}
}
pub fn validate(json_logic: &Value, config: &ValidationConfig) -> ValidationResult {
if let Some(require_and) = &config.require_and_wrapper {
validate_and_wrapper(json_logic, require_and)?;
}
Ok(())
}
fn validate_and_wrapper(json_logic: &Value, config: &RequireAndWrapper) -> ValidationResult {
let ast = expression::Expression::from_json(json_logic)
.map_err(|err| ValidationError::new(&err.to_string(), "$"))?;
match ast {
Expression::Constant(Value::Object(obj)) if obj.is_empty() && config.allow_empty => Ok(()),
Expression::Constant(Value::Object(obj)) if obj.is_empty() && !config.allow_empty => {
Err(ValidationError::new("Empty JSON Logic is not allowed", "$"))
}
Expression::Computed(Operator::And, _) => Ok(()),
_ => Err(ValidationError::new(
"JSON Logic must be wrapped in an 'and' block",
"$",
)),
}
}