shapes_converter/shex_to_sparql/
shex2sparql.rs1use prefixmap::IriRef;
2use shex_ast::{Schema, Shape, ShapeExpr, TripleExpr};
3
4use crate::shex_to_sparql::{
5 SelectQuery, ShEx2SparqlConfig, ShEx2SparqlError, TriplePattern, Var, VarBuilder,
6};
7
8pub struct ShEx2Sparql {
9 config: ShEx2SparqlConfig,
10}
11
12impl ShEx2Sparql {
13 pub fn new(config: &ShEx2SparqlConfig) -> ShEx2Sparql {
14 ShEx2Sparql {
15 config: config.clone(),
16 }
17 }
18
19 pub fn convert(
20 &self,
21 shex: &Schema,
22 maybe_shape: Option<IriRef>,
23 ) -> Result<SelectQuery, ShEx2SparqlError> {
24 let mut var_builder = VarBuilder::new();
25 match maybe_shape {
26 Some(shape) => {
27 if let Some(shape_expr) = shex.find_shape_by_iri_ref(&shape)? {
28 shape_expr2query(&shape_expr, &self.config, shex, &mut var_builder)
29 } else {
30 Err(ShEx2SparqlError::ShapeNotFound {
31 iri: shape,
32 schema: shex.clone(),
33 })
34 }
35 }
36 None => {
37 if let Some(shape_expr) = shex.start() {
38 shape_expr2query(&shape_expr, &self.config, shex, &mut var_builder)
39 } else {
40 if let Some(shapes) = shex.shapes() {
42 if let Some(shape_decl) = shapes.first() {
43 shape_expr2query(
44 &shape_decl.shape_expr,
45 &self.config,
46 shex,
47 &mut var_builder,
48 )
49 } else {
50 Err(ShEx2SparqlError::EmptyShapes {
51 schema: shex.clone(),
52 })
53 }
54 } else {
55 Err(ShEx2SparqlError::NoShapes {
56 schema: shex.clone(),
57 })
58 }
59 }
60 }
61 }
62 }
63}
64
65fn shape_expr2query(
66 shape_expr: &ShapeExpr,
67 config: &ShEx2SparqlConfig,
68 schema: &Schema,
69 var_builder: &mut VarBuilder,
70) -> Result<SelectQuery, ShEx2SparqlError> {
71 let patterns = shape_expr2patterns(shape_expr, config, schema, var_builder)?;
72 let query = SelectQuery::new()
73 .with_prefixmap(schema.prefixmap())
74 .with_base(schema.base())
75 .with_patterns(patterns);
76 Ok(query)
77}
78
79fn shape_expr2patterns(
80 se: &ShapeExpr,
81 config: &ShEx2SparqlConfig,
82 schema: &Schema,
83 var_builder: &mut VarBuilder,
84) -> Result<Vec<TriplePattern>, ShEx2SparqlError> {
85 let mut ps = Vec::new();
86 match se {
87 ShapeExpr::ShapeOr { shape_exprs: _ } => Err(ShEx2SparqlError::not_implemented("ShapeOr")),
88 ShapeExpr::ShapeAnd { shape_exprs: _ } => {
89 Err(ShEx2SparqlError::not_implemented("ShapeAND"))
90 }
91 ShapeExpr::ShapeNot { shape_expr: _ } => Err(ShEx2SparqlError::not_implemented("ShapeNot")),
92 ShapeExpr::NodeConstraint(nc) => {
93 let msg = format!("Node constraint: {nc:?}");
94 Err(ShEx2SparqlError::not_implemented(msg.as_str()))
95 }
96 ShapeExpr::Shape(s) => {
97 shape2patterns(s, &mut ps, config, schema, var_builder);
98 Ok(ps)
99 }
100 ShapeExpr::External => Err(ShEx2SparqlError::not_implemented("ShapeExternal")),
101 ShapeExpr::Ref(sref) => {
102 if let Some(shape_expr) = schema.find_shape_by_label(sref)? {
103 shape_expr2patterns(&shape_expr, config, schema, var_builder)
104 } else {
105 Err(ShEx2SparqlError::ShapeRefNotFound {
106 sref: sref.clone(),
107 schema: schema.clone(),
108 })
109 }
110 }
111 }
112}
113
114fn shape2patterns(
115 s: &Shape,
116 ps: &mut Vec<TriplePattern>,
117 config: &ShEx2SparqlConfig,
118 schema: &Schema,
119 var_builder: &mut VarBuilder,
120) {
121 if let Some(expr) = s.triple_expr() {
123 triple_expr2patterns(&expr, ps, config, schema, var_builder)
124 }
125}
126
127fn triple_expr2patterns(
128 te: &TripleExpr,
129 ps: &mut Vec<TriplePattern>,
130 config: &ShEx2SparqlConfig,
131 schema: &Schema,
132 var_builder: &mut VarBuilder,
133) {
134 match te {
135 TripleExpr::EachOf { expressions, .. } => {
136 for tew in expressions {
137 triple_expr2patterns(&tew.te, ps, config, schema, var_builder)
138 }
139 }
140 TripleExpr::OneOf { expressions, .. } => {
141 for tew in expressions {
142 triple_expr2patterns(&tew.te, ps, config, schema, var_builder)
143 }
144 }
145 TripleExpr::TripleConstraint {
146 inverse,
147 predicate,
148 value_expr: _,
149 min: _,
150 max: _,
151 ..
152 } => {
153 if let Some(true) = inverse {
155 todo!()
156 } else {
157 let subj = Var::new(config.this_variable_name.as_str());
159 let pred = predicate;
160 let obj = var_from_predicate(predicate, schema, var_builder);
161 let tp = TriplePattern::new(&subj, pred, &obj);
162 ps.push(tp)
163 }
164 }
165 TripleExpr::TripleExprRef(_) => todo!(),
166 }
167}
168
169fn var_from_predicate(predicate: &IriRef, schema: &Schema, var_builder: &mut VarBuilder) -> Var {
170 match predicate {
171 IriRef::Iri(iri) => match schema.prefixmap() {
172 None => Var::new_from_iri(iri, var_builder),
173 Some(prefixmap) => {
174 if let Some(local) = prefixmap.qualify_local(iri) {
175 Var::new(local.as_str())
176 } else {
177 todo!()
178 }
179 }
180 },
181 IriRef::Prefixed { prefix: _, local } => Var::new(local),
182 }
183}
184
185#[cfg(test)]
186mod tests {
187 use super::*;
188 use shex_compact::ShExParser;
189 use spargebra::Query;
190
191 #[test]
192 fn test_simple() {
193 let shex_str = "\
194prefix : <http://example.org/>
195prefix xsd: <http://www.w3.org/2001/XMLSchema#>
196
197:Person {
198 :name xsd:string ;
199 :knows @<Person>
200}";
201 let schema = ShExParser::parse(shex_str, None).unwrap();
202 let query_str = "\
203prefix : <http://example.org/>
204prefix xsd: <http://www.w3.org/2001/XMLSchema#>
205
206Select * where {
207 ?this :name ?name .
208 ?this :knows ?knows
209}";
210 let expected_query = Query::parse(query_str, None).unwrap();
211 let converter = ShEx2Sparql::new(&ShEx2SparqlConfig::default());
212 let converted_query = converter.convert(&schema, None).unwrap();
213 let converted_query_str = format!("{}", converted_query);
214 let converted_query_parsed = Query::parse(converted_query_str.as_str(), None).unwrap();
215 assert_eq!(converted_query_parsed, expected_query);
216 }
217}