use crate::error::{Error, Result};
use crate::expression::{extract_f64, extract_i64, extract_string, ExprToFilter};
use crate::expression::{
extract_u32, CompiledAndFilter, CompiledNotFilter, CompiledOrFilter, Expr,
};
use crate::filters::RecordFilter;
use crate::formats::vcf::filters::*;
use crate::formats::vcf::VcfRecord;
impl ExprToFilter<VcfRecord> for Expr {
fn compile(&self) -> Result<Box<dyn RecordFilter<VcfRecord>>> {
match self {
Expr::IsTransition => Ok(Box::new(TransitionOnlyFilter)),
Expr::IsTransversion => Ok(Box::new(TransversionOnlyFilter)),
Expr::IsSnp => Ok(Box::new(SnpOnlyFilter)),
Expr::IsIndel => Ok(Box::new(IndelOnlyFilter)),
Expr::IsPass => Ok(Box::new(PassFilter)),
Expr::OnChromosome(chrom) => Ok(Box::new(ChromosomeFilter {
chromosome: chrom.clone(),
})),
Expr::Eq(left, right) if matches!(**left, Expr::Column(ref name) if name == "chrom") => {
let chrom = extract_string(right)?;
Ok(Box::new(ChromosomeFilter::new(chrom)))
}
Expr::InRegion(interval) => Ok(Box::new(RegionFilter {
intervals: vec![interval.clone()],
})),
Expr::Gt(left, right) if matches!(**left, Expr::Column(ref name) if name == "qual") => {
let min_qual = extract_f64(right)?;
Ok(Box::new(QualityFilter { min_qual }))
}
Expr::Gte(left, right) if matches!(**left, Expr::Column(ref name) if name == "qual") => {
let min_qual = extract_f64(right)?;
Ok(Box::new(QualityFilter { min_qual }))
}
Expr::Lt(left, right) if matches!(**left, Expr::Column(ref name) if name == "qual") => {
let max_qual = extract_f64(right)?;
Ok(Box::new(MaxQualityFilter { max_qual }))
}
Expr::Lte(left, right) if matches!(**left, Expr::Column(ref name) if name == "qual") => {
let max_qual = extract_f64(right)?;
Ok(Box::new(MaxQualityFilter { max_qual }))
}
Expr::Gt(left, right) if matches!(**left, Expr::Column(ref name) if name == "depth" || name == "dp") =>
{
let min_depth = extract_u32(right)?;
Ok(Box::new(DepthFilter { min_depth }))
}
Expr::Gte(left, right) if matches!(**left, Expr::Column(ref name) if name == "depth" || name == "dp") =>
{
let min_depth = extract_u32(right)?;
Ok(Box::new(DepthFilter { min_depth }))
}
Expr::Eq(left, right) if matches!(**left, Expr::Column(ref name) if name == "num_alt") => {
if extract_i64(right)? == 1 {
Ok(Box::new(BiAllelicFilter))
} else {
Err(Error::invalid_input(
"Only num_alt == 1 (bi-allelic) supported",
))
}
}
Expr::And(exprs) => {
if exprs.is_empty() {
return Err(Error::invalid_input("Empty AND expression"));
}
let mut result = exprs[0].compile()?;
for expr in &exprs[1..] {
let next = expr.compile()?;
result = Box::new(CompiledAndFilter {
left: result,
right: next,
});
}
Ok(result)
}
Expr::Or(exprs) => {
if exprs.is_empty() {
return Err(Error::invalid_input("Empty OR expression"));
}
let mut result = exprs[0].compile()?;
for expr in &exprs[1..] {
let next = expr.compile()?;
result = Box::new(CompiledOrFilter {
left: result,
right: next,
});
}
Ok(result)
}
Expr::Not(expr) => {
let inner = expr.compile()?;
Ok(Box::new(CompiledNotFilter { inner }))
}
_ => Err(Error::invalid_input(format!(
"Expression not supported for VCF: {}",
self
))),
}
}
}