.
This commit is contained in:
+100
-28
@@ -3,7 +3,6 @@ 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::vocab::rdac;
|
||||
use gl_search::language;
|
||||
use gl_search::{Schema, SearchDocument, SearchIndex, Value};
|
||||
use http::StatusCode;
|
||||
@@ -22,9 +21,11 @@ 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, NamedNode, NamedOrBlankNode, Quad, Term};
|
||||
use oxigraph::model::{BaseDirection, Dataset, Graph, NamedNode, NamedOrBlankNode, NamedOrBlankNodeRef, Quad, Term, TripleRef};
|
||||
use oxigraph::store::Store;
|
||||
use tracing::{debug_span, error, trace};
|
||||
use gl_graph::{vocab, CurieHelper};
|
||||
use gl_graph::CurieHelper;
|
||||
use gl_graph::inference::InferenceEngine;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) enum Message {
|
||||
@@ -38,7 +39,7 @@ pub(crate) enum Message {
|
||||
ShowNewDocumentButtons,
|
||||
HideNewDocumentButtons,
|
||||
ShowError(String),
|
||||
AddRow(Option<QuadKey>),
|
||||
AddRow(Option<(QuadKey, RowState)>),
|
||||
DeleteRow(QuadKey),
|
||||
DeleteAllRows,
|
||||
OpenQueryWindow(SearchResultClickAction),
|
||||
@@ -65,6 +66,10 @@ pub(crate) enum Message {
|
||||
NavigateForward,
|
||||
ResetState,
|
||||
SetReadOnly(bool),
|
||||
SetInferredTypes(bool),
|
||||
SetInferredProperties(bool),
|
||||
RunInference,
|
||||
SetInferredTriples(Dataset),
|
||||
Event(Event),
|
||||
}
|
||||
|
||||
@@ -93,13 +98,17 @@ pub(crate) struct Publisher {
|
||||
http_client: ClientWithMiddleware,
|
||||
curie_helper: CurieHelper,
|
||||
ontology: Ontology,
|
||||
inference_engine: InferenceEngine,
|
||||
abbreviated_datatypes: Vec<String>,
|
||||
window_id: window::Id,
|
||||
url_input: String,
|
||||
url_input_valid: bool,
|
||||
navigator: Navigator<Url>,
|
||||
document: RdfSource<KeyedDataset<RowState>>,
|
||||
inferred_triples: Graph,
|
||||
show_read_only: bool,
|
||||
show_inferred_types: bool,
|
||||
show_inferred_properties: bool,
|
||||
hovered_row: Option<QuadKey>,
|
||||
search_state: Option<SearchState>,
|
||||
index: SearchIndex,
|
||||
@@ -120,6 +129,8 @@ impl Publisher {
|
||||
.expect("Failed to build ontology")
|
||||
});
|
||||
|
||||
let inference_engine = InferenceEngine::new(ontology.store().clone());
|
||||
|
||||
let index = SearchIndex::builder()
|
||||
.with_path("/home/alex/.local/share/org.graphofliberty.desktop/index")
|
||||
.build()
|
||||
@@ -152,13 +163,17 @@ impl Publisher {
|
||||
http_client,
|
||||
curie_helper,
|
||||
ontology,
|
||||
inference_engine,
|
||||
abbreviated_datatypes,
|
||||
window_id: id,
|
||||
url_input: starting_url.to_string(),
|
||||
url_input_valid: true,
|
||||
navigator,
|
||||
document,
|
||||
inferred_triples: Graph::new(),
|
||||
show_read_only: false,
|
||||
show_inferred_types: false,
|
||||
show_inferred_properties: false,
|
||||
hovered_row: None,
|
||||
search_state: None,
|
||||
index,
|
||||
@@ -234,9 +249,21 @@ impl Publisher {
|
||||
let messages = document
|
||||
.dataset()
|
||||
.quads
|
||||
.keys()
|
||||
.map(|key| Message::AddRow(Some(key)));
|
||||
task = Task::batch(messages.map(Task::done)).chain(Task::done(Message::ResetState));
|
||||
.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()),
|
||||
datatype_state,
|
||||
};
|
||||
Message::AddRow(Some((key, state)))
|
||||
});
|
||||
task = Task::batch(messages.map(Task::done))
|
||||
.chain(Task::done(Message::RunInference))
|
||||
.chain(Task::done(Message::ResetState));
|
||||
|
||||
self.document = document;
|
||||
}
|
||||
@@ -250,33 +277,21 @@ impl Publisher {
|
||||
quad.object = Term::NamedNode(empty_node);
|
||||
|
||||
let key = self.document.dataset_mut().quads.insert(quad);
|
||||
task = Task::done(Message::AddRow(Some(key)));
|
||||
}
|
||||
Message::AddRow(Some(key)) => {
|
||||
let quad = self
|
||||
.document
|
||||
.dataset()
|
||||
.quads
|
||||
.get(key)
|
||||
.expect("Failed to get quad from document");
|
||||
let read_only = self.ontology.is_read_only(quad.as_ref());
|
||||
let term = TermHelper::new(&quad.object);
|
||||
let datatype = term
|
||||
.datatype()
|
||||
.map(|datatype| self.curie_helper.abbreviate(None, datatype.as_str())
|
||||
.unwrap_or(datatype.as_str().to_string()));
|
||||
|
||||
let datatype_state = combo_box::State::new(
|
||||
self.abbreviated_datatypes.clone(),
|
||||
);
|
||||
let state = RowState {
|
||||
read_only,
|
||||
read_only: false,
|
||||
datatype_state,
|
||||
};
|
||||
task = Task::done(Message::AddRow(Some((key, state))));
|
||||
}
|
||||
Message::AddRow(Some((key, state))) => {
|
||||
self.document
|
||||
.dataset_mut()
|
||||
.associated_data
|
||||
.insert(key, state);
|
||||
|
||||
self.modified = true;
|
||||
}
|
||||
Message::DeleteRow(key) => {
|
||||
@@ -472,7 +487,7 @@ impl Publisher {
|
||||
let subject = NamedNode::new_unchecked(url.as_str());
|
||||
self.document = RdfSource::new(url);
|
||||
|
||||
let template_quads = self
|
||||
/*let template_quads = self
|
||||
.ontology
|
||||
.template_triples(class.as_ref(), subject.as_ref())
|
||||
.map(|triples| {
|
||||
@@ -490,7 +505,7 @@ impl Publisher {
|
||||
|
||||
let new_keys = self.document.dataset_mut().extend(template_quads.into_iter());
|
||||
let messages = new_keys.map(|triple| Message::AddRow(Some(triple)));
|
||||
task = task.chain(Task::batch(messages.map(Task::done)));
|
||||
task = task.chain(Task::batch(messages.map(Task::done)));*/
|
||||
}
|
||||
Message::ResetState => {
|
||||
self.modified = false;
|
||||
@@ -526,6 +541,28 @@ impl Publisher {
|
||||
Message::SetReadOnly(value) => {
|
||||
self.show_read_only = value;
|
||||
}
|
||||
Message::SetInferredTypes(value) => {
|
||||
self.show_inferred_types = value;
|
||||
}
|
||||
Message::SetInferredProperties(value) => {
|
||||
self.show_inferred_properties = value;
|
||||
}
|
||||
Message::RunInference => {
|
||||
let dataset = self.document
|
||||
.dataset()
|
||||
.quads
|
||||
.iter()
|
||||
.map(|(_, quad)| quad)
|
||||
.collect();
|
||||
|
||||
let engine = self.inference_engine.clone();
|
||||
task = Task::perform(tokio::task::spawn_blocking(move || {
|
||||
engine.run(&dataset).unwrap()
|
||||
}), |dataset| Message::SetInferredTriples(dataset.unwrap()));
|
||||
}
|
||||
Message::SetInferredTriples(dataset) => {
|
||||
self.inferred_triples = Graph::from_iter(&dataset);
|
||||
}
|
||||
Message::Event(Event::KeyPressed {
|
||||
key: keyboard::Key::Named(key::Named::Tab),
|
||||
modifiers,
|
||||
@@ -823,6 +860,29 @@ impl Publisher {
|
||||
column(rows).into()
|
||||
};
|
||||
|
||||
let inference_table = if self.show_inferred_properties {
|
||||
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())
|
||||
} else { None };
|
||||
|
||||
curie.map(text)
|
||||
});
|
||||
|
||||
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())
|
||||
} else { predicate_info.label };
|
||||
text(label)
|
||||
});
|
||||
|
||||
let object_column = table::column("Object", |triple: TripleRef| text(triple.object.to_string()));
|
||||
Some(table([subject_column, predicate_column, object_column], self.inferred_triples.iter()))
|
||||
} else { None };
|
||||
|
||||
let save_button_base = button(text("\u{1f4be}"));
|
||||
let save_button = if self.modified {
|
||||
save_button_base.on_press(Message::SaveGraph(false))
|
||||
@@ -830,10 +890,22 @@ impl Publisher {
|
||||
save_button_base
|
||||
};
|
||||
|
||||
let inferred_type_toggle = toggler(self.show_inferred_types)
|
||||
.on_toggle(Message::SetInferredTypes);
|
||||
|
||||
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 footer = row![
|
||||
space::horizontal(),
|
||||
text("Show Inferred Types"),
|
||||
inferred_type_toggle,
|
||||
space::horizontal(),
|
||||
text("Show Inferred Properties"),
|
||||
inferred_property_toggle,
|
||||
space::horizontal(),
|
||||
text("Show Read Only Triples"),
|
||||
read_only_toggle
|
||||
@@ -847,9 +919,9 @@ impl Publisher {
|
||||
address_input,
|
||||
save_button,
|
||||
],
|
||||
scrollable(body),
|
||||
space::vertical(),
|
||||
footer,
|
||||
scrollable(body),
|
||||
scrollable(inference_table),
|
||||
])
|
||||
.on_back_click(Message::NavigateBack)
|
||||
.on_forward_click(Message::NavigateForward);
|
||||
|
||||
+9
-7
@@ -15,20 +15,19 @@ use ldp::reqwest::{Client, Url};
|
||||
use ldp::reqwest_middleware::ClientBuilder;
|
||||
use ldp::traverse::Traverse;
|
||||
use oxigraph::io::{RdfFormat, RdfParser, RdfSerializer};
|
||||
use oxigraph::model::{Dataset, Graph, GraphName, GraphNameRef, NamedNode, Quad, Triple};
|
||||
use oxigraph::model::{Dataset, GraphName, NamedNode, Quad, Triple};
|
||||
use oxigraph::sparql::{QueryResults, SparqlEvaluator};
|
||||
use oxigraph::sparql::results::{QueryResultsFormat, QueryResultsSerializer};
|
||||
use oxigraph::store::Store;
|
||||
use tracing::{debug, debug_span, error, field};
|
||||
use tracing::{debug_span, error, field};
|
||||
use crate::app::Publisher;
|
||||
use tracing_subscriber::layer::SubscriberExt;
|
||||
use tracing_subscriber::util::SubscriberInitExt;
|
||||
use tracing_subscriber::{EnvFilter, fmt};
|
||||
use tracing_subscriber::fmt::format::FmtSpan;
|
||||
use gl_graph::inference::InferenceEngine;
|
||||
use gl_search::{Document, Schema, SearchIndex};
|
||||
use gl_search::SearchIndex;
|
||||
use crate::args::{AppArgs, Command};
|
||||
use crate::rdf::ontology::Ontology;
|
||||
|
||||
fn main() -> color_eyre::Result<()> {
|
||||
let appender = tracing_appender::rolling::never("/tmp", "publisher-log");
|
||||
@@ -38,9 +37,6 @@ fn main() -> color_eyre::Result<()> {
|
||||
.init();
|
||||
color_eyre::install()?;
|
||||
|
||||
let store = Store::open("/home/alex/.local/share/org.graphofliberty.desktop/ontology")?;
|
||||
let inference_engine = InferenceEngine::new(store.clone());
|
||||
|
||||
let mut index = SearchIndex::builder()
|
||||
.with_path("/home/alex/.local/share/org.graphofliberty.desktop/index")
|
||||
.build()
|
||||
@@ -49,6 +45,9 @@ fn main() -> color_eyre::Result<()> {
|
||||
let args = AppArgs::parse();
|
||||
match args.command {
|
||||
Some(Command::Query(args)) => {
|
||||
let store = Store::open("/home/alex/.local/share/org.graphofliberty.desktop/ontology")?;
|
||||
let inference_engine = InferenceEngine::new(store.clone());
|
||||
|
||||
let graph_name = GraphName::NamedNode(NamedNode::new_unchecked(format!("file://{}", args.dataset_path.to_string_lossy())));
|
||||
let mut dataset = RdfParser::from_format(RdfFormat::Turtle)
|
||||
.with_default_graph(graph_name)
|
||||
@@ -92,6 +91,9 @@ fn main() -> color_eyre::Result<()> {
|
||||
}*/
|
||||
}
|
||||
Some(Command::Reindex) => {
|
||||
let store = Store::open("/home/alex/.local/share/org.graphofliberty.desktop/ontology")?;
|
||||
let inference_engine = InferenceEngine::new(store.clone());
|
||||
|
||||
let mut writer = index.writer()?;
|
||||
debug_span!("Clear Index").in_scope(|| {
|
||||
writer.delete_all_documents()?;
|
||||
|
||||
@@ -60,7 +60,6 @@ static PREFIXES: LazyLock<BTreeMap<String, String>> = LazyLock::new(|| {
|
||||
|
||||
pub struct OntologyBuilder {
|
||||
path: Option<PathBuf>,
|
||||
materialize_inferences: bool,
|
||||
}
|
||||
|
||||
impl OntologyBuilder {
|
||||
@@ -70,18 +69,9 @@ impl OntologyBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn materialize_inferences(mut self) -> Self {
|
||||
self.materialize_inferences = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> error::Result<Ontology> {
|
||||
let mut store = if let Some(path) = self.path {
|
||||
if self.materialize_inferences {
|
||||
Store::open(path)
|
||||
} else {
|
||||
Store::open_read_only(path)
|
||||
}
|
||||
let store = if let Some(path) = self.path {
|
||||
Store::open(path)
|
||||
} else {
|
||||
Store::new()
|
||||
}?;
|
||||
@@ -158,7 +148,6 @@ impl Ontology {
|
||||
pub fn builder() -> OntologyBuilder {
|
||||
OntologyBuilder {
|
||||
path: None,
|
||||
materialize_inferences: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user