use crate::constraints::ShaclComponent;
use crate::constraints::SparqlDeref;
use crate::focus_nodes::FocusNodes;
use crate::helpers::sparql::select;
use crate::shacl_engine::engine::Engine;
use crate::validate_error::ValidateError;
use crate::validation_cache::ValidationCache;
use crate::validation_report::result::ValidationResult;
use crate::value_nodes::ValueNodes;
use indoc::formatdoc;
use iri_s::IriS;
use rudof_rdf::rdf_core::{
NeighsRDF, SHACLPath,
query::QueryRDF,
term::{Object, Term},
};
use shacl_ir::compiled::component_ir::ComponentIR;
use shacl_ir::compiled::shape::ShapeIR;
use shacl_ir::schema_ir::SchemaIR;
use shacl_ir::shape_label_idx::ShapeLabelIdx;
use std::fmt::Debug;
pub struct SparqlEngine {
cache: ValidationCache,
}
impl SparqlEngine {
pub fn new() -> Self {
Self {
cache: ValidationCache::new(),
}
}
}
impl Default for SparqlEngine {
fn default() -> Self {
Self::new()
}
}
impl<S: QueryRDF + NeighsRDF + Debug + 'static> Engine<S> for SparqlEngine {
fn evaluate(
&mut self,
store: &S,
shape: &ShapeIR,
component: &ComponentIR,
value_nodes: &ValueNodes<S>,
source_shape: Option<&ShapeIR>,
maybe_path: Option<SHACLPath>,
shape_graph: &SchemaIR,
) -> Result<Vec<ValidationResult>, Box<ValidateError>> {
let shacl_component = ShaclComponent::new(component);
let validator = shacl_component.deref();
let result = validator
.validate_sparql(
component,
shape,
store,
value_nodes,
source_shape,
maybe_path,
shape_graph,
)
.map_err(|e| {
Box::new(ValidateError::ConstraintError {
component: component.to_string(),
source: e,
})
})?;
Ok(result)
}
fn target_node(&self, store: &S, node: &Object) -> Result<FocusNodes<S>, Box<ValidateError>> {
let node: S::Term = node.clone().into();
if node.is_blank_node() {
return Err(Box::new(ValidateError::TargetNodeBlankNode));
}
let query = formatdoc! {"
SELECT DISTINCT ?this
WHERE {{
BIND ({} AS ?this)
}}
", node};
select(store, query, "this").map_err(|e| {
Box::new(ValidateError::SparqlError {
msg: "target_node".to_string(),
source: e,
})
})?;
Err(Box::new(ValidateError::NotImplemented {
msg: "target_node".to_string(),
}))
}
fn target_class(&self, store: &S, class: &Object) -> Result<FocusNodes<S>, Box<ValidateError>> {
let class: S::Term = class.clone().into();
if !class.is_iri() {
return Err(Box::new(ValidateError::TargetClassNotIri));
}
let query = formatdoc! {"
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT DISTINCT ?this
WHERE {{
?this rdf:type/rdfs:subClassOf* {} .
}}
", class};
select(store, query, "this").map_err(|e| {
Box::new(ValidateError::SparqlError {
msg: "target_class".to_string(),
source: e,
})
})?;
Err(Box::new(ValidateError::NotImplemented {
msg: "target_class".to_string(),
}))
}
fn target_subject_of(&self, store: &S, predicate: &IriS) -> Result<FocusNodes<S>, Box<ValidateError>> {
let query = formatdoc! {"
SELECT DISTINCT ?this
WHERE {{
?this {} ?any .
}}
", predicate};
select(store, query, "this").map_err(|e| {
Box::new(ValidateError::SparqlError {
msg: "target_subject_of".to_string(),
source: e,
})
})?;
Err(Box::new(ValidateError::NotImplemented {
msg: "target_subject_of".to_string(),
}))
}
fn target_object_of(&self, store: &S, predicate: &IriS) -> Result<FocusNodes<S>, Box<ValidateError>> {
let query = formatdoc! {"
SELECT DISTINCT ?this
WHERE {{
?any {} ?this .
}}
", predicate};
select(store, query, "this").map_err(|e| {
Box::new(ValidateError::SparqlError {
msg: "target_object_of".to_string(),
source: e,
})
})?;
Err(Box::new(ValidateError::NotImplemented {
msg: "target_object_of".to_string(),
}))
}
fn implicit_target_class(&self, _store: &S, _shape: &Object) -> Result<FocusNodes<S>, Box<ValidateError>> {
Err(Box::new(ValidateError::NotImplemented {
msg: "implicit_target_class".to_string(),
}))
}
fn record_validation(&mut self, node: Object, shape_idx: ShapeLabelIdx, results: Vec<ValidationResult>) {
self.cache.record(node, shape_idx, results);
}
fn has_validated(&self, node: &Object, shape_idx: ShapeLabelIdx) -> bool {
self.cache.has_validated(node, shape_idx)
}
fn get_cached_results(&self, node: &Object, shape_idx: ShapeLabelIdx) -> Option<&Vec<ValidationResult>> {
self.cache.get_results(node, shape_idx)
}
}