shacl_ast/ast/
node_shape.rs

1use crate::{
2    component::Component, message_map::MessageMap, severity::Severity, target::Target, SH_CLOSED,
3    SH_DEACTIVATED, SH_DESCRIPTION, SH_GROUP, SH_INFO_STR, SH_NAME, SH_NODE_SHAPE, SH_PROPERTY,
4    SH_SEVERITY, SH_VIOLATION_STR, SH_WARNING_STR,
5};
6use iri_s::iri;
7use srdf::{RDFNode, SRDFBuilder};
8use std::fmt::Display;
9
10#[derive(Debug, Clone)]
11pub struct NodeShape {
12    id: RDFNode,
13    components: Vec<Component>,
14    targets: Vec<Target>,
15    property_shapes: Vec<RDFNode>,
16    closed: bool,
17    // ignored_properties: Vec<IriRef>,
18    deactivated: bool,
19    // message: MessageMap,
20    severity: Option<Severity>,
21    name: MessageMap,
22    description: MessageMap,
23    group: Option<RDFNode>,
24    // source_iri: Option<IriRef>,
25}
26
27impl NodeShape {
28    pub fn new(id: RDFNode) -> Self {
29        NodeShape {
30            id,
31            components: Vec::new(),
32            targets: Vec::new(),
33            property_shapes: Vec::new(),
34            closed: false,
35            // ignored_properties: Vec::new(),
36            deactivated: false,
37            // message: MessageMap::new(),
38            severity: None,
39            name: MessageMap::new(),
40            description: MessageMap::new(),
41            group: None,
42            // source_iri: None,
43        }
44    }
45
46    pub fn with_targets(mut self, targets: Vec<Target>) -> Self {
47        self.targets = targets;
48        self
49    }
50
51    pub fn set_targets(&mut self, targets: Vec<Target>) {
52        self.targets = targets;
53    }
54
55    pub fn with_property_shapes(mut self, property_shapes: Vec<RDFNode>) -> Self {
56        self.property_shapes = property_shapes;
57        self
58    }
59
60    pub fn with_components(mut self, components: Vec<Component>) -> Self {
61        self.components = components;
62        self
63    }
64
65    pub fn with_closed(mut self, closed: bool) -> Self {
66        self.closed = closed;
67        self
68    }
69
70    pub fn id(&self) -> &RDFNode {
71        &self.id
72    }
73
74    pub fn is_closed(&self) -> &bool {
75        &self.closed
76    }
77
78    pub fn is_deactivated(&self) -> &bool {
79        &self.deactivated
80    }
81
82    pub fn severity(&self) -> Option<Severity> {
83        self.severity.to_owned()
84    }
85
86    pub fn components(&self) -> &Vec<Component> {
87        &self.components
88    }
89
90    pub fn targets(&self) -> &Vec<Target> {
91        &self.targets
92    }
93
94    pub fn property_shapes(&self) -> &Vec<RDFNode> {
95        &self.property_shapes
96    }
97
98    // TODO: this is a bit ugly
99    pub fn write<RDF>(&self, rdf: &mut RDF) -> Result<(), RDF::Err>
100    where
101        RDF: SRDFBuilder,
102    {
103        let id: RDF::Subject = self.id.clone().try_into().map_err(|_| unreachable!())?;
104        rdf.add_type(id.clone(), SH_NODE_SHAPE.clone())?;
105
106        self.name.iter().try_for_each(|(lang, value)| {
107            let literal: RDF::Literal = match lang {
108                Some(_) => todo!(),
109                None => value.clone().into(),
110            };
111            rdf.add_triple(id.clone(), SH_NAME.clone(), literal)
112        })?;
113
114        self.description.iter().try_for_each(|(lang, value)| {
115            let literal: RDF::Literal = match lang {
116                Some(_) => todo!(),
117                None => value.clone().into(),
118            };
119            rdf.add_triple(id.clone(), SH_DESCRIPTION.clone(), literal)
120        })?;
121
122        self.components
123            .iter()
124            .try_for_each(|component| component.write(&self.id, rdf))?;
125
126        self.targets
127            .iter()
128            .try_for_each(|target| target.write(&self.id, rdf))?;
129
130        self.property_shapes.iter().try_for_each(|property_shape| {
131            rdf.add_triple(id.clone(), SH_PROPERTY.clone(), property_shape.clone())
132        })?;
133
134        if self.deactivated {
135            let literal: RDF::Literal = "true".to_string().into();
136
137            rdf.add_triple(id.clone(), SH_DEACTIVATED.clone(), literal)?;
138        }
139
140        if let Some(group) = &self.group {
141            rdf.add_triple(id.clone(), SH_GROUP.clone(), group.clone())?;
142        }
143
144        if let Some(severity) = &self.severity {
145            let pred = match severity {
146                Severity::Violation => iri!(SH_VIOLATION_STR),
147                Severity::Info => iri!(SH_INFO_STR),
148                Severity::Warning => iri!(SH_WARNING_STR),
149                Severity::Generic(iri) => iri.get_iri().unwrap(),
150            };
151
152            rdf.add_triple(id.clone(), SH_SEVERITY.clone(), pred.clone())?;
153        }
154
155        if self.closed {
156            let literal: RDF::Literal = "true".to_string().into();
157
158            rdf.add_triple(id.clone(), SH_CLOSED.clone(), literal)?;
159        }
160
161        Ok(())
162    }
163}
164
165impl Display for NodeShape {
166    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
167        writeln!(f, "{{")?;
168        if self.closed {
169            writeln!(f, "       closed: {}", self.closed)?
170        }
171        for target in self.targets.iter() {
172            writeln!(f, "       {target}")?
173        }
174        for property in self.property_shapes.iter() {
175            writeln!(f, "       Property {property}")?
176        }
177        for component in self.components.iter() {
178            writeln!(f, "       {component}")?
179        }
180        write!(f, "}}")?;
181        Ok(())
182    }
183}