1use crate::hierarchy::TaxonomyHierarchy;
4use ontologos_core::{EntityId, Ontology};
5
6use crate::{Error, Result};
7
8pub const OWL_NOTHING_IRI: &str = "http://www.w3.org/2002/07/owl#Nothing";
10
11fn lookup_query_class(ontology: &Ontology, class: &str) -> Result<EntityId> {
12 ontology
13 .lookup_entity(class)
14 .or_else(|| match class {
15 "owl:Nothing" => ontology.lookup_entity(OWL_NOTHING_IRI),
16 "owl:Thing" => ontology.lookup_entity("http://www.w3.org/2002/07/owl#Thing"),
17 _ => None,
18 })
19 .ok_or_else(|| Error::UnknownClass(class.to_owned()))
20}
21
22#[derive(Debug, Clone, PartialEq, Eq)]
24pub enum QueryAtom {
25 Type {
27 var: String,
29 class: String,
31 },
32 Subsumed {
34 var: String,
36 superclass: String,
38 },
39}
40
41#[derive(Debug, Clone, Default)]
43pub struct ConjunctiveQuery {
44 pub atoms: Vec<QueryAtom>,
46}
47
48#[derive(Debug, Clone, PartialEq, Eq)]
50pub struct QueryAnswer {
51 pub bindings: Vec<(String, EntityId)>,
53}
54
55pub fn evaluate(
57 engine: &TaxonomyHierarchy<'_>,
58 ontology: &Ontology,
59 query: &ConjunctiveQuery,
60) -> Result<Vec<QueryAnswer>> {
61 if query.atoms.len() > 1 {
62 return Err(crate::Error::Parse(
63 "conjunctive queries with more than one atom are not supported yet".into(),
64 ));
65 }
66 if query.atoms.is_empty() {
67 return Ok(Vec::new());
68 }
69 let atom = &query.atoms[0];
70 match atom {
71 QueryAtom::Type { var, class } => {
72 let class_id = lookup_query_class(ontology, class)?;
73 if engine.taxonomy().unsatisfiable.contains(&class_id) {
74 return Ok(Vec::new());
75 }
76 let subs = engine.direct_subclasses(class_id)?;
77 let mut answers = Vec::new();
78 for sub in subs {
79 answers.push(QueryAnswer {
80 bindings: vec![(var.clone(), sub)],
81 });
82 }
83 Ok(answers)
84 }
85 QueryAtom::Subsumed { var, superclass } => {
86 let sup_id = lookup_query_class(ontology, superclass)?;
87 if engine.taxonomy().unsatisfiable.contains(&sup_id) {
88 return Ok(Vec::new());
89 }
90 let subs = engine.direct_subclasses(sup_id)?;
91 let mut answers = Vec::new();
92 for sub in subs {
93 answers.push(QueryAnswer {
94 bindings: vec![(var.clone(), sub)],
95 });
96 }
97 Ok(answers)
98 }
99 }
100}