mod completeness;
mod consistency;
mod format;
mod uniqueness;
pub use completeness::{
CompletenessAnalysis, CompletenessAnalyzer, FieldCompleteness, FieldDefinition, FieldValue,
};
pub use consistency::{ConsistencyAnalysis, ConsistencyAnalyzer, ConsistencyRule};
pub use format::{FormatAnalysis, FormatAnalyzer, FormatVariation};
pub use uniqueness::{DuplicateInfo, UniqueRecord, UniquenessAnalysis, UniquenessAnalyzer};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct QualityEvaluation {
pub uniqueness: Option<UniquenessAnalysis>,
pub completeness: Option<CompletenessAnalysis>,
pub format: Option<FormatAnalysis>,
pub consistency: Option<ConsistencyAnalysis>,
pub overall_score: f64,
pub passes: bool,
pub issues: Vec<String>,
pub failures: Vec<String>,
}
impl QualityEvaluation {
pub fn new() -> Self {
Self {
uniqueness: None,
completeness: None,
format: None,
consistency: None,
overall_score: 1.0,
passes: true,
issues: Vec::new(),
failures: Vec::new(),
}
}
pub fn check_thresholds(&mut self, thresholds: &crate::config::EvaluationThresholds) {
self.issues.clear();
self.failures.clear();
let mut scores = Vec::new();
if let Some(ref uniqueness) = self.uniqueness {
if uniqueness.duplicate_rate > thresholds.duplicate_rate_max {
self.issues.push(format!(
"Duplicate rate {} > {} (threshold)",
uniqueness.duplicate_rate, thresholds.duplicate_rate_max
));
}
scores.push(1.0 - uniqueness.duplicate_rate);
}
if let Some(ref completeness) = self.completeness {
if completeness.overall_completeness < thresholds.completeness_rate_min {
self.issues.push(format!(
"Completeness {} < {} (threshold)",
completeness.overall_completeness, thresholds.completeness_rate_min
));
}
scores.push(completeness.overall_completeness);
}
if let Some(ref format) = self.format {
if format.consistency_score < thresholds.format_consistency_min {
self.issues.push(format!(
"Format consistency {} < {} (threshold)",
format.consistency_score, thresholds.format_consistency_min
));
}
scores.push(format.consistency_score);
}
if let Some(ref consistency) = self.consistency {
if consistency.pass_rate < thresholds.format_consistency_min {
self.issues.push(format!(
"Cross-field consistency {} < {} (threshold)",
consistency.pass_rate, thresholds.format_consistency_min
));
}
scores.push(consistency.pass_rate);
}
self.overall_score = if scores.is_empty() {
1.0
} else {
scores.iter().sum::<f64>() / scores.len() as f64
};
self.failures = self.issues.clone();
self.passes = self.issues.is_empty();
}
}
impl Default for QualityEvaluation {
fn default() -> Self {
Self::new()
}
}