use crate::formats::vcf::VcfRecord;
use crate::interval::annotation::AnnotationIndex;
use crate::interval::GenomicInterval;
#[derive(Debug, Clone)]
pub struct AnnotatedVcfRecord {
pub record: VcfRecord,
pub interval: GenomicInterval,
pub annotations: Vec<Vec<String>>,
}
impl AnnotatedVcfRecord {
pub fn new(record: VcfRecord) -> Self {
let interval: GenomicInterval = (&record).into();
Self {
record,
interval,
annotations: Vec::new(),
}
}
pub fn annotate_with(&mut self, index: &AnnotationIndex) {
let annotations: Vec<String> = index
.query(&self.interval)
.into_iter()
.map(|s| s.to_string())
.collect();
self.annotations.push(annotations);
}
pub fn all_annotations(&self) -> Vec<&str> {
self.annotations
.iter()
.flat_map(|v| v.iter().map(|s| s.as_str()))
.collect()
}
pub fn is_annotated(&self) -> bool {
self.annotations.iter().any(|v| !v.is_empty())
}
pub fn primary_annotation(&self) -> Option<&str> {
self.annotations
.first()
.and_then(|v| v.first())
.map(|s| s.as_str())
}
}
impl From<VcfRecord> for AnnotatedVcfRecord {
fn from(record: VcfRecord) -> Self {
Self::new(record)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_annotated_vcf_record() {
let record = VcfRecord {
chrom: "chr1".to_string(),
pos: 1000,
id: String::from(""),
reference: "A".to_string(),
alt: vec!["G".to_string()],
qual: Some(30.0),
filter: "PASS".to_string(),
info: String::from(""),
format: None,
samples: vec![],
};
let annotated = AnnotatedVcfRecord::new(record);
assert_eq!(annotated.interval.chrom, "chr1");
assert_eq!(annotated.interval.start, 999); assert_eq!(annotated.interval.end, 1000);
assert!(!annotated.is_annotated());
assert!(annotated.primary_annotation().is_none());
}
#[test]
fn test_annotation_methods() {
let record = VcfRecord {
chrom: "chr1".to_string(),
pos: 1000,
id: String::from(""),
reference: "A".to_string(),
alt: vec!["G".to_string()],
qual: Some(30.0),
filter: "PASS".to_string(),
info: String::from(""),
format: None,
samples: vec![],
};
let mut annotated = AnnotatedVcfRecord::new(record);
annotated.annotations.push(vec!["GeneA".to_string(), "GeneB".to_string()]);
annotated.annotations.push(vec!["Exon1".to_string()]);
assert!(annotated.is_annotated());
assert_eq!(annotated.primary_annotation(), Some("GeneA"));
let all = annotated.all_annotations();
assert_eq!(all.len(), 3);
assert!(all.contains(&"GeneA"));
assert!(all.contains(&"GeneB"));
assert!(all.contains(&"Exon1"));
}
}