use oca_ast::ast::{AttributeType, NestedAttrType};
use oca_bundle::state::{attribute::Attribute, oca_bundle::OCABundleModel};
use serde_json::Value;
pub enum DataValidationStatus {
Valid,
Invalid(Vec<String>),
}
pub fn validate_data(
oca: &mut OCABundleModel,
data: &Value,
) -> Result<DataValidationStatus, String> {
let mut errors = vec![];
if !data.is_object() {
return Err("Data is not an object".to_string());
}
oca.fill_attributes();
for attr in oca.attributes.as_ref().unwrap().values() {
let value = data.get(attr.name.clone());
let attribute_errors = validate_attribute(attr, value)?;
if !attribute_errors.is_empty() {
errors.extend(attribute_errors);
}
}
if errors.is_empty() {
Ok(DataValidationStatus::Valid)
} else {
Ok(DataValidationStatus::Invalid(errors))
}
}
fn validate_attribute(
attribute: &Attribute,
value: Option<&serde_json::Value>,
) -> Result<Vec<String>, String> {
let mut errors = vec![];
let is_required = false;
let v = match value {
Some(value) => value,
None => {
if is_required {
errors.push(format!(
"Attribute \"{}\" value is mandatory",
attribute.name
));
}
return Ok(errors);
}
};
if v.is_array() || v.is_object() {
return Ok(errors);
}
if let Some(nested_attribute_type) = &attribute.attribute_type {
match nested_attribute_type {
NestedAttrType::Value(attribute_type) => match attribute_type {
AttributeType::Text => {
if !v.is_string() {
errors.push(format!(
"Attribute \"{}\" value ({}) is not a string",
attribute.name, v
));
}
}
AttributeType::Numeric => {
if !v.is_number() {
errors.push(format!(
"Attribute \"{}\" value ({}) is not a number",
attribute.name, v
));
}
}
AttributeType::DateTime => {
if !v.is_string() {
errors.push(format!(
"Attribute \"{}\" value ({}) is not a string",
attribute.name, v
));
}
}
AttributeType::Boolean => {
if !v.is_boolean() {
errors.push(format!(
"Attribute \"{}\" value ({}) is not a boolean",
attribute.name, v
));
}
}
AttributeType::Binary => {
if !v.is_string() {
errors.push(format!(
"Attribute \"{}\" value ({}) is not a string",
attribute.name, v
));
}
}
},
NestedAttrType::Array(_) => {
if !v.is_array() {
errors.push(format!(
"Attribute \"{}\" value ({}) is not an array",
attribute.name, v
));
}
}
NestedAttrType::Null => {}
_ => {}
}
}
Ok(errors)
}