shacl_ast/compiled/
schema.rs1use std::collections::HashMap;
2
3use prefixmap::PrefixMap;
4use srdf::Rdf;
5
6use crate::Schema;
7
8use super::compiled_shacl_error::CompiledShaclError;
9use super::shape::CompiledShape;
10
11#[derive(Debug)]
12pub struct SchemaIR<S: Rdf> {
13 shapes: HashMap<S::Term, CompiledShape<S>>,
16 prefixmap: PrefixMap,
17 base: Option<S::IRI>,
18}
19
20impl<S: Rdf> SchemaIR<S> {
21 pub fn new(
22 shapes: HashMap<S::Term, CompiledShape<S>>,
23 prefixmap: PrefixMap,
24 base: Option<S::IRI>,
25 ) -> SchemaIR<S> {
26 SchemaIR {
27 shapes,
28 prefixmap,
29 base,
30 }
31 }
32
33 pub fn prefix_map(&self) -> PrefixMap {
34 self.prefixmap.clone()
35 }
36
37 pub fn base(&self) -> &Option<S::IRI> {
38 &self.base
39 }
40
41 pub fn iter(&self) -> impl Iterator<Item = (&S::Term, &CompiledShape<S>)> {
42 self.shapes.iter()
43 }
44
45 pub fn iter_with_targets(&self) -> impl Iterator<Item = (&S::Term, &CompiledShape<S>)> {
47 self.shapes
48 .iter()
49 .filter(|(_, shape)| !shape.targets().is_empty())
50 }
51
52 pub fn get_shape(&self, sref: &S::Term) -> Option<&CompiledShape<S>> {
53 self.shapes.get(sref)
54 }
55}
56
57impl<S: Rdf> TryFrom<Schema> for SchemaIR<S> {
58 type Error = CompiledShaclError;
59
60 fn try_from(schema: Schema) -> Result<Self, Self::Error> {
61 let mut shapes = HashMap::default();
62
63 for (rdf_node, shape) in schema.iter() {
64 let term = rdf_node.clone().into();
65 let shape = CompiledShape::compile(shape.to_owned(), &schema)?;
66 shapes.insert(term, shape);
67 }
68
69 let prefixmap = schema.prefix_map();
70
71 let base = schema.base().map(Into::into);
72
73 Ok(SchemaIR::new(shapes, prefixmap, base))
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use std::io::Cursor;
80
81 use srdf::RDFFormat;
82 use srdf::ReaderMode;
83 use srdf::SRDFGraph;
84
85 use crate::ShaclParser;
86
87 use super::SchemaIR;
88
89 const SCHEMA: &str = r#"
90 @prefix sh: <http://www.w3.org/ns/shacl#> .
91 @prefix ex: <http://example.org/> .
92 @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
93
94 ex:PersonShape a sh:NodeShape ;
95 sh:targetClass ex:Person ;
96 sh:property [
97 sh:path ex:name ;
98 sh:datatype xsd:string ;
99 sh:minCount 1 ;
100 sh:maxCount 1 ;
101 ] ;
102 sh:property [
103 sh:path ex:age ;
104 sh:datatype xsd:integer ;
105 sh:minCount 1 ;
106 sh:maxCount 1 ;
107 ] .
108
109 ex:PersonShape2 a sh:NodeShape ;
110 sh:targetClass ex:Person ;
111 sh:property [
112 sh:path ex:name ;
113 sh:datatype xsd:string ;
114 sh:minCount 1 ;
115 sh:maxCount 1 ;
116 ] ;
117 sh:property [
118 sh:path ex:age ;
119 sh:datatype xsd:integer ;
120 sh:minCount 1 ;
121 sh:maxCount 1 ;
122 ] .
123 "#;
124
125 fn load_schema(shacl_schema: &str) -> SchemaIR<SRDFGraph> {
126 let reader = Cursor::new(shacl_schema);
127 let rdf_format = RDFFormat::Turtle;
128 let base = None;
129
130 let rdf =
131 SRDFGraph::from_reader(reader, &rdf_format, base, &ReaderMode::default()).unwrap();
132
133 ShaclParser::new(rdf).parse().unwrap().try_into().unwrap()
134 }
135
136 #[test]
137 fn test_schema_iterator() {
138 let schema = load_schema(SCHEMA);
139 let actual = schema.iter_with_targets().count();
140 let expected = 2;
141 assert_eq!(actual, expected);
142 }
143}