shacl_validation/engine/
sparql.rs

1use indoc::formatdoc;
2use shacl_ast::compiled::component::CompiledComponent;
3use shacl_ast::compiled::property_shape::CompiledPropertyShape;
4use shacl_ast::compiled::shape::CompiledShape;
5use srdf::SHACLPath;
6use srdf::Sparql;
7use srdf::Term;
8
9use super::Engine;
10use crate::constraints::SparqlDeref;
11use crate::focus_nodes::FocusNodes;
12use crate::helpers::sparql::select;
13use crate::validate_error::ValidateError;
14use crate::validation_report::result::ValidationResult;
15use crate::value_nodes::ValueNodes;
16use std::fmt::Debug;
17
18pub struct SparqlEngine;
19
20impl<S: Sparql + Debug + 'static> Engine<S> for SparqlEngine {
21    fn evaluate(
22        &self,
23        store: &S,
24        shape: &CompiledShape<S>,
25        component: &CompiledComponent<S>,
26        value_nodes: &ValueNodes<S>,
27        source_shape: Option<&CompiledShape<S>>,
28    ) -> Result<Vec<ValidationResult>, ValidateError> {
29        let validator = component.deref();
30        Ok(validator.validate_sparql(component, shape, store, value_nodes, source_shape)?)
31    }
32
33    /// If s is a shape in a shapes graph SG and s has value t for sh:targetNode
34    /// in SG then { t } is a target from any data graph for s in SG.
35    fn target_node(&self, store: &S, node: &S::Term) -> Result<FocusNodes<S>, ValidateError> {
36        if node.is_blank_node() {
37            return Err(ValidateError::TargetNodeBlankNode);
38        }
39
40        let query = formatdoc! {"
41            SELECT DISTINCT ?this
42            WHERE {{
43                BIND ({} AS ?this)
44            }}
45        ", node};
46
47        select(store, query, "this")?;
48
49        Err(ValidateError::NotImplemented {
50            msg: "target_node".to_string(),
51        })
52    }
53
54    fn target_class(&self, store: &S, class: &S::Term) -> Result<FocusNodes<S>, ValidateError> {
55        if !class.is_iri() {
56            return Err(ValidateError::TargetClassNotIri);
57        }
58
59        let query = formatdoc! {"
60            PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
61            PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
62
63            SELECT DISTINCT ?this
64            WHERE {{
65                ?this rdf:type/rdfs:subClassOf* {} .
66            }}
67        ", class};
68
69        select(store, query, "this")?;
70
71        Err(ValidateError::NotImplemented {
72            msg: "target_class".to_string(),
73        })
74    }
75
76    fn target_subject_of(
77        &self,
78        store: &S,
79        predicate: &S::IRI,
80    ) -> Result<FocusNodes<S>, ValidateError> {
81        let query = formatdoc! {"
82            SELECT DISTINCT ?this
83            WHERE {{
84                ?this {} ?any .
85            }}
86        ", predicate};
87
88        select(store, query, "this")?;
89
90        Err(ValidateError::NotImplemented {
91            msg: "target_subject_of".to_string(),
92        })
93    }
94
95    fn target_object_of(
96        &self,
97        store: &S,
98        predicate: &S::IRI,
99    ) -> Result<FocusNodes<S>, ValidateError> {
100        let query = formatdoc! {"
101            SELECT DISTINCT ?this
102            WHERE {{
103                ?any {} ?this .
104            }}
105        ", predicate};
106
107        select(store, query, "this")?;
108
109        Err(ValidateError::NotImplemented {
110            msg: "target_object_of".to_string(),
111        })
112    }
113
114    fn implicit_target_class(
115        &self,
116        _store: &S,
117        _shape: &S::Term,
118    ) -> Result<FocusNodes<S>, ValidateError> {
119        Err(ValidateError::NotImplemented {
120            msg: "implicit_target_class".to_string(),
121        })
122    }
123
124    fn predicate(
125        &self,
126        _store: &S,
127        _shape: &CompiledPropertyShape<S>,
128        _predicate: &S::IRI,
129        _focus_node: &S::Term,
130    ) -> Result<FocusNodes<S>, ValidateError> {
131        Err(ValidateError::NotImplemented {
132            msg: "predicate".to_string(),
133        })
134    }
135
136    fn alternative(
137        &self,
138        _store: &S,
139        _shape: &CompiledPropertyShape<S>,
140        _paths: &[SHACLPath],
141        _focus_node: &S::Term,
142    ) -> Result<FocusNodes<S>, ValidateError> {
143        Err(ValidateError::NotImplemented {
144            msg: "alternative".to_string(),
145        })
146    }
147
148    fn sequence(
149        &self,
150        _store: &S,
151        _shape: &CompiledPropertyShape<S>,
152        _paths: &[SHACLPath],
153        _focus_node: &S::Term,
154    ) -> Result<FocusNodes<S>, ValidateError> {
155        Err(ValidateError::NotImplemented {
156            msg: "sequence".to_string(),
157        })
158    }
159
160    fn inverse(
161        &self,
162        _store: &S,
163        _shape: &CompiledPropertyShape<S>,
164        _path: &SHACLPath,
165        _focus_node: &S::Term,
166    ) -> Result<FocusNodes<S>, ValidateError> {
167        Err(ValidateError::NotImplemented {
168            msg: "inverse".to_string(),
169        })
170    }
171
172    fn zero_or_more(
173        &self,
174        _store: &S,
175        _shape: &CompiledPropertyShape<S>,
176        _path: &SHACLPath,
177        _focus_node: &S::Term,
178    ) -> Result<FocusNodes<S>, ValidateError> {
179        Err(ValidateError::NotImplemented {
180            msg: "zero_or_more".to_string(),
181        })
182    }
183
184    fn one_or_more(
185        &self,
186        _store: &S,
187        _shape: &CompiledPropertyShape<S>,
188        _path: &SHACLPath,
189        _focus_node: &S::Term,
190    ) -> Result<FocusNodes<S>, ValidateError> {
191        Err(ValidateError::NotImplemented {
192            msg: "one_or_more".to_string(),
193        })
194    }
195
196    fn zero_or_one(
197        &self,
198        _store: &S,
199        _shape: &CompiledPropertyShape<S>,
200        _path: &SHACLPath,
201        _focus_node: &S::Term,
202    ) -> Result<FocusNodes<S>, ValidateError> {
203        Err(ValidateError::NotImplemented {
204            msg: "zero_or_one".to_string(),
205        })
206    }
207}