use crate::config::FuseRuleConfig;
use crate::evaluator::{DataFusionEvaluator, RuleEvaluator};
use crate::rule::Rule;
use crate::RuleEngine;
use anyhow::Result;
use clap::Parser;
#[derive(Parser)]
pub struct ValidateArgs {
#[arg(short, long)]
config: String,
#[arg(short, long)]
predicate: Option<String>,
}
pub async fn validate_rule(config_path: &str, predicate: Option<&str>) -> Result<()> {
let config = FuseRuleConfig::from_file(config_path)?;
if let Some(pred) = predicate {
let evaluator = DataFusionEvaluator::new();
let schema = RuleEngine::from_config(config.clone())
.await
.map(|e| e.schema())?;
let test_rule = Rule {
id: "test".to_string(),
name: "Test Rule".to_string(),
predicate: pred.to_string(),
action: "logger".to_string(),
window_seconds: None,
version: 1,
enabled: true,
};
match evaluator.compile(test_rule, &schema) {
Ok(_) => {
println!("✅ Predicate is valid");
Ok(())
}
Err(e) => {
eprintln!("❌ Predicate validation failed: {}", e);
Err(e)
}
}
} else {
let evaluator = DataFusionEvaluator::new();
let engine = RuleEngine::from_config(config.clone()).await?;
let schema = engine.schema();
let mut all_valid = true;
for rule_cfg in &config.rules {
let rule = Rule {
id: rule_cfg.id.clone(),
name: rule_cfg.name.clone(),
predicate: rule_cfg.predicate.clone(),
action: rule_cfg.action.clone(),
window_seconds: rule_cfg.window_seconds,
version: rule_cfg.version,
enabled: rule_cfg.enabled,
};
match evaluator.compile(rule.clone(), &schema) {
Ok(compiled) => {
println!("✅ Rule '{}' ({}): Valid", rule.name, rule.id);
if compiled.has_aggregates {
println!(" └─ Contains aggregate functions");
}
}
Err(e) => {
eprintln!("❌ Rule '{}' ({}): Invalid - {}", rule.name, rule.id, e);
all_valid = false;
}
}
}
if all_valid {
println!("\n✅ All rules are valid");
Ok(())
} else {
anyhow::bail!("Some rules failed validation");
}
}
}