1pub mod parser;
10pub mod algebra;
11pub mod optimizer;
12pub mod evaluator;
13
14pub use parser::{SparqlParser, SparqlQuery, QueryType};
16pub use algebra::{Algebra, PlanBuilder};
17pub use optimizer::{SparqlOptimizer, OptimizationRule};
18pub use evaluator::{SparqlEvaluator, QueryResult};
19pub use parser::Bindings;
20
21pub fn execute_query(query: &str, store: &fukurow_store::store::RdfStore) -> Result<QueryResult, SparqlError> {
23 let parser = parser::DefaultSparqlParser;
24 let mut evaluator = evaluator::DefaultSparqlEvaluator::new();
25
26 let parsed = parser.parse(query)?;
27 evaluator.evaluate_query(&parsed, store)
28}
29
30use thiserror::Error;
32
33#[derive(Error, Debug)]
34pub enum SparqlError {
35 #[error("Parse error: {0}")]
36 ParseError(String),
37
38 #[error("Algebra error: {0}")]
39 AlgebraError(String),
40
41 #[error("Optimization error: {0}")]
42 OptimizationError(String),
43
44 #[error("Evaluation error: {0}")]
45 EvaluationError(String),
46
47 #[error("Unsupported feature: {0}")]
48 UnsupportedFeature(String),
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54 use fukurow_core::model::Triple;
55 use fukurow_store::store::RdfStore;
56 use fukurow_store::provenance::{GraphId, Provenance};
57 use std::collections::HashMap;
58
59 fn default_graph_id() -> GraphId {
60 GraphId::Named("test".to_string())
61 }
62
63 fn sensor_provenance() -> Provenance {
64 Provenance::Sensor {
65 source: "test".to_string(),
66 confidence: Some(1.0),
67 }
68 }
69
70 #[test]
71 fn test_sparql_error_display() {
72 let parse_err = SparqlError::ParseError("parse failed".to_string());
73 assert!(parse_err.to_string().contains("Parse error: parse failed"));
74
75 let algebra_err = SparqlError::AlgebraError("algebra failed".to_string());
76 assert!(algebra_err.to_string().contains("Algebra error: algebra failed"));
77
78 let opt_err = SparqlError::OptimizationError("optimization failed".to_string());
79 assert!(opt_err.to_string().contains("Optimization error: optimization failed"));
80
81 let eval_err = SparqlError::EvaluationError("evaluation failed".to_string());
82 assert!(eval_err.to_string().contains("Evaluation error: evaluation failed"));
83
84 let unsupported_err = SparqlError::UnsupportedFeature("feature not supported".to_string());
85 assert!(unsupported_err.to_string().contains("Unsupported feature: feature not supported"));
86 }
87
88 #[test]
89 fn test_algebra_creation() {
90 let triple = parser::TriplePattern {
91 subject: parser::Term::Variable(parser::Variable("s".to_string())),
92 predicate: parser::Term::Iri(parser::Iri("http://example.org/type".to_string())),
93 object: parser::Term::Iri(parser::Iri("http://example.org/Person".to_string())),
94 };
95
96 let bgp = algebra::Algebra::Bgp(vec![triple]);
97 assert!(matches!(bgp, algebra::Algebra::Bgp(_)));
98 }
99
100 #[test]
101 fn test_algebra_union() {
102 let bgp1 = algebra::Algebra::Bgp(vec![]);
103 let bgp2 = algebra::Algebra::Bgp(vec![]);
104 let union = algebra::Algebra::Union(Box::new(bgp1), Box::new(bgp2));
105 assert!(matches!(union, algebra::Algebra::Union(_, _)));
106 }
107
108 #[test]
109 fn test_algebra_filter() {
110 let bgp = algebra::Algebra::Bgp(vec![]);
111 let expr = parser::Expression::Equal(
112 Box::new(parser::Expression::Variable(parser::Variable("x".to_string()))),
113 Box::new(parser::Expression::Iri(parser::Iri("http://example.org/value".to_string()))),
114 );
115 let filter = algebra::Algebra::Filter(Box::new(bgp), expr);
116 assert!(matches!(filter, algebra::Algebra::Filter(_, _)));
117 }
118
119 #[test]
120 fn test_algebra_project() {
121 let bgp = algebra::Algebra::Bgp(vec![]);
122 let vars = vec![parser::Variable("x".to_string())];
123 let project = algebra::Algebra::Project(Box::new(bgp), vars);
124 assert!(matches!(project, algebra::Algebra::Project(_, _)));
125 }
126
127 #[test]
128 fn test_algebra_slice() {
129 let bgp = algebra::Algebra::Bgp(vec![]);
130 let slice = algebra::Algebra::Slice {
131 input: Box::new(bgp),
132 offset: Some(10),
133 limit: Some(20),
134 };
135 assert!(matches!(slice, algebra::Algebra::Slice { .. }));
136 }
137
138 #[test]
139 fn test_query_stats_creation() {
140 let mut stats = optimizer::QueryStats {
141 triple_count: 10,
142 variable_count: 5,
143 selectivity_estimates: HashMap::new(),
144 predicate_selectivities: HashMap::new(),
145 };
146 stats.selectivity_estimates.insert("var1".to_string(), 0.8);
147 stats.predicate_selectivities.insert("type".to_string(), 0.3);
148
149 assert_eq!(stats.triple_count, 10);
150 assert_eq!(stats.variable_count, 5);
151 assert_eq!(stats.selectivity_estimates.get("var1"), Some(&0.8));
152 assert_eq!(stats.predicate_selectivities.get("type"), Some(&0.3));
153 }
154
155 #[test]
156 fn test_optimizer_creation() {
157 let optimizer = optimizer::DefaultSparqlOptimizer::default();
158 assert!(true);
160 }
161
162 #[test]
163 fn test_evaluator_creation() {
164 let evaluator = evaluator::DefaultSparqlEvaluator::new();
165 assert!(true);
167 }
168
169 #[test]
170 fn test_query_result_variants() {
171 let select_result = evaluator::QueryResult::Select {
172 variables: vec![parser::Variable("x".to_string())],
173 bindings: vec![Bindings::new()],
174 };
175 assert!(matches!(select_result, evaluator::QueryResult::Select { .. }));
176
177 let construct_result = evaluator::QueryResult::Construct {
178 triples: vec![Triple {
179 subject: "s".to_string(),
180 predicate: "p".to_string(),
181 object: "o".to_string(),
182 }],
183 };
184 assert!(matches!(construct_result, evaluator::QueryResult::Construct { .. }));
185
186 let ask_result = evaluator::QueryResult::Ask { result: true };
187 assert!(matches!(ask_result, evaluator::QueryResult::Ask { result: true }));
188
189 let describe_result = evaluator::QueryResult::Describe {
190 triples: vec![],
191 };
192 assert!(matches!(describe_result, evaluator::QueryResult::Describe { .. }));
193 }
194
195 #[test]
196 fn test_evaluator_empty_bgp() {
197 let evaluator = evaluator::DefaultSparqlEvaluator::new();
198 let store = RdfStore::new();
199 let bgp = algebra::Algebra::Bgp(vec![]);
200
201 let result = evaluator.evaluate(&bgp, &store);
202 assert!(result.is_ok());
203
204 match result.unwrap() {
205 evaluator::QueryResult::Select { variables, bindings } => {
206 assert!(variables.is_empty());
207 assert_eq!(bindings.len(), 1); }
209 _ => panic!("Expected Select result"),
210 }
211 }
212
213 #[test]
214 fn test_evaluator_simple_bgp() {
215 let evaluator = evaluator::DefaultSparqlEvaluator::new();
216 let mut store = RdfStore::new();
217
218 store.insert(Triple {
220 subject: "http://example.org/alice".to_string(),
221 predicate: "http://example.org/name".to_string(),
222 object: "\"Alice\"".to_string(),
223 }, default_graph_id(), sensor_provenance());
224
225 let bgp = algebra::Algebra::Bgp(vec![parser::TriplePattern {
227 subject: parser::Term::Variable(parser::Variable("person".to_string())),
228 predicate: parser::Term::Iri(parser::Iri("http://example.org/name".to_string())),
229 object: parser::Term::Variable(parser::Variable("name".to_string())),
230 }]);
231
232 let result = evaluator.evaluate(&bgp, &store);
233 assert!(result.is_ok());
234
235 match result.unwrap() {
236 evaluator::QueryResult::Select { variables, bindings } => {
237 assert_eq!(variables.len(), 2);
238 assert_eq!(bindings.len(), 1);
239 assert_eq!(bindings[0].get(&parser::Variable("person".to_string())), Some(&parser::Term::Iri(parser::Iri("http://example.org/alice".to_string()))));
240 assert_eq!(bindings[0].get(&parser::Variable("name".to_string())), Some(&parser::Term::Iri(parser::Iri("\"Alice\"".to_string()))));
242 }
243 _ => panic!("Expected Select result"),
244 }
245 }
246
247 #[test]
248 fn test_optimizer_empty_algebra() {
249 let optimizer = optimizer::DefaultSparqlOptimizer::default();
250 let bgp = algebra::Algebra::Bgp(vec![]);
251
252 let optimized = optimizer.optimize(bgp, None);
253 assert!(matches!(optimized, algebra::Algebra::Bgp(_)));
255 }
256
257 #[test]
258 fn test_parser_creation() {
259 assert!(true);
262 }
263
264 #[test]
265 fn test_bindings_operations() {
266 let mut bindings = parser::Bindings::new();
267
268 assert!(bindings.is_empty());
270
271 bindings.insert(parser::Variable("x".to_string()), parser::Term::Iri(parser::Iri("http://example.org/x".to_string())));
273 bindings.insert(parser::Variable("y".to_string()), parser::Term::Literal(parser::Literal { value: "\"value\"".to_string(), datatype: None, language: None }));
274
275 assert_eq!(bindings.len(), 2);
276 assert_eq!(bindings.get(&parser::Variable("x".to_string())), Some(&parser::Term::Iri(parser::Iri("http://example.org/x".to_string()))));
277 assert_eq!(bindings.get(&parser::Variable("y".to_string())), Some(&parser::Term::Literal(parser::Literal { value: "\"value\"".to_string(), datatype: None, language: None })));
278 assert_eq!(bindings.get(&parser::Variable("z".to_string())), None);
279 }
280
281 #[test]
282 fn test_sparql_parser_simple_select() {
283 let parser = parser::DefaultSparqlParser;
284 let query = r#"
285 PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
286 PREFIX ex: <http://example.org/>
287 SELECT ?person ?name
288 WHERE {
289 ?person rdf:type ex:Person .
290 ?person ex:name ?name .
291 }
292 "#;
293
294 let result = parser.parse_query(query);
295 if let Err(e) = &result {
296 println!("Parse error: {:?}", e);
297 }
298 assert!(result.is_ok());
299
300 let parsed = result.unwrap();
301 assert_eq!(parsed.variables.len(), 2);
302 assert_eq!(parsed.variables[0].0, "person");
303 assert_eq!(parsed.variables[1].0, "name");
304 assert_eq!(parsed.prefixes.len(), 2);
305
306 match &parsed.where_clause {
308 parser::GraphPattern::Bgp(triples) => {
309 assert_eq!(triples.len(), 2);
310 }
311 _ => panic!("Expected BGP"),
312 }
313
314 use crate::algebra::PlanBuilder;
316 let builder = algebra::DefaultPlanBuilder;
317 let algebra_result = builder.to_algebra(&parsed);
318 assert!(algebra_result.is_ok());
319
320 let algebra = algebra_result.unwrap();
321 match algebra {
322 algebra::Algebra::Project(inner, vars) => {
323 assert_eq!(vars.len(), 2);
324 match *inner {
325 algebra::Algebra::Bgp(triples) => {
326 assert_eq!(triples.len(), 2);
327 }
328 _ => panic!("Expected BGP inside Project"),
329 }
330 }
331 _ => panic!("Expected Project algebra"),
332 }
333 }
334
335 #[test]
336 fn test_sparql_ask_query() {
337 let mut store = RdfStore::new();
338
339 store.insert(Triple {
341 subject: "http://example.org/alice".to_string(),
342 predicate: "http://example.org/name".to_string(),
343 object: "\"Alice\"".to_string(),
344 }, default_graph_id(), sensor_provenance());
345
346 store.insert(Triple {
347 subject: "http://example.org/alice".to_string(),
348 predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type".to_string(),
349 object: "http://example.org/Person".to_string(),
350 }, default_graph_id(), sensor_provenance());
351
352 let query = r#"
354 PREFIX ex: <http://example.org/>
355 ASK {
356 ?person ex:name ?name .
357 ?person a ex:Person .
358 }
359 "#;
360
361 let result = execute_query(query, &store);
362 assert!(result.is_ok());
363
364 let unwrapped = result.unwrap();
365 println!("DEBUG: ASK query result: {:?}", unwrapped);
366 match unwrapped {
367 QueryResult::Ask { result } => {
368 println!("DEBUG: Expected true, got {}", result);
369 assert!(result)
370 },
371 _ => panic!("Expected Ask result, got {:?}", unwrapped),
372 }
373
374 let false_query = r#"
376 PREFIX ex: <http://example.org/>
377 ASK {
378 ?person ex:name "Bob" .
379 }
380 "#;
381
382 let false_result = execute_query(false_query, &store);
383 assert!(false_result.is_ok());
384
385 match false_result.unwrap() {
386 QueryResult::Ask { result } => assert!(!result),
387 _ => panic!("Expected Ask result"),
388 }
389 }
390
391 #[test]
392 fn test_sparql_construct_query() {
393 let mut store = RdfStore::new();
394
395 store.insert(Triple {
397 subject: "http://example.org/alice".to_string(),
398 predicate: "http://example.org/name".to_string(),
399 object: "\"Alice\"".to_string(),
400 }, default_graph_id(), sensor_provenance());
401
402 store.insert(Triple {
403 subject: "http://example.org/alice".to_string(),
404 predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type".to_string(),
405 object: "http://example.org/Person".to_string(),
406 }, default_graph_id(), sensor_provenance());
407
408 let query = r#"
410 PREFIX ex: <http://example.org/>
411 PREFIX foaf: <http://xmlns.com/foaf/0.1/>
412 CONSTRUCT {
413 ?person foaf:name ?name .
414 ?person a ex:Person .
415 }
416 WHERE {
417 ?person ex:name ?name .
418 ?person a ex:Person .
419 }
420 "#;
421
422 let result = execute_query(query, &store);
423 assert!(result.is_ok());
424
425 match result.unwrap() {
426 QueryResult::Construct { triples } => {
427 assert_eq!(triples.len(), 2); let name_triple = triples.iter().find(|t| t.predicate.contains("name")).unwrap();
431 assert_eq!(name_triple.subject, "http://example.org/alice");
432 assert!(name_triple.object.contains("Alice"));
433
434 let type_triple = triples.iter().find(|t| t.predicate.contains("type")).unwrap();
435 assert_eq!(type_triple.subject, "http://example.org/alice");
436 assert_eq!(type_triple.object, "http://example.org/Person");
437 }
438 _ => panic!("Expected Construct result"),
439 }
440 }
441
442 #[test]
443 fn test_term_variants() {
444 let iri_term = parser::Term::Iri(parser::Iri("http://example.org/test".to_string()));
445 assert!(matches!(iri_term, parser::Term::Iri(_)));
446
447 let var_term = parser::Term::Variable(parser::Variable("x".to_string()));
448 assert!(matches!(var_term, parser::Term::Variable(_)));
449
450 let literal_term = parser::Term::Literal(parser::Literal { value: "\"test\"".to_string(), datatype: None, language: None });
451 assert!(matches!(literal_term, parser::Term::Literal(_)));
452
453 }
455
456 #[test]
457 fn test_expression_variants() {
458 let var_expr = parser::Expression::Variable(parser::Variable("x".to_string()));
459 assert!(matches!(var_expr, parser::Expression::Variable(_)));
460
461 let iri_expr = parser::Expression::Iri(parser::Iri("http://example.org/type".to_string()));
462 assert!(matches!(iri_expr, parser::Expression::Iri(_)));
463
464 let literal_expr = parser::Expression::Literal(parser::Literal { value: "\"value\"".to_string(), datatype: None, language: None });
465 assert!(matches!(literal_expr, parser::Expression::Literal(_)));
466 }
467
468 #[test]
469 fn test_variable_creation() {
470 let var = parser::Variable("test_var".to_string());
471 assert!(true);
473 }
474}