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#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
12pub struct RdfDataConfig {
13 pub base: Option<IriS>,
15
16 pub endpoints: Option<HashMap<String, EndpointDescription>>,
18
19 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}