shacl_ast/ast/
component.rs

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!(), // write!(f, "languageIn({langs})"),
325            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}