rdf_store_rs/
graph.rs

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