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 { ?class rdfs:subClassOf+ ?parent } OPTIONAL { GRAPH ?g2 { ?item a ?class } } }"#)?; 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(()) }