This commit is contained in:
2026-08-20 20:43:18 -04:00
parent 025392b129
commit fcb1da7e0d
21 changed files with 637 additions and 178 deletions
+178 -153
View File
@@ -1,22 +1,21 @@
use std::collections::{HashMap, HashSet};
use crate::navigator::Navigator;
use crate::rdf::ontology::{LabeledIri, Ontology};
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;
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::grid::Sizing;
use iced::widget::{
button, center, column, combo_box, container, grid, mouse_area, opaque, operation, pick_list,
row, scrollable, space, stack, table, text, text_input, toggler,
};
use iced::window::Settings;
use iced::{Background, Color, Element, Length, Subscription, Task, color, keyboard, window};
use iced::advanced::text::Wrapping;
use ldp::middleware::BasicAuthMiddleware;
use ldp::model::{KeyedDataset, QuadKey};
use ldp::reqwest::{Client, Url};
@@ -24,15 +23,23 @@ 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,
TripleRef,
};
use tracing::{debug_span, error, trace};
use oxigraph::model::{BaseDirection, Dataset, 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_search::tantivy::schema::Value;
use crate::tasks;
#[derive(Clone, Debug)]
pub(crate) enum Message {
None,
ConnectToOntologyService(String),
ConnectedToOntologyService(Ontology),
CacheDatatypes(HashMap<NamedNode, ResourceDescription>),
CacheReadOnlyEntities(HashSet<ReadOnlyEntity>),
PopulateCaches,
LookupResourceDescription(NamedNode),
CacheResourceDescription(NamedNode, ResourceDescription),
WindowClosed(window::Id),
URLInputChanged(String),
URLInputSubmitted,
@@ -49,8 +56,8 @@ pub(crate) enum Message {
HoverRow(QuadKey),
UnhoverRow(QuadKey),
QueryUpdated(String),
SetSearchResults(Vec<()>),
QueryTypeUpdated(LabeledIri),
SetSearchResults(Vec<HashMap<gl_search::Field, gl_search::OwnedValue>>),
UpdateQueryClass(Class),
SearchResultClicked(NamedNode),
DatatypeUpdated(QuadKey, Option<String>),
LanguageUpdated(QuadKey, Option<String>),
@@ -68,11 +75,10 @@ pub(crate) enum Message {
NavigateBack,
NavigateForward,
ResetState,
SetReadOnly(bool),
SetInferredTypes(bool),
SetInferredProperties(bool),
SetShowReadOnly(bool),
SetShowInferredTriples(bool),
RunInference,
SetInferredTriples(Dataset),
SetInferredTriples(Graph),
Event(Event),
}
@@ -92,16 +98,18 @@ pub(crate) enum SearchResultClickAction {
struct SearchState {
window_id: window::Id,
action: SearchResultClickAction,
entity_selection: Option<LabeledIri>,
entity_class_selection: Option<Class>,
query: String,
results: Vec<()>,
results: Vec<HashMap<gl_search::Field, gl_search::OwnedValue>>,
}
pub(crate) struct Publisher {
http_client: ClientWithMiddleware,
curie_helper: CurieHelper,
ontology: Ontology,
ontology: Option<Ontology>,
read_only_entities: HashSet<ReadOnlyEntity>,
abbreviated_datatypes: Vec<String>,
resource_descriptions: HashMap<NamedNode, ResourceDescription>,
window_id: window::Id,
url_input: String,
url_input_valid: bool,
@@ -109,44 +117,34 @@ pub(crate) struct Publisher {
document: RdfSource<KeyedDataset<RowState>>,
inferred_triples: Graph,
show_read_only: bool,
show_inferred_types: bool,
show_inferred_properties: bool,
show_inferred_triples: bool,
hovered_row: Option<QuadKey>,
search_state: Option<SearchState>,
index: SearchIndex,
traversal: Option<Dataset>,
show_overwrite_confirmation: bool,
modified: bool,
show_new_document_buttons: bool,
}
impl Publisher {
pub(crate) fn new() -> (Self, Task<Message>) {
let curie_helper = CurieHelper::new(Ontology::prefixes().clone());
fn is_read_only<'a>(&'a self, triple: impl Into<TripleRef<'a>>) -> bool {
let triple = triple.into();
if triple.predicate == rdf::TYPE &&
let TermRef::NamedNode(node) = triple.object {
self.read_only_entities.contains(&ReadOnlyEntity::Class(node.into_owned()))
} else {
self.read_only_entities.contains(&ReadOnlyEntity::Property(triple.predicate.into_owned()))
}
}
let ontology = debug_span!("Ontology Creation").in_scope(|| {
Ontology::builder()
.with_path("/home/alex/.local/share/org.graphofliberty.desktop/ontology")
.build()
.expect("Failed to build ontology")
});
pub(crate) fn new() -> (Self, Task<Message>) {
let curie_helper = CurieHelper::new(gl_graph::PREFIXES.clone());
let index = SearchIndex::builder()
.with_path("/home/alex/.local/share/org.graphofliberty.desktop/index")
.build()
.expect("Failed to build search index");
let mut abbreviated_datatypes = ontology
.datatypes()
.into_iter()
.map(|node| {
curie_helper
.abbreviate(None, node.as_str())
.unwrap_or(node.as_str().to_string())
})
.collect::<Vec<_>>();
abbreviated_datatypes.sort();
let (id, task) = window::open(Settings::default());
let client = Client::new();
@@ -165,8 +163,10 @@ impl Publisher {
Self {
http_client,
curie_helper,
ontology,
abbreviated_datatypes,
ontology: None,
read_only_entities: HashSet::new(),
abbreviated_datatypes: Vec::new(),
resource_descriptions: HashMap::new(),
window_id: id,
url_input: starting_url.to_string(),
url_input_valid: true,
@@ -174,17 +174,15 @@ impl Publisher {
document,
inferred_triples: Graph::new(),
show_read_only: false,
show_inferred_types: false,
show_inferred_properties: false,
show_inferred_triples: false,
hovered_row: None,
search_state: None,
index,
traversal: None,
show_overwrite_confirmation: false,
modified: false,
show_new_document_buttons: false,
},
task.map(|_| Message::None),
task.map(|_| Message::ConnectToOntologyService("http://[::1]:3000".to_string())),
)
}
@@ -193,6 +191,39 @@ impl Publisher {
trace!(?message);
match message {
Message::ConnectToOntologyService(endpoint) => {
task = tasks::connect_to_ontology_service(endpoint)
.chain(Task::done(Message::PopulateCaches));
}
Message::ConnectedToOntologyService(ontology) => {
self.ontology = Some(ontology);
}
Message::PopulateCaches => {
if let Some(ontology) = &mut self.ontology {
task = Task::batch([
tasks::list_datatypes(ontology.clone()),
tasks::list_read_only_entities(ontology.clone()),
])
}
}
Message::CacheDatatypes(datatypes) => {
self.abbreviated_datatypes = datatypes.keys()
.map(|node| {
self.curie_helper.abbreviate(None, node.as_str())
.unwrap_or(node.as_str().to_string())
}).collect();
}
Message::CacheReadOnlyEntities(entities) => {
self.read_only_entities = entities;
}
Message::LookupResourceDescription(node) => {
if let Some(ontology) = &mut self.ontology {
task = tasks::lookup_resource_description(ontology.clone(), node)
}
}
Message::CacheResourceDescription(node, description) => {
self.resource_descriptions.insert(node, description);
}
Message::WindowClosed(id) => {
if self.window_id == id {
task = iced::exit();
@@ -248,16 +279,16 @@ impl Publisher {
});
}
Message::LoadDocument(document) => {
let messages = document.dataset().quads.iter().map(|(key, quad)| {
let add_row_tasks = document.dataset().quads.iter().map(|(key, quad)| {
let datatype_state = combo_box::State::new(self.abbreviated_datatypes.clone());
let state = RowState {
read_only: self.ontology.is_read_only(quad.as_ref()),
read_only: self.is_read_only(quad.as_ref()),
datatype_state,
};
Message::AddRow(Some((key, state)))
Task::done(Message::AddRow(Some((key, state))))
.chain(Task::done(Message::LookupResourceDescription(quad.predicate.clone())))
});
task = Task::batch(messages.map(Task::done))
task = Task::batch(add_row_tasks)
.chain(Task::done(Message::RunInference))
.chain(Task::done(Message::ResetState));
@@ -318,33 +349,29 @@ impl Publisher {
self.search_state = Some(SearchState {
window_id: id,
action,
entity_selection: None,
entity_class_selection: None,
query: String::new(),
results: Vec::new(),
});
task = window_task.then(|_| operation::focus("query"));
}
if let Some(selected_entity_class) = selected_entity_class {
let selection = self.ontology.info(
&selected_entity_class.into_owned(),
&*language::ENGLISH_OR_UNTAGGED,
);
task = task.chain(Task::done(Message::QueryTypeUpdated(selection)));
if let Some(selected_entity_class) = selected_entity_class &&
let Some(class) = Class::try_from_named_node(selected_entity_class) {
task = task.chain(Task::done(Message::UpdateQueryClass(class)))
}
}
Message::QueryTypeUpdated(type_) => {
Message::UpdateQueryClass(type_) => {
if let Some(search_state) = &mut self.search_state {
search_state.entity_selection = Some(type_);
search_state.entity_class_selection = Some(type_);
task = Task::done(Message::QueryUpdated(search_state.query.clone()));
}
}
Message::QueryUpdated(new_query) => {
if let Some(search_state) = &mut self.search_state {
let category_id = search_state
.entity_selection
.clone()
.and_then(|info| self.ontology.category_id(&info.iri));
let category_id = search_state.entity_class_selection
.as_ref()
.map(|selection| selection.to_owned() as u64);
let query = new_query.clone();
search_state.query = new_query;
@@ -352,7 +379,7 @@ impl Publisher {
.index
.query(category_id, query.as_str(), Schema::all_fields(), 25)
.expect("Unable to complete search");
task = Task::done(Message::SetSearchResults(vec![]));
task = Task::done(Message::SetSearchResults(results));
};
}
Message::SetSearchResults(results) => {
@@ -449,8 +476,16 @@ impl Publisher {
}
Message::SaveGraph(overwrite) => {
let client = self.http_client.clone();
let read_only_entities = self.read_only_entities.clone();
let options = SerializationOptions::from_format(RdfFormat::Turtle)
.with_filter(self.ontology.exclude_read_only());
.with_filter(move |triple| {
if triple.predicate == rdf::TYPE &&
let TermRef::NamedNode(node) = triple.object {
read_only_entities.contains(&ReadOnlyEntity::Class(node.into_owned()))
} else {
read_only_entities.contains(&ReadOnlyEntity::Property(triple.predicate.into_owned()))
}
});
let request = self
.document
.to_update(options)
@@ -538,19 +573,33 @@ impl Publisher {
task = Task::done(Message::URLInputChanged(url.to_string()))
.chain(Task::done(Message::NavigateTo(url)));
}
Message::SetReadOnly(value) => {
Message::SetShowReadOnly(value) => {
self.show_read_only = value;
}
Message::SetInferredTypes(value) => {
self.show_inferred_types = value;
}
Message::SetInferredProperties(value) => {
self.show_inferred_properties = value;
Message::SetShowInferredTriples(value) => {
self.show_inferred_triples = value;
}
Message::RunInference => {
if let Some(ontology) = &mut self.ontology {
let graph = self.document
.dataset()
.quads
.iter()
.map(|(_, quad)| Triple::from(quad.clone()))
.collect();
task = tasks::run_inference(ontology.clone(), graph);
}
}
Message::SetInferredTriples(dataset) => {
self.inferred_triples = Graph::from_iter(&dataset);
Message::SetInferredTriples(graph) => {
let messages = graph.iter()
.map(|triple| {
Message::LookupResourceDescription(triple.predicate.into_owned())
}).map(Task::done)
.collect::<Vec<_>>();
task = Task::batch(messages);
self.inferred_triples = graph;
}
Message::Event(Event::KeyPressed {
key: keyboard::Key::Named(key::Named::Tab),
@@ -582,7 +631,7 @@ impl Publisher {
fn view_row<'a>(
&'a self,
key: QuadKey,
triple: &'a Quad,
quad: &'a Quad,
state: &'a RowState,
) -> Element<'a, Message> {
const BUTTON_WIDTH: Length = Length::Fixed(35.0);
@@ -598,13 +647,13 @@ impl Publisher {
let base = self.document.origin().as_str();
let subject = match &triple.subject {
let subject = match &quad.subject {
NamedOrBlankNode::NamedNode(subject) => subject.as_str(),
_ => "",
};
let subject_input_base = iri_input(&self.curie_helper, "Subject", Some(&base), subject);
let subject_input = if self.ontology.is_read_only(triple.as_ref()) {
let subject_input = if state.read_only {
subject_input_base
} else {
subject_input_base.on_input(move |value| Message::SubjectUpdated(key, value))
@@ -614,9 +663,9 @@ impl Publisher {
&self.curie_helper,
"Predicate",
Some(&base),
triple.predicate.as_str(),
quad.predicate.as_str(),
);
let predicate_input = if self.ontology.is_read_only(triple.as_ref()) {
let predicate_input = if state.read_only {
predicate_input_base
} else {
predicate_input_base
@@ -627,19 +676,17 @@ impl Publisher {
.on_shift_click(Message::NavigateToPredicate(key))
};
let predicate_info = self
.ontology
.info(&triple.predicate, &*language::ENGLISH_OR_UNTAGGED);
let predicate_label = container(text(predicate_info.label));
let predicate_label = self.resource_descriptions
.get(&quad.predicate)
.and_then(|description| description.label.clone())
.map(|label| container(text(label)));
let term = TermHelper::new(&triple.object);
let term = TermHelper::new(&quad.object);
let value_label = term.value_as_named_node().and_then(|node| {
let info = self
.ontology
.info(&node.into_owned(), &*language::ENGLISH_OR_UNTAGGED);
Some(container(text(info.label)))
});
let value_label = term.value_as_named_node()
.and_then(|node| self.resource_descriptions.get(&node.into_owned()))
.and_then(|description| description.label.clone())
.map(|label| container(text(label)));
let value = term
.value_as_named_node()
@@ -658,7 +705,7 @@ impl Publisher {
// text_input as opposed to an iri_input.
let object_input: Element<Message> = if term.datatype().is_some() {
let base = text_input("Object", value.clone());
if self.ontology.is_read_only(triple.as_ref()) {
if state.read_only {
base.into()
} else {
base.on_input(move |value| Message::ObjectUpdated(key, value))
@@ -667,7 +714,7 @@ impl Publisher {
} else {
let base = iri_input(&self.curie_helper, "Object", Some(&base), value.as_str())
.on_shift_click(Message::NavigateToObject(key));
if self.ontology.is_read_only(triple.as_ref()) {
if state.read_only {
base.into()
} else {
base.align_x(value_alignment)
@@ -751,13 +798,13 @@ impl Publisher {
fn view_new_entity_buttons(
&self,
entities: impl IntoIterator<Item = LabeledIri>,
entities: impl IntoIterator<Item = ResourceDescription>,
) -> Element<'_, Message> {
let buttons = entities.into_iter().map(|entity| {
/*let buttons = entities.into_iter().map(|entity| {
let abbreviation = self
.curie_helper
.abbreviate(None, entity.iri.as_str())
.unwrap_or_else(|| entity.iri.as_str().to_string());
.abbreviate(None, entity.label.as_str())
.unwrap_or_else(|| entity.as_str().to_string());
let label = format!("{} ({})", entity.label, abbreviation);
button(text(label))
@@ -767,7 +814,8 @@ impl Publisher {
grid(buttons)
.height(Sizing::EvenlyDistribute(Length::Shrink))
.into()
.into()*/
text("to do").into()
}
pub(crate) fn view(&self, window: window::Id) -> Element<'_, Message> {
@@ -778,44 +826,27 @@ impl Publisher {
.on_input(Message::QueryUpdated)
.id("query");
let entities = Vec::new(); /*self.ontology
.searchable_classes(&*language::ENGLISH_OR_UNTAGGED)
.into_iter()
.collect::<Vec<_>>();*/
let type_selector = pick_list(
search_state.entity_selection.as_ref(),
entities,
search_state.entity_class_selection.as_ref(),
Class::ALL,
ToString::to_string,
)
.on_select(|selection| Message::QueryTypeUpdated(selection));
).on_select(|selection| Message::UpdateQueryClass(selection));
let mut columns = vec![table::column(text("CURIE"), |_| {
/*let iri = document
.get_first(Schema::iri_field())
let mut columns = vec![table::column(text("CURIE"), |document: &HashMap<gl_search::Field, gl_search::OwnedValue>| {
let iri = document.get(&Schema::iri_field())
.and_then(|value| value.as_str())
.unwrap_or_default();
let abbreviated_iri = self
.curie_helper
let abbreviated_iri = self.curie_helper
.abbreviate(None, iri)
.unwrap_or_else(|| iri.to_string());
button(text(abbreviated_iri).wrapping(Wrapping::Word))
.on_press(Message::SearchResultClicked(NamedNode::new_unchecked(iri)))
.style(button::text)*/
text("")
.style(button::text)
})];
let fields = if let Some(selection) = search_state.entity_selection.as_ref() {
self.ontology
.fields_for_class(&selection.iri, &*language::ENGLISH_OR_UNTAGGED)
.expect("Unable to load fields for class")
} else {
vec![]
};
/*for field in fields.into_iter() {
/*for field in {
let field_name = field.name.clone();
columns.push(
table::column(text(field.label), move |document: &SearchDocument| {
@@ -847,9 +878,7 @@ impl Publisher {
}
let back_button = button("\u{1f870}").on_press(Message::NavigateBack);
let forward_button = button("\u{1f872}").on_press(Message::NavigateForward);
let add_row_button = button("Add row").on_press(Message::AddRow(None));
let address_input = iri_input(&self.curie_helper, "URL", None, &self.url_input)
@@ -861,28 +890,29 @@ impl Publisher {
));
let mut rows: Vec<Element<Message>> = vec![];
rows = self
.document
rows = self.document
.dataset()
.iter_both()
.filter(|(_, _, state)| self.show_read_only || !state.read_only)
.map(|(key, quad, state)| self.view_row(key, quad, state))
.collect();
let body: Element<Message> = if self.show_new_document_buttons {
let body: Element<Message> = /*if self.show_new_document_buttons {
let subclasses = Vec::new(); // TODO self.ontology.subclasses_of(vocab::rda::ENTITY.into_owned());
let labeled_subclasses = subclasses
.iter()
.map(|iri| self.ontology.info(iri, &*language::ENGLISH_OR_UNTAGGED));
column![self.view_new_entity_buttons(labeled_subclasses)].into()
} else {
column(rows).into()
};
} else {*/
column(rows).into();
//};
let inference_table = if self.show_inferred_properties {
let inference_table = if self.show_inferred_triples {
let subject_column = table::column("Subject", |triple: TripleRef| {
let curie = if let NamedOrBlankNodeRef::NamedNode(subject) = triple.subject {
self.curie_helper.abbreviate(None, subject.as_str())
Some(self.curie_helper
.abbreviate(None, subject.as_str())
.unwrap_or_else(|| subject.as_str().to_string()))
} else {
None
};
@@ -891,18 +921,19 @@ impl Publisher {
});
let predicate_column = table::column("Predicate", |triple: TripleRef| {
let predicate_info = self.ontology.info(
&triple.predicate.into_owned(),
&*language::ENGLISH_OR_UNTAGGED,
);
let label = if predicate_info.label.is_empty() {
self.curie_helper
.abbreviate(None, triple.predicate.as_str())
.unwrap_or(triple.predicate.as_str().to_string())
let curie = self.curie_helper
.abbreviate(None, triple.predicate.as_str())
.unwrap_or_else(|| triple.predicate.as_str().to_string());
let label = self.resource_descriptions
.get(&triple.predicate.into_owned())
.and_then(|description| description.label.clone());
if let Some(label) = label {
text(format!("{curie} ({label})"))
} else {
predicate_info.label
};
text(label)
text(curie)
}
});
let object_column = table::column("Object", |triple: TripleRef| {
@@ -923,21 +954,15 @@ impl Publisher {
save_button_base
};
let inferred_type_toggle =
toggler(self.show_inferred_types).on_toggle(Message::SetInferredTypes);
let inferred_triples_toggle =
toggler(self.show_inferred_triples).on_toggle(Message::SetShowInferredTriples);
let inferred_property_toggle =
toggler(self.show_inferred_properties).on_toggle(Message::SetInferredProperties);
let read_only_toggle = toggler(self.show_read_only).on_toggle(Message::SetReadOnly);
let read_only_toggle = toggler(self.show_read_only).on_toggle(Message::SetShowReadOnly);
let footer = row![
space::horizontal(),
text("Show Inferred Types"),
inferred_type_toggle,
space::horizontal(),
text("Show Inferred Properties"),
inferred_property_toggle,
text("Show Inferred Triples"),
inferred_triples_toggle,
space::horizontal(),
text("Show Read Only Triples"),
read_only_toggle
+7 -1
View File
@@ -7,10 +7,13 @@ pub(crate) struct QueryArgs {
pub(crate) dataset_path: Option<PathBuf>,
#[arg(short, long, value_name = "QUERY PATH")]
pub(crate) query_path: PathBuf,
pub(crate) query_path: Option<PathBuf>,
#[arg(short, long, value_name = "BASE IRI")]
pub(crate) base: Option<String>,
#[arg(short, long)]
pub(crate) inferences_only: bool,
}
#[derive(Args)]
@@ -18,6 +21,9 @@ pub(crate) struct SearchArgs {
#[arg(short, long, value_name = "DOC TYPE")]
pub(crate) discriminant: Option<u64>,
#[arg(short, long, value_name = "LIMIT")]
pub(crate) limit: Option<usize>,
#[arg(value_name = "QUERY")]
pub(crate) query: String,
}
+19 -9
View File
@@ -5,7 +5,7 @@ mod navigator;
mod rdf;
mod theme;
mod widget;
mod windows;
mod tasks;
use std::collections::HashMap;
use crate::app::Publisher;
@@ -42,25 +42,23 @@ fn main() -> color_eyre::Result<()> {
.init();
color_eyre::install()?;
let mut index = SearchIndex::builder()
.with_path("/home/alex/.local/share/org.graphofliberty.desktop/index")
.build()
.expect("Failed to build search index");
let args = AppArgs::parse();
match args.command {
Some(Command::Query(args)) => {
let raw_query = String::from_utf8(std::fs::read(&args.query_path)?)?;
let raw_query = if let Some(query) = &args.query_path {
Some(String::from_utf8(std::fs::read(query)?)?)
} else { None };
let graph = if let Some(dataset_path) = &args.dataset_path {
Some(String::from_utf8(std::fs::read(dataset_path)?)?)
} else { None };
let mut request = OntologyQueryRequest::default();
request.sparql_query = Some(raw_query);
request.sparql_query = raw_query;
request.turtle = graph;
request.prefixes = HashMap::from_iter(gl_graph::PREFIXES.iter().map(|(name, iri)| (name.clone(), iri.clone())));
request.base = args.base.clone();
request.inferences_only = args.inferences_only;
let runtime = tokio::runtime::Builder::new_multi_thread()
.enable_all()
@@ -74,11 +72,22 @@ fn main() -> color_eyre::Result<()> {
});
}
Some(Command::Search(args)) => {
for document in index.query(args.discriminant, &args.query, Schema::all_fields(), 5000)? {
let mut index = SearchIndex::builder()
.with_path("/home/alex/.local/share/org.graphofliberty.desktop/index")
.build()
.expect("Failed to build search index");
let limit = args.limit.unwrap_or(5);
for document in index.query(args.discriminant, &args.query, Schema::all_fields(), limit)? {
println!("{}", gl_search::to_json(document));
}
}
Some(Command::Reindex) => {
let mut index = SearchIndex::builder()
.with_path("/home/alex/.local/share/org.graphofliberty.desktop/index")
.build()
.expect("Failed to build search index");
let mut writer = index.writer()?;
debug_span!("Clear Index").in_scope(|| {
writer.delete_all_documents()?;
@@ -147,6 +156,7 @@ fn main() -> color_eyre::Result<()> {
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)
+1 -1
View File
@@ -33,4 +33,4 @@ impl<T> Navigator<T> {
}
self.current()
}
}
}
+1 -1
View File
@@ -1,3 +1,3 @@
pub(crate) mod conversion;
pub(crate) mod ontology;
//pub(crate) mod ontology;
pub(crate) mod term_helper;
+52
View File
@@ -0,0 +1,52 @@
use iced::Task;
use oxigraph::model::{Graph, NamedNode};
use gl_graph::language;
use gl_graph::ontology::Ontology;
use crate::app::Message;
pub(crate) fn connect_to_ontology_service(endpoint: String) -> Task<Message> {
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 lookup_resource_description(mut ontology: Ontology, subject: NamedNode) -> Task<Message> {
let subject_clone = subject.clone();
Task::perform(async move { ontology.resource_description(subject_clone).await }, |result| {
match result {
Ok(description) => Message::CacheResourceDescription(subject, description),
Err(err) => Message::ShowError(err.to_string()),
}
})
}
pub(crate) fn list_datatypes(mut ontology: Ontology) -> Task<Message> {
Task::perform(async move { ontology.datatypes().await }, |result| {
match result {
Ok(datatypes) => Message::CacheDatatypes(datatypes),
Err(err) => Message::ShowError(err.to_string()),
}
})
}
pub(crate) fn list_read_only_entities(mut ontology: Ontology) -> Task<Message> {
Task::perform(async move { ontology.list_read_only().await }, |result| {
match result {
Ok(entities) => Message::CacheReadOnlyEntities(entities),
Err(err) => Message::ShowError(err.to_string()),
}
})
}
pub(crate) fn run_inference(mut ontology: Ontology, graph: Graph) -> Task<Message> {
Task::perform(async move { ontology.run_inference(&graph).await }, |result| {
match result {
Ok(inferences) => Message::SetInferredTriples(inferences),
Err(err) => Message::ShowError(err.to_string()),
}
})
}
-1
View File
@@ -1 +0,0 @@
View File