Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 11 additions & 9 deletions src/materializer.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
use crate::parsing::traits::ParsableNode;
use crate::tree::node::{DynamicNode, MaterializedNode};
use crate::tree::node_repository::NodeRepository;
use crate::tree::traits::LocatableNode;
use crate::tree::traits::{LocatableNode, NodeRepository};
use log::error;
use phenopackets::schema::v2::Phenopacket;
use phenopackets::schema::v2::core::{
Diagnosis, Disease, OntologyClass, PhenotypicFeature, Resource, VitalStatus,
};
use phenopackets::schema::v2::{Cohort, Phenopacket};

pub(crate) struct NodeMaterializer;

impl NodeMaterializer {
pub fn materialize_nodes(&mut self, dyn_node: &DynamicNode, repo: &mut NodeRepository) {
if let Some(oc) = OntologyClass::parse(dyn_node) {
pub fn materialize_nodes(&mut self, dyn_node: &DynamicNode, repo: &mut impl NodeRepository) {
if let Some(cohort) = Cohort::parse(dyn_node) {
Self::push_to_repo(cohort, dyn_node, repo);
} else if let Some(oc) = OntologyClass::parse(dyn_node) {
Self::push_to_repo(oc, dyn_node, repo);
} else if let Some(pf) = PhenotypicFeature::parse(dyn_node) {
Self::push_to_repo(pf, dyn_node, repo);
Expand All @@ -31,12 +32,13 @@ impl NodeMaterializer {
};
}

fn push_to_repo<T: 'static>(
materialized: T,
fn push_to_repo<NodeType: 'static + Clone>(
materialized: NodeType,
dyn_node: &DynamicNode,
board: &mut NodeRepository,
board: &mut impl NodeRepository,
) {
let node = MaterializedNode::from_dynamic(materialized, dyn_node);
board.insert(node);
// TODO: Error throwing
board.insert(node).expect("Unable to insert node");
}
}
20 changes: 18 additions & 2 deletions src/parsing/parseable_nodes.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,26 @@
use crate::parsing::traits::ParsableNode;
use crate::tree::node::DynamicNode;
use crate::tree::traits::LocatableNode;
use phenopackets::schema::v2::Phenopacket;
use phenopackets::schema::v2::core::{
Diagnosis, Disease, OntologyClass, PhenotypicFeature, Resource, VitalStatus,
};
use phenopackets::schema::v2::{Cohort, Phenopacket};
use serde_json::Value;

impl ParsableNode<Cohort> for Cohort {
fn parse(node: &DynamicNode) -> Option<Cohort> {
if let Value::Object(map) = &node.inner
&& map.contains_key("id")
&& map.contains_key("members")
&& let Ok(cohort) = serde_json::from_value::<Cohort>(node.inner.clone())
{
Some(cohort)
} else {
None
}
}
}

impl ParsableNode<OntologyClass> for OntologyClass {
fn parse(node: &DynamicNode) -> Option<OntologyClass> {
if let Value::Object(map) = &node.inner
Expand Down Expand Up @@ -41,7 +55,6 @@ impl ParsableNode<Phenopacket> for Phenopacket {
if let Value::Object(map) = &node.inner
&& map.contains_key("id")
&& map.contains_key("metaData")
&& node.pointer().is_root()
&& let Ok(pp) = serde_json::from_value::<Phenopacket>(node.inner.clone())
{
Some(pp)
Expand All @@ -57,6 +70,9 @@ impl ParsableNode<Resource> for Resource {
&& map.contains_key("id")
&& map.contains_key("name")
&& map.contains_key("url")
&& map.contains_key("namespacePrefix")
&& map.contains_key("version")
&& map.contains_key("iriPrefix")
&& let Ok(resource) = serde_json::from_value::<Resource>(node.inner.clone())
{
Some(resource)
Expand Down
15 changes: 3 additions & 12 deletions src/phenolint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use crate::diagnostics::enums::PhenopacketData;
use crate::diagnostics::{LintFinding, LintReport};
use crate::enums::InputTypes;
use crate::error::{InitError, LintResult, LinterError, ParsingError, validation_error_to_string};
use crate::materializer::NodeMaterializer;
use crate::parsing::phenopacket_parser::PhenopacketParser;
use crate::patches::patch_engine::PatchEngine;
use crate::patches::patch_registry::PatchRegistry;
Expand All @@ -12,23 +11,22 @@ use crate::report::report_registry::ReportRegistry;
use crate::rules::rule_registry::{RuleRegistry, check_duplicate_rule_ids};
use crate::schema_validation::validator::PhenopacketSchemaValidator;
use crate::traits::Lint;
use crate::tree::abstract_pheno_tree::AbstractTreeTraversal;
use crate::tree::node::DynamicNode;
use crate::tree::node_repository::NodeRepository;
use crate::tree::pointer::Pointer;
use log::{error, warn};
use phenopackets::schema::v2::Phenopacket;
use prost::Message;
use serde_json::Value;

use crate::tree::flat_node_repository::FlatNodeRepositoryBuilder;
use crate::tree::traits::NodeRepositoryBuilder;
use std::fs;
use std::path::PathBuf;

pub struct Phenolint {
rule_registry: RuleRegistry,
patch_registry: PatchRegistry,
report_registry: ReportRegistry,
node_materializer: NodeMaterializer,
patch_engine: PatchEngine,
validator: PhenopacketSchemaValidator,
}
Expand All @@ -45,7 +43,6 @@ impl Phenolint {
rule_registry,
report_registry,
patch_registry,
node_materializer: NodeMaterializer,
patch_engine: PatchEngine,
validator: PhenopacketSchemaValidator::default(),
}
Expand All @@ -70,13 +67,7 @@ impl Lint<str> for Phenolint {

let root_node = DynamicNode::new(&values, &spans, Pointer::at_root());

let apt = AbstractTreeTraversal::new(values, spans);
let mut node_repo: NodeRepository = NodeRepository::new();

for node in apt.traverse() {
self.node_materializer
.materialize_nodes(&node, &mut node_repo)
}
let node_repo = FlatNodeRepositoryBuilder::build(values, spans);

let mut findings = vec![];
for rule in self.rule_registry.rules() {
Expand Down
7 changes: 4 additions & 3 deletions src/rules/curies/curie_format_rule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ use crate::report::traits::{CompileReport, RegisterableReport, ReportFromContext
use crate::rules::rule_registration::RuleRegistration;
use crate::rules::traits::RuleMetaData;
use crate::rules::traits::{LintRule, RuleCheck, RuleFromContext};
use crate::tree::node_repository::List;
use crate::tree::querying::presentation::Flattened;
use crate::tree::querying::queries::convenience::All;
use crate::tree::traits::{LocatableNode, Node};
use phenolint_macros::{register_report, register_rule};
use phenopackets::schema::v2::core::OntologyClass;
Expand Down Expand Up @@ -38,9 +39,9 @@ impl RuleFromContext for CurieFormatRule {
}

impl RuleCheck for CurieFormatRule {
type Data<'a> = List<'a, OntologyClass>;
type Query = All<OntologyClass>;

fn check(&self, data: Self::Data<'_>) -> Vec<LintViolation> {
fn check(&self, data: Flattened<OntologyClass>) -> Vec<LintViolation> {
let mut violations = vec![];

for node in data.0.iter() {
Expand Down
56 changes: 30 additions & 26 deletions src/rules/interpretation/disease_consistency_rule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ use crate::report::traits::{CompileReport, RegisterableReport, ReportFromContext
use crate::rules::rule_registration::RuleRegistration;
use crate::rules::traits::RuleMetaData;
use crate::rules::traits::{LintRule, RuleCheck, RuleFromContext};
use crate::tree::node_repository::List;
use crate::tree::pointer::Pointer;
use crate::tree::querying::presentation::Grouped;
use crate::tree::querying::queries::convenience::GroupedIndividuals;
use crate::tree::traits::{LocatableNode, Node};
use phenolint_macros::{register_patch, register_report, register_rule};
use phenopackets::schema::v2::core::{Diagnosis, Disease, OntologyClass};
Expand All @@ -38,34 +39,37 @@ impl RuleFromContext for DiseaseConsistencyRule {
}

impl RuleCheck for DiseaseConsistencyRule {
type Data<'a> = (List<'a, Diagnosis>, List<'a, Disease>);
type Query = (GroupedIndividuals<Diagnosis>, GroupedIndividuals<Disease>);

fn check(&self, data: Self::Data<'_>) -> Vec<LintViolation> {
fn check(&self, data: (Grouped<Diagnosis>, Grouped<Disease>)) -> Vec<LintViolation> {
let mut violations = vec![];

let disease_terms: Vec<(&str, &str)> = data
.1
.iter()
.filter_map(|disease| {
disease
.inner
.term
.as_ref()
.map(|oc| (oc.id.as_str(), oc.label.as_str()))
})
.collect();

for diagnosis in data.0.iter() {
if let Some(oc) = &diagnosis.inner.disease
&& !disease_terms.contains(&(oc.id.as_str(), oc.label.as_str()))
{
violations.push(LintViolation::new(
ViolationSeverity::Warning,
LintRule::rule_id(self),
NonEmptyVec::with_single_entry(
diagnosis.pointer().clone().down("disease").clone(),
),
))
let (diagnosis_groups, diseases_group) = data;

for (diagnosis, diseases) in diagnosis_groups.0.iter().zip(diseases_group.0) {
let disease_terms: Vec<(&str, &str)> = diseases
.iter()
.filter_map(|disease| {
disease
.inner
.term
.as_ref()
.map(|oc| (oc.id.as_str(), oc.label.as_str()))
})
.collect();

for diagnosis in diagnosis.iter() {
if let Some(oc) = &diagnosis.inner.disease
&& !disease_terms.contains(&(oc.id.as_str(), oc.label.as_str()))
{
violations.push(LintViolation::new(
ViolationSeverity::Warning,
LintRule::rule_id(self),
NonEmptyVec::with_single_entry(
diagnosis.pointer().clone().down("disease").clone(),
),
))
}
}
}

Expand Down
49 changes: 28 additions & 21 deletions src/rules/resources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ use crate::report::traits::RuleReport;
use crate::report::traits::{CompileReport, RegisterableReport, ReportFromContext};
use crate::rules::rule_registration::RuleRegistration;
use crate::rules::traits::{LintRule, RuleCheck, RuleFromContext, RuleMetaData};
use crate::tree::node_repository::List;
use crate::tree::pointer::Pointer;
use crate::tree::querying::presentation::Grouped;
use crate::tree::querying::queries::convenience::GroupedIndividuals;
use crate::tree::traits::{LocatableNode, Node};
use phenolint_macros::{register_report, register_rule};
use phenopackets::schema::v2::core::{OntologyClass, Resource};
Expand All @@ -35,28 +36,34 @@ impl RuleFromContext for CuriesHaveResourcesRule {
}

impl RuleCheck for CuriesHaveResourcesRule {
type Data<'a> = (List<'a, OntologyClass>, List<'a, Resource>);

fn check(&self, data: Self::Data<'_>) -> Vec<LintViolation> {
let known_prefixes: HashSet<_> = data
.1
.iter()
.map(|r| r.inner.namespace_prefix.as_str())
.collect();
type Query = (
GroupedIndividuals<OntologyClass>,
GroupedIndividuals<Resource>,
);

fn check(&self, data: (Grouped<OntologyClass>, Grouped<Resource>)) -> Vec<LintViolation> {
let (ontology_classes, resources) = data;
let mut violations = vec![];

for node in data.0.iter() {
if let Some(prefix) = find_prefix(node.inner.id.as_str())
&& !known_prefixes.contains(prefix)
{
violations.push(LintViolation::new(
ViolationSeverity::Error,
LintRule::rule_id(self),
node.pointer().clone().into(), // <- warns about the ontology class itself
));
for (o, r) in ontology_classes.0.iter().zip(resources.0) {
let known_prefixes: HashSet<_> = r
.iter()
.map(|r| r.inner.namespace_prefix.as_str())
.collect();

for node in o.iter() {
if let Some(prefix) = find_prefix(node.inner.id.as_str())
&& !known_prefixes.contains(prefix)
{
violations.push(LintViolation::new(
ViolationSeverity::Error,
LintRule::rule_id(self),
node.pointer().clone().into(), // <- warns about the ontology class itself
));
}
}
}

violations
}
}
Expand All @@ -66,8 +73,8 @@ mod test_curies_have_resources {
use crate::rules::resources::CuriesHaveResourcesRule;
use crate::rules::traits::{RuleCheck, RuleMetaData};
use crate::tree::node::MaterializedNode;
use crate::tree::node_repository::List;
use crate::tree::pointer::Pointer;
use crate::tree::querying::presentation::Grouped;
use phenopackets::schema::v2::core::OntologyClass;

#[test]
Expand All @@ -82,8 +89,8 @@ mod test_curies_have_resources {
Default::default(),
Pointer::from("/phenotypicFeatures/0/type"),
)];
let resources = [];
let data = (List(&ocs), List(&resources));
let resources = vec![vec![]];
let data = (Grouped(vec![ocs.to_vec()]), Grouped(resources));

let violations = rule.check(data);

Expand Down
7 changes: 4 additions & 3 deletions src/rules/rule_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ mod tests {
use crate::rules::traits::RuleCheck;
use crate::rules::traits::RuleFromContext;
use crate::rules::traits::RuleMetaData;
use crate::tree::node_repository::List;
use crate::tree::querying::presentation::Flattened;
use crate::tree::querying::queries::convenience::All;
use phenolint_macros::register_rule;
use phenopackets::schema::v2::core::OntologyClass;
use rstest::rstest;
Expand All @@ -100,9 +101,9 @@ mod tests {
}
}
impl RuleCheck for TestRule {
type Data<'a> = List<'a, OntologyClass>;
type Query = All<OntologyClass>;

fn check(&self, _: Self::Data<'_>) -> Vec<LintViolation> {
fn check(&self, _: Flattened<OntologyClass>) -> Vec<LintViolation> {
todo!()
}
}
Expand Down
Loading
Loading