Files
tools/publish/src/rdf/materialize.rs
T
2026-06-30 19:25:15 -04:00

118 lines
3.9 KiB
Rust

use oxigraph::model::{Dataset, GraphName, NamedNodeRef, NamedOrBlankNode, NamedOrBlankNodeRef, Term};
use oxigraph::sparql::SparqlEvaluator;
use oxigraph::store::Store;
use tracing::{debug, debug_span};
use crate::error;
use crate::rdf::vocab::owl;
const INFERENCE_GRAPH: NamedNodeRef = NamedNodeRef::new_unchecked("https://graphofliberty.org/inference");
const RDF_SCHEMA: NamedNodeRef = NamedNodeRef::new_unchecked("http://www.w3.org/2000/01/rdf-schema#");
pub fn same_as(store: &mut Store) -> error::Result<()> {
let span = debug_span!("Materialize owl:sameAs");
let _enter = span.enter();
let additional_quads = store
.quads_for_pattern(None, Some(owl::SAME_AS), None, None)
.filter_map(Result::ok)
.fold(Dataset::new(), |mut new_dataset, alias| {
if let NamedOrBlankNode::NamedNode(x) = alias.subject
&& let Term::NamedNode(y) = alias.object
{
for mut quad in store.quads_for_pattern(
Some(NamedOrBlankNodeRef::NamedNode(x.as_ref())),
None,
None,
None,
).filter_map(Result::ok) {
quad.subject = NamedOrBlankNode::NamedNode(y.clone());
quad.graph_name = GraphName::NamedNode(INFERENCE_GRAPH.into_owned());
new_dataset.insert(quad.as_ref());
}
for mut quad in store.quads_for_pattern(
Some(NamedOrBlankNodeRef::NamedNode(y.as_ref())),
None,
None,
None,
).filter_map(Result::ok) {
quad.subject = NamedOrBlankNode::NamedNode(x.clone());
quad.graph_name = GraphName::NamedNode(INFERENCE_GRAPH.into_owned());
new_dataset.insert(quad.as_ref());
}
}
new_dataset
});
let old_size = store.len()?;
store.extend(&additional_quads)?;
let new_size = store.len()?;
if new_size > old_size {
let difference = new_size - old_size;
debug!(?old_size, ?new_size, ?difference, "same_as");
same_as(store)?;
}
Ok(())
}
pub fn super_properties(store: &mut Store) -> error::Result<()> {
let span = debug_span!("Materialize rdfs:subPropertyOf");
let _enter = span.enter();
let update = SparqlEvaluator::new()
.with_prefix("rdfs", RDF_SCHEMA.as_str())?
.with_prefix("inference", INFERENCE_GRAPH.as_str())?
.parse_update(r#"INSERT {
GRAPH inference: {
?property rdfs:subPropertyOf ?parent .
?subject ?parent ?object .
}
} WHERE {
GRAPH ?g1 { ?property rdfs:subPropertyOf+ ?parent }
OPTIONAL { GRAPH ?g2 { ?subject ?parent ?object } }
}"#)?;
let old_size = store.len()?;
update.on_store(&store).execute()?;
let new_size = store.len()?;
if new_size > old_size {
let difference = new_size - old_size;
debug!(?old_size, ?new_size, ?difference, "super_properties");
super_properties(store)?;
}
Ok(())
}
pub fn super_classes(store: &mut Store) -> error::Result<()> {
let span = debug_span!("Materialize rdfs:subClassOf");
let _enter = span.enter();
let update = SparqlEvaluator::new()
.with_prefix("rdfs", RDF_SCHEMA.as_str())?
.with_prefix("inference", INFERENCE_GRAPH.as_str())?
.parse_update(r#"INSERT {
GRAPH inference: {
?class rdfs:subClassOf ?parent .
?item a ?parent .
}
} WHERE {
GRAPH ?g1 { ?item a ?class }
GRAPH ?g2 { ?class rdfs:subClassOf+ ?parent }
}"#)?;
let old_size = store.len()?;
update.on_store(&store).execute()?;
let new_size = store.len()?;
if new_size > old_size {
let difference = new_size - old_size;
debug!(?old_size, ?new_size, ?difference, "super_classes");
super_classes(store)?;
}
Ok(())
}