srdf/
rdf_data_config.rs

1use std::{collections::HashMap, io, path::Path, str::FromStr};
2
3use prefixmap::PrefixMap;
4use thiserror::Error;
5
6use iri_s::{IriS, IriSError};
7use serde::{Deserialize, Serialize};
8use std::io::Read;
9
10/// This struct can be used to define configuration of RDF data readers
11#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
12pub struct RdfDataConfig {
13    /// Default base to resolve relative IRIs, if it is `None` relative IRIs will be marked as errors`
14    pub base: Option<IriS>,
15
16    /// Endpoints to query RDF data. Each endpoint description is identified by a name
17    pub endpoints: Option<HashMap<String, EndpointDescription>>,
18
19    /// If true, the base IRI will be automatically set to the local file or URI of the document
20    pub automatic_base: Option<bool>,
21}
22
23impl RdfDataConfig {
24    pub fn new() -> RdfDataConfig {
25        RdfDataConfig {
26            base: None,
27            endpoints: None,
28            automatic_base: Some(true),
29        }
30    }
31
32    pub fn with_wikidata(mut self) -> Self {
33        let wikidata_name = "wikidata";
34        let wikidata_iri = "https://query.wikidata.org/sparql";
35        let wikidata =
36            EndpointDescription::new_unchecked(wikidata_iri).with_prefixmap(PrefixMap::wikidata());
37
38        match self.endpoints {
39            None => {
40                self.endpoints = Some(HashMap::from([(wikidata_name.to_string(), wikidata)]));
41            }
42            Some(ref mut map) => {
43                map.insert(wikidata_name.to_string(), wikidata);
44            }
45        };
46        self
47    }
48
49    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<RdfDataConfig, RdfDataConfigError> {
50        let path_name = path.as_ref().display().to_string();
51        let f = std::fs::File::open(path).map_err(|e| RdfDataConfigError::ReadingConfigError {
52            path_name: path_name.clone(),
53            error: e,
54        })?;
55        let s = read_string(f).map_err(|e| RdfDataConfigError::ReadingConfigError {
56            path_name: path_name.clone(),
57            error: e,
58        })?;
59        let config: RdfDataConfig =
60            toml::from_str(s.as_str()).map_err(|e| RdfDataConfigError::TomlError {
61                path_name: path_name.to_string(),
62                error: e,
63            })?;
64        Ok(config)
65    }
66
67    pub fn find_endpoint(&self, str: &str) -> Option<&EndpointDescription> {
68        match &self.endpoints {
69            None => None,
70            Some(map) => match map.get(str) {
71                Some(ed) => Some(ed),
72                None => None,
73            },
74        }
75    }
76}
77
78impl Default for RdfDataConfig {
79    fn default() -> Self {
80        Self::new().with_wikidata()
81    }
82}
83
84#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
85pub struct EndpointDescription {
86    query_url: IriS,
87    update_url: Option<IriS>,
88    prefixmap: PrefixMap,
89}
90
91impl EndpointDescription {
92    pub fn new_unchecked(str: &str) -> Self {
93        EndpointDescription {
94            query_url: IriS::new_unchecked(str),
95            update_url: None,
96            prefixmap: PrefixMap::new(),
97        }
98    }
99
100    pub fn query_url(&self) -> &IriS {
101        &self.query_url
102    }
103
104    pub fn prefixmap(&self) -> &PrefixMap {
105        &self.prefixmap
106    }
107
108    pub fn with_prefixmap(mut self, prefixmap: PrefixMap) -> Self {
109        self.prefixmap = prefixmap;
110        self
111    }
112
113    pub fn add_prefixmap(&mut self, prefixmap: PrefixMap) {
114        self.prefixmap = prefixmap;
115    }
116}
117
118impl FromStr for EndpointDescription {
119    type Err = IriSError;
120
121    fn from_str(query_url: &str) -> Result<Self, Self::Err> {
122        let iri = IriS::from_str(query_url)?;
123        Ok(EndpointDescription {
124            query_url: iri,
125            update_url: None,
126            prefixmap: PrefixMap::new(),
127        })
128    }
129}
130
131#[derive(Error, Debug)]
132pub enum RdfDataConfigError {
133    #[error("Reading path {path_name:?} error: {error:?}")]
134    ReadingConfigError { path_name: String, error: io::Error },
135
136    #[error("Reading TOML from {path_name:?}. Error: {error:?}")]
137    TomlError {
138        path_name: String,
139        error: toml::de::Error,
140    },
141
142    #[error("Converting to IRI the string {str}. Error: {error}")]
143    ConvertingIriEndpoint { error: String, str: String },
144}
145
146fn read_string<R: Read>(mut reader: R) -> io::Result<String> {
147    let mut buf = String::new();
148    reader.read_to_string(&mut buf)?;
149    Ok(buf)
150}