Skip to main content

genomicframe_core/formats/fastq/
expression.rs

1use crate::error::{Error, Result};
2use crate::expression::{extract_f64, extract_usize, ExprToFilter};
3use crate::expression::{CompiledAndFilter, CompiledNotFilter, CompiledOrFilter, Expr};
4use crate::filters::RecordFilter;
5use crate::formats::fastq::filters::*;
6use crate::formats::fastq::FastqRecord;
7
8impl ExprToFilter<FastqRecord> for Expr {
9    fn compile(&self) -> Result<Box<dyn RecordFilter<FastqRecord>>> {
10        match self {
11            // Quality filter
12            Expr::Gt(left, right) | Expr::Gte(left, right) if matches!(**left, Expr::Column(ref name) if name == "quality" || name == "qual") =>
13            {
14                let min_mean_qual = extract_f64(right)?;
15                Ok(Box::new(QualityFilter { min_mean_qual }))
16            }
17
18            // Length filter
19            Expr::Gt(left, right) | Expr::Gte(left, right) if matches!(**left, Expr::Column(ref name) if name == "length") =>
20            {
21                let min_length = extract_usize(right)?;
22                Ok(Box::new(MinLengthFilter { min_length }))
23            }
24
25            Expr::Lt(left, right) | Expr::Lte(left, right) if matches!(**left, Expr::Column(ref name) if name == "length") =>
26            {
27                let max_length = extract_usize(right)?;
28                Ok(Box::new(LengthFilter {
29                    min_length: 0,
30                    max_length,
31                }))
32            }
33
34            // GC content filter
35            Expr::Gt(left, right) | Expr::Gte(left, right) if matches!(**left, Expr::Column(ref name) if name == "gc_content") =>
36            {
37                let min_gc = extract_f64(right)?;
38                Ok(Box::new(GCContentFilter {
39                    min_gc,
40                    max_gc: 1.0,
41                }))
42            }
43
44            // Boolean logic
45            Expr::And(exprs) => {
46                if exprs.is_empty() {
47                    return Err(Error::invalid_input("Empty AND expression"));
48                }
49
50                let mut result = exprs[0].compile()?;
51                for expr in &exprs[1..] {
52                    let next = expr.compile()?;
53                    result = Box::new(CompiledAndFilter {
54                        left: result,
55                        right: next,
56                    });
57                }
58                Ok(result)
59            }
60
61            Expr::Or(exprs) => {
62                if exprs.is_empty() {
63                    return Err(Error::invalid_input("Empty OR expression"));
64                }
65
66                let mut result = exprs[0].compile()?;
67                for expr in &exprs[1..] {
68                    let next = expr.compile()?;
69                    result = Box::new(CompiledOrFilter {
70                        left: result,
71                        right: next,
72                    });
73                }
74                Ok(result)
75            }
76
77            Expr::Not(expr) => {
78                let inner = expr.compile()?;
79                Ok(Box::new(CompiledNotFilter { inner }))
80            }
81
82            _ => Err(Error::invalid_input(format!(
83                "Expression not supported for FASTQ: {}",
84                self
85            ))),
86        }
87    }
88}