1use crate::{
2 node_kind::NodeKind, value::Value, SH_AND_STR, SH_CLASS_STR, SH_CLOSED_STR, SH_DATATYPE_STR,
3 SH_DISJOINT_STR, SH_EQUALS_STR, SH_FLAGS_STR, SH_HAS_VALUE_STR, SH_IGNORED_PROPERTIES_STR,
4 SH_IN_STR, SH_IRI_STR, SH_LANGUAGE_IN_STR, SH_LESS_THAN_OR_EQUALS_STR, SH_LESS_THAN_STR,
5 SH_MAX_COUNT_STR, SH_MAX_EXCLUSIVE_STR, SH_MAX_INCLUSIVE_STR, SH_MAX_LENGTH_STR,
6 SH_MIN_COUNT_STR, SH_MIN_EXCLUSIVE_STR, SH_MIN_INCLUSIVE_STR, SH_MIN_LENGTH_STR, SH_NODE_STR,
7 SH_NOT_STR, SH_OR_STR, SH_PATTERN_STR, SH_QUALIFIED_MAX_COUNT_STR, SH_QUALIFIED_MIN_COUNT_STR,
8 SH_QUALIFIED_VALUE_SHAPE_STR, SH_UNIQUE_LANG_STR, SH_XONE_STR,
9};
10use iri_s::{iri, IriS};
11use itertools::Itertools;
12use prefixmap::IriRef;
13use srdf::{lang::Lang, literal::Literal, RDFNode, SRDFBuilder};
14use std::fmt::Display;
15
16#[derive(Debug, Clone, Eq, PartialEq, Hash)]
17pub enum Component {
18 Class(RDFNode),
19 Datatype(IriRef),
20 NodeKind(NodeKind),
21 MinCount(isize),
22 MaxCount(isize),
23 MinExclusive(Literal),
24 MaxExclusive(Literal),
25 MinInclusive(Literal),
26 MaxInclusive(Literal),
27 MinLength(isize),
28 MaxLength(isize),
29 Pattern {
30 pattern: String,
31 flags: Option<String>,
32 },
33 UniqueLang(bool),
34 LanguageIn {
35 langs: Vec<Lang>,
36 },
37 Equals(IriRef),
38 Disjoint(IriRef),
39 LessThan(IriRef),
40 LessThanOrEquals(IriRef),
41 Or {
42 shapes: Vec<RDFNode>,
43 },
44 And {
45 shapes: Vec<RDFNode>,
46 },
47 Not {
48 shape: RDFNode,
49 },
50 Xone {
51 shapes: Vec<RDFNode>,
52 },
53 Closed {
54 is_closed: bool,
55 ignored_properties: Vec<IriRef>,
56 },
57 Node {
58 shape: RDFNode,
59 },
60 HasValue {
61 value: Value,
62 },
63 In {
64 values: Vec<Value>,
65 },
66 QualifiedValueShape {
67 shape: RDFNode,
68 qualified_min_count: Option<isize>,
69 qualified_max_count: Option<isize>,
70 qualified_value_shapes_disjoint: Option<bool>,
71 },
72}
73
74impl Component {
75 pub fn write<RDF>(&self, rdf_node: &RDFNode, rdf: &mut RDF) -> Result<(), RDF::Err>
76 where
77 RDF: SRDFBuilder,
78 {
79 match self {
80 Self::Class(rdf_node) => {
81 Self::write_term(&rdf_node.clone().into(), SH_CLASS_STR, rdf_node, rdf)?;
82 }
83 Self::Datatype(iri) => {
84 Self::write_iri(iri, SH_DATATYPE_STR, rdf_node, rdf)?;
85 }
86 Self::NodeKind(node_kind) => {
87 let iri = match &node_kind {
88 NodeKind::Iri => SH_IRI_STR,
89
90 _ => unimplemented!(),
91 };
92
93 Self::write_iri(&IriRef::Iri(iri!(iri)), SH_DATATYPE_STR, rdf_node, rdf)?;
94 }
95 Self::MinCount(value) => {
96 Self::write_integer(*value, SH_MIN_COUNT_STR, rdf_node, rdf)?;
97 }
98 Self::MaxCount(value) => {
99 Self::write_integer(*value, SH_MAX_COUNT_STR, rdf_node, rdf)?;
100 }
101 Self::MinExclusive(value) => {
102 Self::write_literal(value, SH_MIN_EXCLUSIVE_STR, rdf_node, rdf)?;
103 }
104 Self::MaxExclusive(value) => {
105 Self::write_literal(value, SH_MAX_EXCLUSIVE_STR, rdf_node, rdf)?;
106 }
107 Self::MinInclusive(value) => {
108 Self::write_literal(value, SH_MIN_INCLUSIVE_STR, rdf_node, rdf)?;
109 }
110 Self::MaxInclusive(value) => {
111 Self::write_literal(value, SH_MAX_INCLUSIVE_STR, rdf_node, rdf)?;
112 }
113 Self::MinLength(value) => {
114 Self::write_integer(*value, SH_MIN_LENGTH_STR, rdf_node, rdf)?;
115 }
116 Self::MaxLength(value) => {
117 Self::write_integer(*value, SH_MAX_LENGTH_STR, rdf_node, rdf)?;
118 }
119 Self::Pattern { pattern, flags } => {
120 Self::write_literal(&Literal::str(pattern), SH_PATTERN_STR, rdf_node, rdf)?;
121 if let Some(flags) = flags {
122 Self::write_literal(&Literal::str(flags), SH_FLAGS_STR, rdf_node, rdf)?;
123 }
124 }
125 Self::UniqueLang(value) => {
126 Self::write_boolean(*value, SH_UNIQUE_LANG_STR, rdf_node, rdf)?;
127 }
128 Self::LanguageIn { langs } => {
129 langs.iter().try_for_each(|lang| {
130 Self::write_literal(
131 &Literal::str(&lang.to_string()),
132 SH_LANGUAGE_IN_STR,
133 rdf_node,
134 rdf,
135 )
136 })?;
137 }
138 Self::Equals(iri) => {
139 Self::write_iri(iri, SH_EQUALS_STR, rdf_node, rdf)?;
140 }
141 Self::Disjoint(iri) => {
142 Self::write_iri(iri, SH_DISJOINT_STR, rdf_node, rdf)?;
143 }
144 Self::LessThan(iri) => {
145 Self::write_iri(iri, SH_LESS_THAN_STR, rdf_node, rdf)?;
146 }
147 Self::LessThanOrEquals(iri) => {
148 Self::write_iri(iri, SH_LESS_THAN_OR_EQUALS_STR, rdf_node, rdf)?;
149 }
150 Self::Or { shapes } => {
151 shapes.iter().try_for_each(|shape| {
152 Self::write_term(&shape.clone().into(), SH_OR_STR, rdf_node, rdf)
153 })?;
154 }
155 Self::And { shapes } => {
156 shapes.iter().try_for_each(|shape| {
157 Self::write_term(&shape.clone().into(), SH_AND_STR, rdf_node, rdf)
158 })?;
159 }
160 Self::Not { shape } => {
161 Self::write_term(&shape.clone().into(), SH_PATTERN_STR, rdf_node, rdf)?;
162 }
163 Self::Xone { shapes } => {
164 shapes.iter().try_for_each(|shape| {
165 Self::write_term(&shape.clone().into(), SH_XONE_STR, rdf_node, rdf)
166 })?;
167 }
168 Self::Closed {
169 is_closed,
170 ignored_properties,
171 } => {
172 Self::write_boolean(*is_closed, SH_CLOSED_STR, rdf_node, rdf)?;
173
174 ignored_properties.iter().try_for_each(|iri| {
175 Self::write_iri(iri, SH_IGNORED_PROPERTIES_STR, rdf_node, rdf)
176 })?;
177 }
178 Self::Node { shape } => {
179 Self::write_term(&shape.clone().into(), SH_NODE_STR, rdf_node, rdf)?;
180 }
181 Self::HasValue { value } => match value {
182 Value::Iri(iri) => {
183 Self::write_iri(iri, SH_HAS_VALUE_STR, rdf_node, rdf)?;
184 }
185 Value::Literal(literal) => {
186 Self::write_literal(
187 &Literal::str(&literal.to_string()),
188 SH_HAS_VALUE_STR,
189 rdf_node,
190 rdf,
191 )?;
192 }
193 },
194 Self::In { values } => {
195 values.iter().try_for_each(|value| match value {
196 Value::Iri(iri) => Self::write_iri(iri, SH_HAS_VALUE_STR, rdf_node, rdf),
197 Value::Literal(literal) => Self::write_literal(
198 &Literal::str(&literal.to_string()),
199 SH_HAS_VALUE_STR,
200 rdf_node,
201 rdf,
202 ),
203 })?;
204 }
205 Self::QualifiedValueShape {
206 shape,
207 qualified_min_count,
208 qualified_max_count,
209 qualified_value_shapes_disjoint,
210 } => {
211 Self::write_term(
212 &shape.clone().into(),
213 SH_QUALIFIED_VALUE_SHAPE_STR,
214 rdf_node,
215 rdf,
216 )?;
217
218 if let Some(value) = qualified_min_count {
219 Self::write_integer(*value, SH_QUALIFIED_MIN_COUNT_STR, rdf_node, rdf)?;
220 }
221
222 if let Some(value) = qualified_max_count {
223 Self::write_integer(*value, SH_QUALIFIED_MAX_COUNT_STR, rdf_node, rdf)?;
224 }
225
226 if let Some(value) = qualified_value_shapes_disjoint {
227 Self::write_boolean(*value, SH_QUALIFIED_MAX_COUNT_STR, rdf_node, rdf)?;
228 }
229 }
230 }
231 Ok(())
232 }
233
234 fn write_integer<RDF>(
235 value: isize,
236 predicate: &str,
237 rdf_node: &RDFNode,
238 rdf: &mut RDF,
239 ) -> Result<(), RDF::Err>
240 where
241 RDF: SRDFBuilder,
242 {
243 let value: i128 = value.try_into().unwrap();
244 let literal: RDF::Literal = value.into();
245 Self::write_term(&literal.into(), predicate, rdf_node, rdf)
246 }
247
248 fn write_boolean<RDF>(
249 value: bool,
250 predicate: &str,
251 rdf_node: &RDFNode,
252 rdf: &mut RDF,
253 ) -> Result<(), RDF::Err>
254 where
255 RDF: SRDFBuilder,
256 {
257 let literal: RDF::Literal = value.into();
258 Self::write_term(&literal.into(), predicate, rdf_node, rdf)
259 }
260
261 fn write_literal<RDF>(
262 value: &Literal,
263 predicate: &str,
264 rdf_node: &RDFNode,
265 rdf: &mut RDF,
266 ) -> Result<(), RDF::Err>
267 where
268 RDF: SRDFBuilder,
269 {
270 let literal: RDF::Literal = value.lexical_form().into();
271 Self::write_term(&literal.into(), predicate, rdf_node, rdf)
272 }
273
274 fn write_iri<RDF>(
275 value: &IriRef,
276 predicate: &str,
277 rdf_node: &RDFNode,
278 rdf: &mut RDF,
279 ) -> Result<(), RDF::Err>
280 where
281 RDF: SRDFBuilder,
282 {
283 Self::write_term(
284 &value.get_iri().unwrap().clone().into(),
285 predicate,
286 rdf_node,
287 rdf,
288 )
289 }
290
291 fn write_term<RDF>(
292 value: &RDF::Term,
293 predicate: &str,
294 rdf_node: &RDFNode,
295 rdf: &mut RDF,
296 ) -> Result<(), RDF::Err>
297 where
298 RDF: SRDFBuilder,
299 {
300 let node: RDF::Subject = rdf_node.clone().try_into().map_err(|_| unreachable!())?;
301 rdf.add_triple(node, iri!(predicate), value.clone())
302 }
303}
304
305impl Display for Component {
306 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
307 match self {
308 Component::Class(cls) => write!(f, "class({cls})"),
309 Component::Datatype(dt) => write!(f, "datatype({dt})"),
310 Component::NodeKind(nk) => write!(f, "nodeKind({nk})"),
311 Component::MinCount(mc) => write!(f, "minCount({mc})"),
312 Component::MaxCount(mc) => write!(f, "maxCount({mc})"),
313 Component::MinExclusive(me) => write!(f, "minExclusive({me})"),
314 Component::MaxExclusive(me) => write!(f, "maxExclusive({me})"),
315 Component::MinInclusive(mi) => write!(f, "minInclusive({mi})"),
316 Component::MaxInclusive(mi) => write!(f, "maxInclusive({mi})"),
317 Component::MinLength(ml) => write!(f, "minLength({ml})"),
318 Component::MaxLength(ml) => write!(f, "maxLength({ml})"),
319 Component::Pattern { pattern, flags } => match flags {
320 Some(flags) => write!(f, "pattern({pattern}, {flags})"),
321 None => write!(f, "pattern({pattern})"),
322 },
323 Component::UniqueLang(ul) => write!(f, "uniqueLang({ul})"),
324 Component::LanguageIn { .. } => todo!(), Component::Equals(e) => write!(f, "equals({e})"),
326 Component::Disjoint(d) => write!(f, "disjoint({d})"),
327 Component::LessThan(lt) => write!(f, "uniqueLang({lt})"),
328 Component::LessThanOrEquals(lte) => write!(f, "uniqueLang({lte})"),
329 Component::Or { shapes } => {
330 let str = shapes.iter().map(|s| s.to_string()).join(" ");
331 write!(f, "or [{str}]")
332 }
333 Component::And { shapes } => {
334 let str = shapes.iter().map(|s| s.to_string()).join(" ");
335 write!(f, "and [{str}]")
336 }
337 Component::Not { shape } => {
338 write!(f, "not [{shape}]")
339 }
340 Component::Xone { shapes } => {
341 let str = shapes.iter().map(|s| s.to_string()).join(" ");
342 write!(f, "xone [{str}]")
343 }
344 Component::Closed { .. } => todo!(),
345 Component::Node { shape } => write!(f, "node({shape})"),
346 Component::HasValue { value } => write!(f, "hasValue({value})"),
347 Component::In { values } => {
348 let str = values.iter().map(|v| v.to_string()).join(" ");
349 write!(f, "In [{str}]")
350 }
351 Component::QualifiedValueShape { .. } => todo!(),
352 }
353 }
354}
355
356impl From<Component> for IriS {
357 fn from(value: Component) -> Self {
358 match value {
359 Component::Class(_) => IriS::new_unchecked(SH_CLASS_STR),
360 Component::Datatype(_) => IriS::new_unchecked(SH_DATATYPE_STR),
361 Component::NodeKind(_) => IriS::new_unchecked(SH_IRI_STR),
362 Component::MinCount(_) => IriS::new_unchecked(SH_MIN_COUNT_STR),
363 Component::MaxCount(_) => IriS::new_unchecked(SH_MAX_COUNT_STR),
364 Component::MinExclusive(_) => IriS::new_unchecked(SH_MIN_EXCLUSIVE_STR),
365 Component::MaxExclusive(_) => IriS::new_unchecked(SH_MAX_EXCLUSIVE_STR),
366 Component::MinInclusive(_) => IriS::new_unchecked(SH_MIN_INCLUSIVE_STR),
367 Component::MaxInclusive(_) => IriS::new_unchecked(SH_MAX_INCLUSIVE_STR),
368 Component::MinLength(_) => IriS::new_unchecked(SH_MIN_LENGTH_STR),
369 Component::MaxLength(_) => IriS::new_unchecked(SH_MAX_LENGTH_STR),
370 Component::Pattern { .. } => IriS::new_unchecked(SH_PATTERN_STR),
371 Component::UniqueLang(_) => IriS::new_unchecked(SH_UNIQUE_LANG_STR),
372 Component::LanguageIn { .. } => IriS::new_unchecked(SH_LANGUAGE_IN_STR),
373 Component::Equals(_) => IriS::new_unchecked(SH_EQUALS_STR),
374 Component::Disjoint(_) => IriS::new_unchecked(SH_DISJOINT_STR),
375 Component::LessThan(_) => IriS::new_unchecked(SH_LESS_THAN_STR),
376 Component::LessThanOrEquals(_) => IriS::new_unchecked(SH_LESS_THAN_OR_EQUALS_STR),
377 Component::Or { .. } => IriS::new_unchecked(SH_OR_STR),
378 Component::And { .. } => IriS::new_unchecked(SH_AND_STR),
379 Component::Not { .. } => IriS::new_unchecked(SH_NOT_STR),
380 Component::Xone { .. } => IriS::new_unchecked(SH_XONE_STR),
381 Component::Closed { .. } => IriS::new_unchecked(SH_CLOSED_STR),
382 Component::Node { .. } => IriS::new_unchecked(SH_NODE_STR),
383 Component::HasValue { .. } => IriS::new_unchecked(SH_HAS_VALUE_STR),
384 Component::In { .. } => IriS::new_unchecked(SH_IN_STR),
385 Component::QualifiedValueShape { .. } => {
386 IriS::new_unchecked(SH_QUALIFIED_VALUE_SHAPE_STR)
387 }
388 }
389 }
390}