shacl_validation/constraints/core/value/
class.rs

1use crate::constraints::constraint_error::ConstraintError;
2use crate::constraints::NativeValidator;
3use crate::constraints::SparqlValidator;
4use crate::helpers::constraint::validate_ask_with;
5use crate::helpers::constraint::validate_with;
6use crate::helpers::srdf::get_objects_for;
7use crate::validation_report::result::ValidationResult;
8use crate::value_nodes::ValueNodeIteration;
9use crate::value_nodes::ValueNodes;
10use indoc::formatdoc;
11use shacl_ast::compiled::component::Class;
12use shacl_ast::compiled::component::CompiledComponent;
13use shacl_ast::compiled::shape::CompiledShape;
14use srdf::Query;
15use srdf::Sparql;
16use srdf::Term;
17use srdf::RDFS_SUBCLASS_OF;
18use srdf::RDF_TYPE;
19use std::fmt::Debug;
20
21impl<S: Query + 'static> NativeValidator<S> for Class<S> {
22    fn validate_native(
23        &self,
24        component: &CompiledComponent<S>,
25        shape: &CompiledShape<S>,
26        store: &S,
27        value_nodes: &ValueNodes<S>,
28        _source_shape: Option<&CompiledShape<S>>,
29    ) -> Result<Vec<ValidationResult>, ConstraintError> {
30        let class = |value_node: &S::Term| {
31            if value_node.is_literal() {
32                return true;
33            }
34
35            let is_class_valid = get_objects_for(store, value_node, &RDF_TYPE.clone().into())
36                .unwrap_or_default()
37                .iter()
38                .any(|ctype| {
39                    ctype == self.class_rule()
40                        || get_objects_for(store, ctype, &RDFS_SUBCLASS_OF.clone().into())
41                            .unwrap_or_default()
42                            .contains(self.class_rule())
43                });
44
45            !is_class_valid
46        };
47
48        validate_with(component, shape, value_nodes, ValueNodeIteration, class)
49    }
50}
51
52impl<S: Sparql + Debug + 'static> SparqlValidator<S> for Class<S> {
53    fn validate_sparql(
54        &self,
55        component: &CompiledComponent<S>,
56        shape: &CompiledShape<S>,
57        store: &S,
58        value_nodes: &ValueNodes<S>,
59        _source_shape: Option<&CompiledShape<S>>,
60    ) -> Result<Vec<ValidationResult>, ConstraintError> {
61        let class_value = self.class_rule().clone();
62
63        let query = move |value_node: &S::Term| {
64            formatdoc! {"
65            PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
66            PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
67            ASK {{ {} rdf:type/rdfs:subClassOf* {} }}
68        ", value_node, class_value,
69            }
70        };
71
72        validate_ask_with(component, shape, store, value_nodes, query)
73    }
74}