diff --git a/graph/src/error.rs b/graph/src/error.rs index a1e42de..f3ac0a4 100644 --- a/graph/src/error.rs +++ b/graph/src/error.rs @@ -30,4 +30,7 @@ pub enum Error { #[error(transparent)] TonicStatus(#[from] gl_inference::tonic::Status), + + #[error("Ontology client is not connected")] + NotConnected, } diff --git a/graph/src/indexer.rs b/graph/src/indexer.rs index c8c69fc..14bbb5e 100644 --- a/graph/src/indexer.rs +++ b/graph/src/indexer.rs @@ -1,16 +1,12 @@ use rayon::iter::ParallelIterator; use std::collections::{HashMap, HashSet}; use oxigraph::model::{Graph, NamedNode, TermRef, NamedOrBlankNodeRef, NamedNodeRef}; -use oxigraph::sparql::results::{QueryResultsFormat, QueryResultsParser, SliceQueryResultsParserOutput}; use rayon::iter::IntoParallelRefIterator; -use gl_inference::tonic::transport::Channel; -use gl_inference::proto::ontology_client::OntologyClient; -use gl_inference::proto::OntologyQueryRequest; use gl_search::{Field, OwnedValue, Schema}; use crate::class::Class; use crate::{helpers, vocab, CurieHelper}; -use crate::helpers::{term_as_str, term_to_named_node}; use crate::language::LanguageCondition; +use crate::ontology::ResourceDescription; pub struct Indexer<'a> { language: LanguageCondition, @@ -83,7 +79,7 @@ impl<'a> Indexer<'a> { ]) } - pub fn graph(&self, graph: &Graph) -> crate::Result>> { + pub fn graph(&self, graph: &Graph) -> Vec> { let mut entities_and_types = HashSet::new(); let triples = graph.triples_for_predicate(vocab::rdf::TYPE); for triple in triples { @@ -119,85 +115,42 @@ impl<'a> Indexer<'a> { }) }).collect(); - Ok(results) + results } - pub async fn ontology(&self, client: &mut OntologyClient) -> crate::Result>> { - let filter = LanguageCondition::filter([ - (String::from("label"), self.language.clone()), - (String::from("description"), self.language.clone()), - ]); + pub fn ontology(&self, entities: HashMap) -> Vec> { + let label_field = Schema::field("label", self.language.primary_language()); + let definition_field = Schema::field("definition", self.language.primary_language()); - let mut request = OntologyQueryRequest::default(); - request.sparql_query = Some(format!(r#"PREFIX rdf: -PREFIX rdfs: -PREFIX skos: - -SELECT ?class ?subject ?label ?description WHERE {{ - VALUES ?class {{ rdf:Property rdfs:Class skos:Concept }} - ?subject a ?class ; - rdfs:label ?label . - - OPTIONAL {{ ?subject rdfs:comment ?comment }} - OPTIONAL {{ ?subject skos:definition ?definition }} - BIND(COALESCE(?definition, ?comment) AS ?description) - {filter} -}}"#)); - - let response = client.query(request).await?; - let parser_output = QueryResultsParser::from_format(QueryResultsFormat::Json) - .for_slice(&response.get_ref().results)?; - - let mut results = Vec::new(); - if let SliceQueryResultsParserOutput::Solutions(solutions) = parser_output { - let primary_language = self.language.primary_language(); - let label_field = Schema::field("label", primary_language); - let definition_field = Schema::field("definition", primary_language); - for solution in solutions.filter_map(Result::ok) { + entities.iter() + .map(|(subject, (class, description))| { let mut document = HashMap::with_capacity(4); - let discriminant = solution - .get("class") - .and_then(term_to_named_node) - .and_then(Class::try_from_named_node) + let discriminant = Class::try_from_named_node(class) .map(|doc_type| doc_type as u64) .map(OwnedValue::U64) .unwrap_or(OwnedValue::Null); document.insert(Schema::discriminant_field(), discriminant); - let subject_str = solution - .get("subject") - .and_then(term_to_named_node) - .map(NamedNode::as_str); - - let curie = subject_str - .and_then(|subject| self.curie_helper.abbreviate(None, subject)) + let curie = self.curie_helper.abbreviate(None, subject.as_str()) .map(OwnedValue::Str) .unwrap_or(OwnedValue::Null); document.insert(Schema::curie_field(), curie); - let subject = subject_str - .map(OwnedValue::from) - .unwrap_or(OwnedValue::Null); + let subject = OwnedValue::from(subject.as_str()); document.insert(Schema::iri_field(), subject); - let label = solution - .get("label") - .and_then(term_as_str) + let label = description.label.clone() .map(OwnedValue::from) .unwrap_or(OwnedValue::Null); document.insert(label_field, label); - let definition = solution - .get("description") - .and_then(term_as_str) + let definition = description.description.clone() .map(OwnedValue::from) .unwrap_or(OwnedValue::Null); document.insert(definition_field, definition); - results.push(document); - } - } - Ok(results) + document + }).collect() } } \ No newline at end of file diff --git a/graph/src/language.rs b/graph/src/language.rs index b8237bc..8b4e6a9 100644 --- a/graph/src/language.rs +++ b/graph/src/language.rs @@ -53,47 +53,35 @@ impl LanguageCondition { } } - pub fn filter(conditions: impl IntoIterator) -> String { - let exact_expression = |variable: String, language| Expression::FunctionCall( + pub fn filter(&self, variable: impl Into) -> String { + let variable = variable.into(); + + let exact = |language: &LanguageTag| Expression::FunctionCall( Function::LangMatches, vec![ Expression::FunctionCall(Function::Lang, vec![ - Expression::Variable(Variable::new_unchecked(variable)) + Expression::Variable(Variable::new_unchecked(&variable)) ]), - Expression::Literal(Literal::new_simple_literal(language)) + Expression::Literal(Literal::new_simple_literal(language.to_string())) ], ); - - let untagged_expression = |variable| Expression::Not( + + let untagged = Expression::Not( Box::new(Expression::FunctionCall(Function::HasLang, vec![ - Expression::Variable(Variable::new_unchecked(variable)) + Expression::Variable(Variable::new_unchecked(&variable)) ])) ); - let condition_to_expression = |variable, condition| match condition { - LanguageCondition::ExactMatchOnly(language) => - Some(exact_expression(variable, language.to_string())), - LanguageCondition::ExactMatchOrUntagged(language) => { - Some(Expression::Or( - Box::new(exact_expression(variable.clone(), language.to_string())), - Box::new(untagged_expression(variable)), - )) - } - LanguageCondition::UntaggedOnly => Some(untagged_expression(variable)), - LanguageCondition::AnyOrNone => None, - }; - - let mut iter = conditions.into_iter(); - let first_expression = iter.next() - .and_then(|(variable, condition)| condition_to_expression(variable, condition)); - if let Some(expression) = first_expression { - let expr = iter.filter_map(|(variable, condition)| condition_to_expression(variable, condition)) - .fold(expression, |acc, next_exp| Expression::Or(Box::new(acc), Box::new(next_exp))); - GraphPattern::Filter { - expr, - inner: Box::new(GraphPattern::Bgp { patterns: vec![] }), - }.to_string() - } else { - String::default() - } + match self { + Self::ExactMatchOnly(language) => Some(exact(language)), + Self::ExactMatchOrUntagged(language) => Some(Expression::Or( + Box::new(exact(language)), + Box::new(untagged), + )), + Self::UntaggedOnly => Some(untagged), + Self::AnyOrNone => None, + }.map(|expr| GraphPattern::Filter { + expr, + inner: Box::new(GraphPattern::Bgp { patterns: vec![] }), + }.to_string()).unwrap_or_default() } } diff --git a/graph/src/ontology.rs b/graph/src/ontology.rs index 4b1ca04..b4bc1c0 100644 --- a/graph/src/ontology.rs +++ b/graph/src/ontology.rs @@ -1,12 +1,13 @@ use std::collections::{HashMap, HashSet}; use std::fmt::Debug; +use std::str::FromStr; use oxigraph::io::{RdfFormat, RdfParser, RdfSerializer}; -use oxigraph::model::{Graph, NamedNode, Triple, TripleRef}; +use oxigraph::model::{Graph, NamedNode, NamedNodeRef, Triple}; use oxigraph::sparql::results::{QueryResultsFormat, QueryResultsParser, SliceQueryResultsParserOutput}; -use tracing::debug; +use spargebra::algebra::GraphPattern; +use spargebra::term::{GroundTerm, Variable}; use gl_inference::proto::ontology_client::OntologyClient; use gl_inference::proto::OntologyQueryRequest; -use gl_inference::tonic::codegen::StdError; use gl_inference::tonic::transport::{Channel, Endpoint}; use crate::helpers::{term_as_str, term_to_named_node}; use crate::language::LanguageCondition; @@ -24,31 +25,51 @@ pub enum ReadOnlyEntity { Class(NamedNode), } +pub struct OntologyBuilder { + endpoint: Endpoint, + language: LanguageCondition, +} + +impl OntologyBuilder { + pub fn from_string(endpoint: &str, language: LanguageCondition) -> crate::Result { + let endpoint = Endpoint::from_str(endpoint)? + .connect_timeout(std::time::Duration::from_secs(10)) + .tcp_keepalive(Some(std::time::Duration::from_secs(30))) + .http2_keep_alive_interval(std::time::Duration::from_secs(15)) + .keep_alive_timeout(std::time::Duration::from_secs(20)) + .keep_alive_while_idle(true); + + Ok(Self { + endpoint, + language, + }) + } + + pub async fn connect(self) -> crate::Result { + let client = OntologyClient::connect(self.endpoint) + .await? + .max_decoding_message_size(1024 * 1024 * 1024); + + Ok(ConnectedOntology { + client, + language: self.language, + }) + } +} + #[derive(Clone)] -pub struct Ontology { +pub struct ConnectedOntology { client: OntologyClient, language: LanguageCondition, } -impl Debug for Ontology { +impl Debug for ConnectedOntology { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str("ontology") } } -impl Ontology { - pub async fn new(endpoint: D, language: LanguageCondition) -> crate::Result - where - D: TryInto, - D::Error: Into, - { - let client = OntologyClient::connect(endpoint).await?; - Ok(Self { - client, - language, - }) - } - +impl ConnectedOntology { pub async fn run_inference(&mut self, graph: &Graph) -> crate::Result { let mut output_buffer = Vec::new(); let mut serializer = RdfSerializer::from_format(RdfFormat::Turtle) @@ -118,23 +139,24 @@ SELECT ?subject ?class WHERE {{ } pub async fn datatypes(&mut self) -> crate::Result> { - let filter = LanguageCondition::filter([ - (String::from("label"), self.language.clone()), - (String::from("description"), self.language.clone()), - ]); + let label_filter = self.language.filter("label"); + let comment_filter = self.language.filter("comment"); let mut request = OntologyQueryRequest::default(); request.sparql_query = Some(format!(r#"PREFIX rdf: PREFIX rdfs: PREFIX skos: -SELECT ?subject ?label ?description WHERE {{ - ?subject a rdfs:Datatype - OPTIONAL {{ ?subject rdfs:label ?label }} - OPTIONAL {{ ?subject rdfs:comment ?comment }} - OPTIONAL {{ ?subject skos:definition ?definition }} - BIND(COALESCE(?definition, ?comment) AS ?description) - {filter} +SELECT ?subject ?label ?comment WHERE {{ + OPTIONAL {{ + ?subject a rdfs:Datatype + }} OPTIONAL {{ + ?subject rdfs:label ?label + {label_filter} + }} OPTIONAL {{ + ?subject rdfs:comment ?comment + {comment_filter} + }} }}"#)); let response = self.client.query(request).await?; @@ -167,12 +189,10 @@ SELECT ?subject ?label ?description WHERE {{ Ok(results) } - pub async fn resource_description(&mut self, subject: NamedNode) -> crate::Result { - let filter = LanguageCondition::filter([ - (String::from("label"), self.language.clone()), - (String::from("description"), self.language.clone()), - ]); - debug!("Filter: {filter}"); + pub async fn resource_description_from_subject(&mut self, subject: NamedNode) -> crate::Result { + let label_filter = self.language.filter("label"); + let comment_filter = self.language.filter("comment"); + let definition_filter = self.language.filter("definition"); let mut request = OntologyQueryRequest::default(); request.sparql_query = Some(format!(r#"PREFIX rdf: @@ -180,13 +200,21 @@ PREFIX rdfs: PREFIX skos: SELECT ?label ?description WHERE {{ - OPTIONAL {{ {subject} rdfs:label ?label }} - OPTIONAL {{ {subject} rdfs:comment ?comment }} - OPTIONAL {{ {subject} skos:definition ?definition }} + OPTIONAL {{ + {subject} rdfs:label ?label + {label_filter} + }} OPTIONAL {{ + {subject} rdfs:comment ?comment + {comment_filter} + }} OPTIONAL {{ + {subject} skos:definition ?definition + {definition_filter} + }} BIND(COALESCE(?definition, ?comment) AS ?description) - {filter} }}"#)); + let foo = request.sparql_query.clone().unwrap(); + let response = self.client.query(request).await?; let parser_output = QueryResultsParser::from_format(QueryResultsFormat::Json) .for_slice(&response.get_ref().results)?; @@ -213,4 +241,79 @@ SELECT ?label ?description WHERE {{ ) } else { unreachable!() } } + + fn named_nodes_to_values_expression<'a>(variable: &str, nodes: impl IntoIterator>) -> String { + let bindings = nodes.into_iter() + .map(|node| GroundTerm::NamedNode(node.into_owned())) + .map(Some) + .map(|item| vec![item]) + .collect(); + + GraphPattern::Values { + variables: vec![Variable::new_unchecked(variable)], + bindings, + }.to_string() + } + + pub async fn resource_descriptions_from_classes<'a>(&mut self, classes: impl IntoIterator>) -> crate::Result> { + let values = Self::named_nodes_to_values_expression("class", classes); + let label_filter = self.language.filter("label"); + let comment_filter = self.language.filter("comment"); + let definition_filter = self.language.filter("definition"); + + let mut request = OntologyQueryRequest::default(); + request.sparql_query = Some(format!(r#"PREFIX rdf: +PREFIX rdfs: +PREFIX skos: + +SELECT ?class ?subject ?label ?description WHERE {{ + {values} + ?subject a ?class . + OPTIONAL {{ + ?subject rdfs:label ?label . + {label_filter} + }} OPTIONAL {{ + ?subject rdfs:comment ?comment . + {comment_filter} + }} OPTIONAL {{ + ?subject skos:definition ?definition . + {definition_filter} + }} + BIND(COALESCE(?definition, ?comment) AS ?description) +}}"#)); + + let response = self.client.query(request).await?; + let parser_output = QueryResultsParser::from_format(QueryResultsFormat::Json) + .for_slice(&response.get_ref().results)?; + + let mut results = HashMap::new(); + if let SliceQueryResultsParserOutput::Solutions(solutions) = parser_output { + for solution in solutions.filter_map(Result::ok) { + let class = solution + .get("class") + .and_then(term_to_named_node); + + let subject = solution + .get("subject") + .and_then(term_to_named_node) + .map(|node| node.clone()); + + if let Some(subject) = subject && + let Some(class) = class { + let label = solution + .get("label") + .and_then(term_as_str) + .map(String::from); + + let description = solution + .get("description") + .and_then(term_as_str) + .map(String::from); + + results.insert(subject, (class.clone(), ResourceDescription { label, description })); + } + } + } + Ok(results) + } } \ No newline at end of file diff --git a/publish/src/app.rs b/publish/src/app.rs index cdac080..e921653 100644 --- a/publish/src/app.rs +++ b/publish/src/app.rs @@ -3,14 +3,14 @@ use crate::navigator::Navigator; use crate::rdf::term_helper::{TermHelper, TermHelperMut}; use crate::widget::iri_input::iri_input; use crate::widget::navigation_area::navigation_area; -use gl_graph::CurieHelper; +use gl_graph::{language, CurieHelper}; use gl_search::{Schema, SearchIndex}; use http::StatusCode; use iced::alignment::Horizontal; use iced::keyboard::{Event, key}; use iced::widget::button::Style; use iced::widget::{ - button, center, column, combo_box, container, grid, mouse_area, opaque, operation, pick_list, + button, center, column, combo_box, container, mouse_area, opaque, operation, pick_list, row, scrollable, space, stack, table, text, text_input, toggler, }; use iced::window::Settings; @@ -23,10 +23,10 @@ use ldp::reqwest_middleware::{ClientBuilder, ClientWithMiddleware}; use ldp::{RdfSource, RdfSourceUpdateResponse, ResourceRequestBuilder, SerializationOptions}; use oxigraph::io::RdfFormat; use oxigraph::model::vocab::{rdf, rdfs}; -use oxigraph::model::{BaseDirection, Dataset, Graph, NamedNode, NamedOrBlankNode, NamedOrBlankNodeRef, Quad, Term, TermRef, Triple, TripleRef}; +use oxigraph::model::{BaseDirection, Graph, NamedNode, NamedOrBlankNode, NamedOrBlankNodeRef, Quad, Term, TermRef, Triple, TripleRef}; use tracing::{debug, error, trace}; use gl_graph::class::Class; -use gl_graph::ontology::{Ontology, ReadOnlyEntity, ResourceDescription}; +use gl_graph::ontology::{ConnectedOntology, OntologyBuilder, ReadOnlyEntity, ResourceDescription}; use gl_search::tantivy::schema::Value; use crate::tasks; @@ -34,7 +34,7 @@ use crate::tasks; pub(crate) enum Message { None, ConnectToOntologyService(String), - ConnectedToOntologyService(Ontology), + ConnectedToOntologyService(ConnectedOntology), CacheDatatypes(HashMap), CacheReadOnlyEntities(HashSet), PopulateCaches, @@ -106,7 +106,7 @@ struct SearchState { pub(crate) struct Publisher { http_client: ClientWithMiddleware, curie_helper: CurieHelper, - ontology: Option, + ontology: Option, read_only_entities: HashSet, abbreviated_datatypes: Vec, resource_descriptions: HashMap, @@ -192,7 +192,10 @@ impl Publisher { match message { Message::ConnectToOntologyService(endpoint) => { - task = tasks::connect_to_ontology_service(endpoint) + let builder = OntologyBuilder::from_string(&endpoint, language::ENGLISH_OR_UNTAGGED.clone()) + .expect("Unable to parse endpoint of ontology service"); + + task = tasks::connect_to_ontology_service(builder) .chain(Task::done(Message::PopulateCaches)); } Message::ConnectedToOntologyService(ontology) => { @@ -217,8 +220,10 @@ impl Publisher { self.read_only_entities = entities; } Message::LookupResourceDescription(node) => { - if let Some(ontology) = &mut self.ontology { - task = tasks::lookup_resource_description(ontology.clone(), node) + if !self.resource_descriptions.contains_key(&node) { + if let Some(ontology) = &mut self.ontology { + task = tasks::lookup_resource_description(ontology.clone(), node) + } } } Message::CacheResourceDescription(node, description) => { diff --git a/publish/src/main.rs b/publish/src/main.rs index b9d05c8..d45a1b1 100644 --- a/publish/src/main.rs +++ b/publish/src/main.rs @@ -26,7 +26,8 @@ use tracing_subscriber::util::SubscriberInitExt; use tracing_subscriber::{EnvFilter, fmt}; use url::Url; use gl_graph::indexer::Indexer; -use gl_graph::{language, CurieHelper}; +use gl_graph::{language, CurieHelper, vocab}; +use gl_graph::ontology::OntologyBuilder; use gl_inference::proto::ontology_client::OntologyClient; use gl_inference::proto::OntologyQueryRequest; @@ -66,7 +67,11 @@ fn main() -> color_eyre::Result<()> { .build()?; runtime.block_on(async { - let mut client = OntologyClient::connect("http://[::1]:3000").await.unwrap(); + let mut client = OntologyClient::connect("http://[::1]:3000") + .await + .unwrap() + .max_decoding_message_size(1024 * 1024 * 1024); + let response = client.query(request).await.unwrap(); println!("{}", response.get_ref().results); }); @@ -103,8 +108,15 @@ fn main() -> color_eyre::Result<()> { let curie_helper = CurieHelper::new(gl_graph::PREFIXES.clone()); let indexer = Indexer::new(language::ENGLISH_OR_UNTAGGED.clone(), &curie_helper); - let mut client = OntologyClient::connect("http://[::1]:3000").await?; - let documents = indexer.ontology(&mut client).await?; + let mut client = OntologyBuilder::from_string("http://[::1]:3000", language::ENGLISH_OR_UNTAGGED.clone())? + .connect() + .await?; + let resource_descriptions = client.resource_descriptions_from_classes([ + vocab::rdf::PROPERTY, + vocab::rdfs::CLASS, + vocab::skos::CONCEPT, + ]).await?; + let documents = indexer.ontology(resource_descriptions); debug_span!("Index Ontology", documents = field::Empty).in_scope(|| { for document in documents { writer.add_document(document).unwrap(); @@ -122,13 +134,16 @@ fn main() -> color_eyre::Result<()> { .build(); let starting_url = Url::parse("http://fedora.quill.lan/rest/")?; - let mut dataset = Dataset::new(); + let mut graph = Graph::new(); let mut traversal = Traverse::new(http_client, starting_url, None); let mut rdf_source_count = 0usize; while let Some(result) = traversal.next().await { match result { Ok(rdf_source) => { - dataset.extend(rdf_source.dataset()); + let triples = rdf_source.dataset() + .iter() + .map(|quad| TripleRef::from(quad)); + graph.extend(triples); rdf_source_count += 1; }, Err(err) => error!(?err), @@ -140,32 +155,12 @@ fn main() -> color_eyre::Result<()> { let curie_helper = CurieHelper::new(gl_graph::PREFIXES.clone()); let indexer = Indexer::new(language::ENGLISH_OR_UNTAGGED.clone(), &curie_helper); - let mut client = OntologyClient::connect("http://[::1]:3000").await?; - let mut request = OntologyQueryRequest::default(); + let mut client = OntologyBuilder::from_string("http://[::1]:3000", language::ENGLISH_OR_UNTAGGED.clone())? + .connect() + .await?; - let mut output_buffer = Vec::new(); - let mut serializer = RdfSerializer::from_format(RdfFormat::Turtle) - .for_writer(output_buffer); - for quad in &dataset { - serializer.serialize_triple(TripleRef::from(quad))?; - } - output_buffer = serializer.finish()?; - let turtle = String::from_utf8_lossy(&output_buffer).to_string(); - - request.sparql_query = None; - request.turtle = Some(turtle); - request.prefixes = HashMap::new(); - request.base = None; - request.inferences_only = false; - - let response = client.query(request).await?; - let graph_with_inferences = RdfParser::from_format(RdfFormat::Turtle) - .for_slice(&response.get_ref().results) - .filter_map(Result::ok) - .map(Triple::from) - .collect::(); - - for document in indexer.graph(&graph_with_inferences)? { + let graph_with_inferences = client.run_inference(&graph).await?; + for document in indexer.graph(&graph_with_inferences) { writer.add_document(document)?; } diff --git a/publish/src/tasks.rs b/publish/src/tasks.rs index ab7e89f..dd95008 100644 --- a/publish/src/tasks.rs +++ b/publish/src/tasks.rs @@ -1,22 +1,20 @@ use iced::Task; use oxigraph::model::{Graph, NamedNode}; -use gl_graph::language; -use gl_graph::ontology::Ontology; +use gl_graph::ontology::{ConnectedOntology, OntologyBuilder}; use crate::app::Message; -pub(crate) fn connect_to_ontology_service(endpoint: String) -> Task { - Task::future(Ontology::new(endpoint, (&*language::ENGLISH_OR_UNTAGGED).clone())) - .then(|result| { - match result { - Ok(ontology) => Task::done(Message::ConnectedToOntologyService(ontology)), - Err(err) => Task::done(Message::ShowError(err.to_string())) - } - }) +pub(crate) fn connect_to_ontology_service(builder: OntologyBuilder) -> Task { + Task::perform(builder.connect(), |result| { + match result { + Ok(ontology) => Message::ConnectedToOntologyService(ontology), + Err(err) => Message::ShowError(err.to_string()) + } + }) } -pub(crate) fn lookup_resource_description(mut ontology: Ontology, subject: NamedNode) -> Task { +pub(crate) fn lookup_resource_description(mut ontology: ConnectedOntology, subject: NamedNode) -> Task { let subject_clone = subject.clone(); - Task::perform(async move { ontology.resource_description(subject_clone).await }, |result| { + Task::perform(async move { ontology.resource_description_from_subject(subject_clone).await }, |result| { match result { Ok(description) => Message::CacheResourceDescription(subject, description), Err(err) => Message::ShowError(err.to_string()), @@ -24,7 +22,7 @@ pub(crate) fn lookup_resource_description(mut ontology: Ontology, subject: Named }) } -pub(crate) fn list_datatypes(mut ontology: Ontology) -> Task { +pub(crate) fn list_datatypes(mut ontology: ConnectedOntology) -> Task { Task::perform(async move { ontology.datatypes().await }, |result| { match result { Ok(datatypes) => Message::CacheDatatypes(datatypes), @@ -33,7 +31,7 @@ pub(crate) fn list_datatypes(mut ontology: Ontology) -> Task { }) } -pub(crate) fn list_read_only_entities(mut ontology: Ontology) -> Task { +pub(crate) fn list_read_only_entities(mut ontology: ConnectedOntology) -> Task { Task::perform(async move { ontology.list_read_only().await }, |result| { match result { Ok(entities) => Message::CacheReadOnlyEntities(entities), @@ -42,7 +40,7 @@ pub(crate) fn list_read_only_entities(mut ontology: Ontology) -> Task { }) } -pub(crate) fn run_inference(mut ontology: Ontology, graph: Graph) -> Task { +pub(crate) fn run_inference(mut ontology: ConnectedOntology, graph: Graph) -> Task { Task::perform(async move { ontology.run_inference(&graph).await }, |result| { match result { Ok(inferences) => Message::SetInferredTriples(inferences),