rudof_rdf/rdf_core/focus_rdf.rs
1use crate::rdf_core::{
2 NeighsRDF, RDFError, SHACLPath,
3 parser::rdf_node_parser::{RDFNodeParse, constructors::ShaclPathParser},
4};
5
6/// A trait for RDF graphs that maintain a focus node for context-aware parsing.
7///
8/// `FocusRDF` extends [`NeighsRDF`] by adding the concept of a "focus node" - a current
9/// point of reference within the RDF graph. This focus node serves as the starting point
10/// for parsing operations, allowing parsers to navigate the graph structure from a specific
11/// node without repeatedly specifying it.
12///
13/// The focus node pattern is commonly used in RDF validation (like SHACL) and graph
14/// traversal scenarios where operations are performed relative to a particular node.
15pub trait FocusRDF: NeighsRDF
16where
17 Self: 'static,
18{
19 /// Sets the current focus node.
20 ///
21 /// # Arguments
22 ///
23 /// * `focus` - The RDF term to set as the new focus node
24 fn set_focus(&mut self, focus: &Self::Term);
25
26 /// Retrieves the current focus node if one is set.
27 ///
28 /// # Returns
29 ///
30 /// A reference to `Some(term)` if a focus is set, or `None` otherwise
31 fn get_focus(&self) -> Option<&Self::Term>;
32
33 /// Retrieves the current focus node as a term, failing if no focus is set.
34 ///
35 /// This is a convenience method that unwraps the focus option and returns
36 /// an error if no focus node is currently set. Useful when a focus is required
37 /// for an operation to proceed.
38 ///
39 /// # Returns
40 ///
41 /// * `Ok(&term)` - A reference to the current focus node
42 /// * `Err(RDFError::NoFocusNodeError)` - If no focus is currently set
43 fn get_focus_as_term(&self) -> Result<&Self::Term, RDFError> {
44 match self.get_focus() {
45 None => Err(RDFError::NoFocusNodeError),
46 Some(term) => Ok(term),
47 }
48 }
49
50 /// Retrieves the current focus node as a subject, failing if not set or not a valid subject.
51 ///
52 /// # Returns
53 ///
54 /// * `Ok(subject)` - The current focus as a subject node
55 /// * `Err(RDFError::NoFocusNodeError)` - If no focus is currently set
56 /// * `Err(RDFError::ExpectedSubjectError)` - If the focus is a literal or cannot be converted to a subject
57 fn get_focus_as_subject(&self) -> Result<Self::Subject, RDFError> {
58 match self.get_focus() {
59 None => Err(RDFError::NoFocusNodeError),
60 Some(term) => {
61 let subject = Self::term_as_subject(term).map_err(|_| RDFError::ExpectedSubjectError {
62 node: format!("{term}"),
63 context: "get_focus_as_subject".to_string(),
64 })?;
65 Ok(subject)
66 },
67 }
68 }
69
70 /// Parses and retrieves a SHACL path from a subject-predicate pair.
71 ///
72 /// # Arguments
73 ///
74 /// * `subject` - The subject node to query
75 /// * `predicate` - The predicate whose object should be parsed as a SHACL path
76 ///
77 /// # Returns
78 ///
79 /// * `Ok(Some(path))` - If an object exists and was successfully parsed as a SHACL path
80 /// * `Ok(None)` - If no object exists or parsing failed
81 /// * `Err(e)` - If querying the graph for objects fails
82 fn get_path_for(&mut self, subject: &Self::Term, predicate: &Self::IRI) -> Result<Option<SHACLPath>, RDFError> {
83 match self.objects_for(subject, predicate)?.into_iter().next() {
84 Some(term) => {
85 let path = ShaclPathParser::new(term.clone()).parse_focused(self).map_err(|e| {
86 RDFError::InvalidSHACLPathError {
87 node: format!("{term}"),
88 error: Box::new(e),
89 }
90 })?;
91 Ok(Some(path))
92 },
93 None => Ok(None),
94 }
95 }
96}