use crate::jsoneval::types::{ValidationError, ValidationResult};
use indexmap::IndexMap;
use serde_json::Value;
#[derive(Clone, Debug)]
pub struct CachedFieldValidation {
pub field_data: Value,
pub is_hidden: bool,
pub validate_readonly: bool,
pub rules_snapshot: Value,
pub error: Option<ValidationError>,
}
#[derive(Clone, Default, Debug)]
pub struct ValidationCache {
pub last_data_str: Option<String>,
pub last_context_str: Option<String>,
pub last_validate_readonly: bool,
pub last_include_subforms: bool,
pub last_result: Option<ValidationResult>,
pub field_cache: IndexMap<String, CachedFieldValidation>,
}
impl ValidationCache {
pub fn new() -> Self {
Self::default()
}
#[inline]
pub fn get_cached_full_result(
&self,
data: &str,
context: Option<&str>,
validate_readonly: bool,
include_subforms: bool,
) -> Option<ValidationResult> {
if self.last_validate_readonly != validate_readonly
|| self.last_include_subforms != include_subforms
{
return None;
}
let last_data = self.last_data_str.as_deref()?;
if last_data != data {
return None;
}
let ctx_matches = match (self.last_context_str.as_deref(), context) {
(None, None) => true,
(Some(""), None) | (None, Some("")) => true,
(Some("{}"), None) | (None, Some("{}")) => true,
(Some(a), Some(b)) => a == b,
_ => false,
};
if ctx_matches {
self.last_result.clone()
} else {
None
}
}
#[inline]
pub fn check_field_cache(
&self,
field_path: &str,
field_data: &Value,
is_hidden: bool,
validate_readonly: bool,
rules: &Value,
) -> Option<Option<ValidationError>> {
let cached = self.field_cache.get(field_path)?;
if cached.is_hidden == is_hidden
&& cached.validate_readonly == validate_readonly
&& &cached.field_data == field_data
&& &cached.rules_snapshot == rules
{
Some(cached.error.clone())
} else {
None
}
}
#[inline]
pub fn update_field(
&mut self,
field_path: String,
field_data: Value,
is_hidden: bool,
validate_readonly: bool,
rules_snapshot: Value,
error: Option<ValidationError>,
) {
self.field_cache.insert(
field_path,
CachedFieldValidation {
field_data,
is_hidden,
validate_readonly,
rules_snapshot,
error,
},
);
}
#[inline]
pub fn save_full_result(
&mut self,
data_str: String,
context_str: Option<String>,
validate_readonly: bool,
include_subforms: bool,
result: ValidationResult,
) {
self.last_data_str = Some(data_str);
self.last_context_str = context_str;
self.last_validate_readonly = validate_readonly;
self.last_include_subforms = include_subforms;
self.last_result = Some(result);
}
#[inline]
pub fn invalidate_full_result(&mut self) {
self.last_data_str = None;
self.last_context_str = None;
self.last_validate_readonly = false;
self.last_include_subforms = false;
self.last_result = None;
}
#[inline]
pub fn clear(&mut self) {
self.last_data_str = None;
self.last_context_str = None;
self.last_validate_readonly = false;
self.last_include_subforms = false;
self.last_result = None;
self.field_cache.clear();
}
}