1use {
2 crate::{DataType, Literal},
3 std::str::FromStr,
4};
5
6#[derive(Debug)]
10pub enum Term {
11 Iri(Literal),
12 Literal(Literal),
13 BlankNode(Literal),
14}
15
16const ACCEPTABLE_IRI_PROTOCOLS: [&str; 3] = ["http://", "https://", "s3://"];
17
18impl Term {
19 pub fn from_static(iri_str: &'static str) -> Result<Self, ekg_error::Error> {
20 Self::new_iri_from_str(iri_str)
21 }
22
23 pub fn new_iri(iri: &iri_string::types::IriReferenceStr) -> Result<Self, ekg_error::Error> {
24 for acceptable_protocol in ACCEPTABLE_IRI_PROTOCOLS.iter() {
25 if iri.as_str().starts_with(acceptable_protocol) {
26 return Ok(Term::Iri(Literal::from_iri(iri)?));
27 }
28 }
29 Err(ekg_error::Error::InvalidIri(
30 iri.as_str().to_string(),
31 ))
32 }
33
34 pub fn new_iri_from_str(iri_str: &str) -> Result<Self, ekg_error::Error> {
35 Term::new_iri(&iri_string::types::IriReferenceString::try_from(
36 iri_str,
37 )?)
38 }
39
40 pub fn new_str(str: &str) -> Result<Self, ekg_error::Error> {
41 Ok(Term::Literal(Literal::from_str(str)?))
42 }
43
44 pub fn new_blank_node(str: &str) -> Result<Self, ekg_error::Error> {
45 Ok(Term::BlankNode(
46 Literal::from_type_and_buffer(DataType::BlankNode, str, None)?.unwrap(),
47 ))
48 }
49
50 pub fn display_turtle<'a, 'b>(&'a self) -> impl std::fmt::Display + 'a + 'b
64 where 'a: 'b {
65 struct TurtleTerm<'b>(&'b Term);
66 impl<'b> std::fmt::Display for TurtleTerm<'b> {
67 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
68 let value = match self.0 {
69 Term::Iri(value) => value,
70 Term::Literal(value) => value,
71 Term::BlankNode(value) => value,
72 };
73 value.display_turtle().fmt(f)
74 }
75 }
76 TurtleTerm(self)
77 }
78}
79
80impl FromStr for Term {
81 type Err = ekg_error::Error;
82
83 fn from_str(str: &str) -> Result<Self, Self::Err> { Term::new_str(str) }
84}
85
86impl From<Literal> for Term {
87 fn from(value: Literal) -> Self { value.as_term() }
88}
89
90#[cfg(test)]
91mod tests {
92 #[test_log::test]
93 fn test_term_01() {
94 let uri = iri_string::types::IriReferenceString::try_from("https://whatever.url/").unwrap();
95 assert_eq!(uri.to_string(), "https://whatever.url/");
96 assert_eq!(uri.path_str(), "/");
97 let term = crate::Term::new_iri(&uri).unwrap();
98 let turtle = term.display_turtle().to_string();
99
100 assert_eq!(turtle, "<https://whatever.url/>");
101 }
102
103 #[test_log::test]
104 fn test_term_02() {
105 let term = crate::Term::new_iri(
106 &iri_string::types::IriReferenceString::try_from("unknown-protocol://whatever.url")
107 .unwrap(),
108 );
109 assert!(term.is_err());
110 assert!(matches!(
111 term.unwrap_err(),
112 ekg_error::Error::InvalidIri(_)
113 ));
114 }
115
116 #[test_log::test]
117 fn test_term_03() {
118 let term = crate::Term::from_static("https:/x/whatever.url");
120 assert!(term.is_err());
121 assert!(matches!(
122 term.unwrap_err(),
123 ekg_error::Error::InvalidIri(_)
124 ));
125 }
126
127 #[test_log::test]
128 fn test_term_04() {
129 let term = crate::Term::new_str("some string").unwrap();
130
131 let turtle = format!("{}", term.display_turtle());
132
133 assert_eq!(turtle, "\"some string\"");
134 }
135
136 #[test_log::test]
137 fn test_term_05() -> Result<(), ekg_error::Error> {
138 let term: crate::Term = "some string".parse()?;
139
140 let turtle = format!("{}", term.display_turtle());
141
142 assert_eq!(turtle, "\"some string\"");
143
144 Ok(())
145 }
146
147 #[test_log::test]
148 fn test_term_06() -> Result<(), ekg_error::Error> {
149 let term: crate::Term = "\"some string\"^^xsd:string".parse()?;
150
151 let turtle = format!("{}", term.display_turtle());
152
153 assert_eq!(turtle, "\"\"some string\"^^xsd:string\""); Ok(())
156 }
157
158 #[test_log::test]
159 fn test_fluent_uri_01() -> Result<(), ekg_error::Error> {
160 let uri = iri_string::types::IriReferenceString::try_from(
161 "https://placeholder.kg/ontology/abc#xyz",
162 )
163 .map_err(|e| {
164 println!("{}", e);
165 ekg_error::Error::Unknown
166 })?;
167
168 assert_eq!(
169 uri.to_string().as_str(),
170 "https://placeholder.kg/ontology/abc#xyz"
171 );
172 Ok(())
173 }
174
175 #[test_log::test]
176 fn test_fluent_uri_02() -> Result<(), ekg_error::Error> {
177 let uri =
178 iri_string::types::IriReferenceString::try_from("https://placeholder.kg/ontology/abc#")
179 .map_err(|e| {
180 println!("{}", e);
181 ekg_error::Error::Unknown
182 })?;
183
184 assert_eq!(
185 uri.to_string().as_str(),
186 "https://placeholder.kg/ontology/abc#"
187 );
188 Ok(())
189 }
190
191 #[test_log::test]
192 fn test_fluent_uri_03() -> Result<(), ekg_error::Error> {
193 let uri =
194 iri_string::types::IriReferenceString::try_from("https://placeholder.kg/ontology/abc/")
195 .map_err(|e| {
196 println!("{}", e);
197 ekg_error::Error::Unknown
198 })?;
199
200 assert_eq!(
201 uri.to_string().as_str(),
202 "https://placeholder.kg/ontology/abc/"
203 );
204 Ok(())
205 }
206}