ekg_namespace/
graph.rs

1use {
2    crate::{Literal, Namespace},
3    std::ffi::CString,
4};
5
6/// Similar to [`Class`](crate::Class), the `Graph` struct represents an RDF
7/// named graph identifier, also known as a "context identifier", consisting of
8/// a [`Namespace`] (i.e. a namespace) and a "local name".
9#[derive(Debug, Clone)]
10pub struct Graph {
11    pub namespace:  Namespace,
12    pub local_name: String,
13}
14
15/// Print IRI in prefix:localName format
16impl std::fmt::Display for Graph {
17    // noinspection DuplicatedCode
18    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19        write!(
20            f,
21            "{}{}",
22            self.namespace.name.as_str(),
23            self.local_name.as_str()
24        )
25    }
26}
27
28impl Graph {
29    pub fn declare(namespace: Namespace, local_name: &str) -> Self {
30        // TODO: Find a class for URI/IRIs that has separate base + local name
31        // and use that as param instead
32        Self { namespace, local_name: local_name.to_string() }
33    }
34
35    pub fn dataset_from_path(namespace: Namespace, path: &std::path::Path) -> Self {
36        Self::declare(
37            namespace,
38            path.file_name().unwrap().to_str().unwrap(),
39        )
40    }
41
42    pub fn test_dataset_from_path(namespace: Namespace, path: &std::path::Path) -> Self {
43        Self::declare(
44            namespace,
45            format!(
46                "test-{}",
47                path.file_name().unwrap().to_str().unwrap()
48            )
49            .as_str(),
50        )
51    }
52
53    pub fn as_iri(&self) -> Result<fluent_uri::Uri<String>, ekg_error::Error> {
54        self.namespace
55            .with_local_name(self.local_name.as_str())
56            .map_err(ekg_error::Error::from)
57    }
58
59    pub fn as_display_iri(&self) -> GraphDisplayIRI { GraphDisplayIRI { graph: self } }
60
61    pub fn as_c_string(&self) -> Result<CString, ekg_error::Error> {
62        // Wrap the graph IRI into a Literal first so that it can convert it into a
63        // turtle style identifier first
64        let literal = self.as_lexical_value()?;
65        CString::new(literal.to_string().as_str()).map_err(ekg_error::Error::from)
66    }
67
68    pub fn as_lexical_value(&self) -> Result<Literal, ekg_error::Error> {
69        Literal::from_iri(self.as_iri()?.borrow())
70    }
71}
72
73pub struct GraphDisplayIRI<'a> {
74    graph: &'a Graph,
75}
76
77impl<'a> std::fmt::Display for GraphDisplayIRI<'a> {
78    // noinspection SpellCheckingInspection
79    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80        write!(
81            f,
82            "<{:}{}>",
83            self.graph.namespace.iri,
84            self.graph.local_name.as_str()
85        )
86    }
87}
88
89#[cfg(test)]
90mod tests {
91    // noinspection SpellCheckingInspection
92    #[test]
93    fn test_display_iri() {
94        let ns = fluent_uri::Uri::parse("https://whatever.kom/graph/").unwrap();
95        let graph_prefix = crate::Namespace::declare("graph:", &ns).unwrap();
96        let graph = crate::Graph::declare(graph_prefix, "somedataset");
97
98        assert_eq!(
99            format!("{:}", graph).as_str(),
100            "graph:somedataset"
101        );
102        assert_eq!(
103            format!("{:}", graph.as_display_iri()).as_str(),
104            "<https://whatever.kom/graph/somedataset>"
105        );
106    }
107
108    // noinspection SpellCheckingInspection
109    #[test]
110    fn test_graph_ns() {
111        let ns = fluent_uri::Uri::parse("https://whatever.kom/graph/").unwrap();
112        let graph_prefix = crate::Namespace::declare("kggraph:", &ns).unwrap();
113
114        let graph = crate::Graph::declare(graph_prefix, "somedataset");
115        let c_string = graph.as_c_string().unwrap().into_string().unwrap();
116
117        assert_eq!(
118            c_string,
119            "<https://whatever.kom/graph/somedataset>"
120        );
121    }
122}