1use std::fmt::Display;
2
3use iri_s::iri;
4use srdf::{numeric_literal::NumericLiteral, RDFNode, SHACLPath, SRDFBuilder};
5
6use crate::{
7 component::Component, message_map::MessageMap, severity::Severity, target::Target,
8 SH_DEACTIVATED, SH_DESCRIPTION, SH_GROUP, SH_INFO_STR, SH_NAME, SH_ORDER, SH_PATH,
9 SH_PROPERTY_SHAPE, SH_SEVERITY, SH_VIOLATION_STR, SH_WARNING_STR,
10};
11
12#[derive(Debug, Clone)]
13pub struct PropertyShape {
14 id: RDFNode,
15 path: SHACLPath,
16 components: Vec<Component>,
17 targets: Vec<Target>,
18 property_shapes: Vec<RDFNode>,
19 closed: bool,
20 deactivated: bool,
22 severity: Option<Severity>,
24 name: MessageMap,
25 description: MessageMap,
26 order: Option<NumericLiteral>,
27 group: Option<RDFNode>,
28 }
31
32impl PropertyShape {
33 pub fn new(id: RDFNode, path: SHACLPath) -> Self {
34 PropertyShape {
35 id,
36 path,
37 components: Vec::new(),
38 targets: Vec::new(),
39 property_shapes: Vec::new(),
40 closed: false,
41 deactivated: false,
43 severity: None,
45 name: MessageMap::new(),
46 description: MessageMap::new(),
47 order: None,
48 group: None,
49 }
52 }
53
54 pub fn with_name(mut self, name: MessageMap) -> Self {
55 self.name = name;
56 self
57 }
58 pub fn with_description(mut self, description: MessageMap) -> Self {
59 self.description = description;
60 self
61 }
62
63 pub fn with_order(mut self, order: Option<NumericLiteral>) -> Self {
64 self.order = order;
65 self
66 }
67
68 pub fn with_group(mut self, group: Option<RDFNode>) -> Self {
69 self.group = group;
70 self
71 }
72
73 pub fn with_targets(mut self, targets: Vec<Target>) -> Self {
74 self.targets = targets;
75 self
76 }
77
78 pub fn with_property_shapes(mut self, property_shapes: Vec<RDFNode>) -> Self {
79 self.property_shapes = property_shapes;
80 self
81 }
82
83 pub fn with_components(mut self, components: Vec<Component>) -> Self {
84 self.components = components;
85 self
86 }
87
88 pub fn with_closed(mut self, closed: bool) -> Self {
89 self.closed = closed;
90 self
91 }
92
93 pub fn with_severity(mut self, severity: Option<Severity>) -> Self {
94 self.severity = severity;
95 self
96 }
97
98 pub fn id(&self) -> &RDFNode {
99 &self.id
100 }
101
102 pub fn path(&self) -> &SHACLPath {
103 &self.path
104 }
105
106 pub fn name(&self) -> &MessageMap {
107 &self.name
108 }
109
110 pub fn description(&self) -> &MessageMap {
111 &self.description
112 }
113
114 pub fn is_closed(&self) -> &bool {
115 &self.closed
116 }
117
118 pub fn is_deactivated(&self) -> &bool {
119 &self.deactivated
120 }
121
122 pub fn severity(&self) -> Option<Severity> {
123 self.severity.to_owned()
124 }
125
126 pub fn components(&self) -> &Vec<Component> {
127 &self.components
128 }
129
130 pub fn targets(&self) -> &Vec<Target> {
131 &self.targets
132 }
133
134 pub fn property_shapes(&self) -> &Vec<RDFNode> {
135 &self.property_shapes
136 }
137
138 pub fn write<RDF>(&self, rdf: &mut RDF) -> Result<(), RDF::Err>
181 where
182 RDF: SRDFBuilder,
183 {
184 let id: RDF::Subject = self.id.clone().try_into().map_err(|_| unreachable!())?;
185 rdf.add_type(id.clone(), SH_PROPERTY_SHAPE.clone())?;
186
187 self.name.iter().try_for_each(|(lang, value)| {
188 let literal: RDF::Literal = match lang {
189 Some(_) => todo!(),
190 None => value.clone().into(),
191 };
192 rdf.add_triple(id.clone(), SH_NAME.clone(), literal)
193 })?;
194
195 self.description.iter().try_for_each(|(lang, value)| {
196 let literal: RDF::Literal = match lang {
197 Some(_) => todo!(),
198 None => value.clone().into(),
199 };
200 rdf.add_triple(id.clone(), SH_DESCRIPTION.clone(), literal)
201 })?;
202
203 if let Some(order) = self.order.clone() {
204 let literal: RDF::Literal = match order {
205 NumericLiteral::Decimal(_) => todo!(),
206 NumericLiteral::Double(float) => float.into(),
207 NumericLiteral::Integer(int) => {
208 let i: i128 = int.try_into().unwrap();
209 i.into()
210 }
211 };
212 rdf.add_triple(id.clone(), SH_ORDER.clone(), literal)?;
213 }
214
215 if let Some(group) = &self.group {
216 rdf.add_triple(id.clone(), SH_GROUP.clone(), group.clone())?;
217 }
218
219 if let SHACLPath::Predicate { pred } = &self.path {
220 rdf.add_triple(id.clone(), SH_PATH.clone(), pred.clone())?;
221 } else {
222 unimplemented!()
223 }
224
225 self.components
226 .iter()
227 .try_for_each(|component| component.write(&self.id, rdf))?;
228
229 self.targets
230 .iter()
231 .try_for_each(|target| target.write(&self.id, rdf))?;
232
233 if self.deactivated {
234 let literal: RDF::Literal = "true".to_string().into();
235
236 rdf.add_triple(id.clone(), SH_DEACTIVATED.clone(), literal)?;
237 }
238
239 if let Some(severity) = &self.severity {
240 let pred = match severity {
241 Severity::Violation => iri!(SH_VIOLATION_STR),
242 Severity::Info => iri!(SH_INFO_STR),
243 Severity::Warning => iri!(SH_WARNING_STR),
244 Severity::Generic(iri) => iri.get_iri().unwrap(),
245 };
246
247 rdf.add_triple(id.clone(), SH_SEVERITY.clone(), pred.clone())?;
248 }
249
250 Ok(())
251 }
252}
253
254impl Display for PropertyShape {
255 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
256 writeln!(f, "{{")?;
257 writeln!(f, " PropertyShape")?;
258 writeln!(f, " path: {}", self.path)?;
259 for target in self.targets.iter() {
260 writeln!(f, " {target}")?
261 }
262 if self.closed {
263 writeln!(f, " closed: {}", self.closed)?
264 }
265 for property in self.property_shapes.iter() {
266 writeln!(f, " Property {property}")?
267 }
268 for component in self.components.iter() {
269 writeln!(f, " {component}")?
270 }
271 write!(f, "}}")?;
272 Ok(())
273 }
274}