Skip to main content

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}