1pub mod algebra;
4pub mod binding_optimizer;
5pub mod distributed;
6pub mod exec;
7pub mod functions;
8pub mod gpu;
9pub mod jit;
10pub mod optimizer;
11pub mod parser;
12pub mod pattern_optimizer;
13pub mod pattern_unification;
14pub mod plan;
15pub mod property_paths;
16pub mod sparql_algebra;
17pub mod sparql_query;
18pub mod streaming_results;
19pub mod update;
20pub mod wasm;
21
22pub use crate::{GraphName, Triple};
24pub use sparql_algebra::{
25 Expression as SparqlExpression, GraphPattern as SparqlGraphPattern, NamedNodePattern,
26 PropertyPathExpression, TermPattern as SparqlTermPattern, TriplePattern as SparqlTriplePattern,
27};
28pub use sparql_query::*;
29
30pub use plan::ExecutionPlan;
32
33pub use algebra::{
36 AlgebraTriplePattern, Expression as AlgebraExpression, GraphPattern as AlgebraGraphPattern,
37 PropertyPath, Query as AlgebraQuery, TermPattern as AlgebraTermPattern,
38};
39pub use binding_optimizer::{BindingIterator, BindingOptimizer, BindingSet, Constraint, TermType};
40pub use distributed::{DistributedConfig, DistributedQueryEngine, FederatedEndpoint};
41pub use gpu::{GpuBackend, GpuQueryExecutor};
42pub use jit::{JitCompiler, JitConfig};
43pub use optimizer::{AIQueryOptimizer, MultiQueryOptimizer};
44pub use parser::*;
45pub use pattern_optimizer::{IndexType, OptimizedPatternPlan, PatternExecutor, PatternOptimizer};
46pub use pattern_unification::{
47 PatternConverter, PatternOptimizer as UnifiedPatternOptimizer, UnifiedTermPattern,
48 UnifiedTriplePattern,
49};
50pub use streaming_results::{
51 ConstructResults, SelectResults, Solution as StreamingSolution, SolutionMetadata,
52 StreamingConfig, StreamingProgress, StreamingQueryResults, StreamingResultBuilder,
53};
54pub use update::{UpdateExecutor, UpdateParser};
55pub use wasm::{OptimizationLevel, WasmQueryCompiler, WasmTarget};
56
57pub use exec::{QueryExecutor, QueryResults, Solution};
59
60use crate::model::{Object, Predicate, Subject, Term, Variable};
61use crate::OxirsError;
62use crate::Store;
63use std::collections::HashMap;
64use std::future::Future;
65use std::pin::Pin;
66
67use algebra::TermPattern;
69
70#[derive(Debug, Clone)]
72pub enum QueryResult {
73 Select {
75 variables: Vec<String>,
76 bindings: Vec<HashMap<String, Term>>,
77 },
78 Ask(bool),
80 Construct(Vec<crate::model::Triple>),
82}
83
84pub struct QueryEngine {
86 parser: parser::SparqlParser,
88 executor_config: QueryExecutorConfig,
90 federation_executor: Option<crate::federation::FederationExecutor>,
92}
93
94impl Default for QueryEngine {
95 fn default() -> Self {
96 Self::new()
97 }
98}
99
100#[derive(Debug, Clone)]
102pub struct QueryExecutorConfig {
103 pub max_results: usize,
105 pub timeout_ms: Option<u64>,
107 pub optimize: bool,
109}
110
111impl Default for QueryExecutorConfig {
112 fn default() -> Self {
113 Self {
114 max_results: 10000,
115 timeout_ms: Some(30000),
116 optimize: true,
117 }
118 }
119}
120
121impl QueryEngine {
122 pub fn new() -> Self {
124 Self {
125 parser: parser::SparqlParser::new(),
126 executor_config: QueryExecutorConfig::default(),
127 federation_executor: crate::federation::FederationExecutor::new().ok(),
128 }
129 }
130
131 pub fn with_config(config: QueryExecutorConfig) -> Self {
133 Self {
134 parser: parser::SparqlParser::new(),
135 executor_config: config,
136 federation_executor: crate::federation::FederationExecutor::new().ok(),
137 }
138 }
139
140 pub fn with_federation(mut self) -> Self {
142 self.federation_executor = crate::federation::FederationExecutor::new().ok();
143 self
144 }
145
146 pub fn without_federation(mut self) -> Self {
148 self.federation_executor = None;
149 self
150 }
151
152 pub fn query(&self, query_str: &str, store: &dyn Store) -> Result<QueryResult, OxirsError> {
154 let parsed_query = self.parser.parse(query_str)?;
156
157 self.execute_query(&parsed_query, store)
159 }
160
161 pub fn execute_query(
163 &self,
164 query: &sparql_query::Query,
165 store: &dyn Store,
166 ) -> Result<QueryResult, OxirsError> {
167 match query {
168 sparql_query::Query::Select {
169 pattern, dataset, ..
170 } => self.execute_select_query(pattern, dataset.as_ref(), store),
171 sparql_query::Query::Ask {
172 pattern, dataset, ..
173 } => self.execute_ask_query(pattern, dataset.as_ref(), store),
174 sparql_query::Query::Construct {
175 template,
176 pattern,
177 dataset,
178 ..
179 } => self.execute_construct_query(template, pattern, dataset.as_ref(), store),
180 sparql_query::Query::Describe {
181 pattern, dataset, ..
182 } => self.execute_describe_query(pattern, dataset.as_ref(), store),
183 }
184 }
185
186 fn execute_select_query(
188 &self,
189 pattern: &SparqlGraphPattern,
190 _dataset: Option<&QueryDataset>,
191 store: &dyn Store,
192 ) -> Result<QueryResult, OxirsError> {
193 let executor = QueryExecutor::new(store);
194
195 let plan = self.pattern_to_plan(pattern)?;
197
198 let solutions = executor.execute(&plan)?;
200
201 let variables = self.extract_variables(pattern);
203 let bindings: Vec<HashMap<String, Term>> = solutions
204 .into_iter()
205 .take(self.executor_config.max_results)
206 .map(|sol| {
207 let mut binding = HashMap::new();
208 for var in &variables {
209 if let Some(term) = sol.get(var) {
210 binding.insert(var.name().to_string(), term.clone());
211 }
212 }
213 binding
214 })
215 .collect();
216
217 Ok(QueryResult::Select {
218 variables: variables
219 .into_iter()
220 .map(|v| v.name().to_string())
221 .collect(),
222 bindings,
223 })
224 }
225
226 fn execute_ask_query(
228 &self,
229 pattern: &SparqlGraphPattern,
230 _dataset: Option<&QueryDataset>,
231 store: &dyn Store,
232 ) -> Result<QueryResult, OxirsError> {
233 let executor = QueryExecutor::new(store);
234
235 let plan = self.pattern_to_plan(pattern)?;
237
238 let solutions = executor.execute(&plan)?;
240
241 Ok(QueryResult::Ask(!solutions.is_empty()))
243 }
244
245 fn execute_construct_query(
247 &self,
248 template: &[SparqlTriplePattern],
249 pattern: &SparqlGraphPattern,
250 _dataset: Option<&QueryDataset>,
251 store: &dyn Store,
252 ) -> Result<QueryResult, OxirsError> {
253 let executor = QueryExecutor::new(store);
254
255 let plan = self.pattern_to_plan(pattern)?;
257
258 let solutions = executor.execute(&plan)?;
260
261 let mut triples = Vec::new();
263 for solution in solutions.into_iter().take(self.executor_config.max_results) {
264 for triple_pattern in template {
265 if let Some(triple) = self.instantiate_triple_pattern(triple_pattern, &solution)? {
266 triples.push(triple);
267 }
268 }
269 }
270
271 Ok(QueryResult::Construct(triples))
272 }
273
274 fn execute_describe_query(
276 &self,
277 pattern: &SparqlGraphPattern,
278 _dataset: Option<&QueryDataset>,
279 store: &dyn Store,
280 ) -> Result<QueryResult, OxirsError> {
281 let executor = QueryExecutor::new(store);
284
285 let plan = self.pattern_to_plan(pattern)?;
287
288 let solutions = executor.execute(&plan)?;
290
291 let mut triples = Vec::new();
293 for solution in solutions.into_iter().take(self.executor_config.max_results) {
294 for (_, term) in solution.iter() {
296 if let Ok(store_quads) =
297 store.find_quads(None, None, None, Some(&GraphName::DefaultGraph))
298 {
299 for quad in store_quads {
300 let triple = Triple::new(
301 quad.subject().clone(),
302 quad.predicate().clone(),
303 quad.object().clone(),
304 );
305 if self.triple_involves_term(&triple, term) {
306 triples.push(triple);
307 }
308 }
309 }
310 }
311 }
312
313 triples.dedup();
314 Ok(QueryResult::Construct(triples))
315 }
316
317 fn pattern_to_plan(&self, pattern: &SparqlGraphPattern) -> Result<ExecutionPlan, OxirsError> {
319 match pattern {
320 SparqlGraphPattern::Bgp { patterns } => {
321 if patterns.len() == 1 {
322 Ok(ExecutionPlan::TripleScan {
324 pattern: self.convert_sparql_triple_pattern(&patterns[0])?,
325 })
326 } else {
327 let mut plan = ExecutionPlan::TripleScan {
329 pattern: self.convert_sparql_triple_pattern(&patterns[0])?,
330 };
331
332 for triple_pattern in &patterns[1..] {
333 let right_plan = ExecutionPlan::TripleScan {
334 pattern: self.convert_sparql_triple_pattern(triple_pattern)?,
335 };
336
337 let join_vars = self.find_join_variables(&plan, &right_plan);
339
340 plan = ExecutionPlan::HashJoin {
341 left: Box::new(plan),
342 right: Box::new(right_plan),
343 join_vars,
344 };
345 }
346
347 Ok(plan)
348 }
349 }
350 SparqlGraphPattern::Join { left, right } => {
351 let left_plan = self.pattern_to_plan(left)?;
352 let right_plan = self.pattern_to_plan(right)?;
353 let join_vars = self.find_join_variables(&left_plan, &right_plan);
354
355 Ok(ExecutionPlan::HashJoin {
356 left: Box::new(left_plan),
357 right: Box::new(right_plan),
358 join_vars,
359 })
360 }
361 SparqlGraphPattern::Filter { expr, inner } => {
362 let input_plan = self.pattern_to_plan(inner)?;
363 let condition = self.convert_expression(expr.clone())?;
365 Ok(ExecutionPlan::Filter {
366 input: Box::new(input_plan),
367 condition,
368 })
369 }
370 SparqlGraphPattern::Union { left, right } => {
371 let left_plan = self.pattern_to_plan(left)?;
372 let right_plan = self.pattern_to_plan(right)?;
373
374 Ok(ExecutionPlan::Union {
375 left: Box::new(left_plan),
376 right: Box::new(right_plan),
377 })
378 }
379 SparqlGraphPattern::Project { inner, variables } => {
380 let input_plan = self.pattern_to_plan(inner)?;
381 Ok(ExecutionPlan::Project {
382 input: Box::new(input_plan),
383 vars: variables.clone(),
384 })
385 }
386 SparqlGraphPattern::Distinct { inner } => {
387 let input_plan = self.pattern_to_plan(inner)?;
388 Ok(ExecutionPlan::Distinct {
389 input: Box::new(input_plan),
390 })
391 }
392 SparqlGraphPattern::Slice {
393 inner,
394 start,
395 length,
396 } => {
397 let input_plan = self.pattern_to_plan(inner)?;
398 Ok(ExecutionPlan::Limit {
399 input: Box::new(input_plan),
400 limit: length.unwrap_or(usize::MAX),
401 offset: *start,
402 })
403 }
404 _ => {
405 Err(OxirsError::Query(format!(
407 "Unsupported graph pattern type: {pattern:?}"
408 )))
409 }
410 }
411 }
412
413 fn convert_sparql_triple_pattern(
415 &self,
416 pattern: &SparqlTriplePattern,
417 ) -> Result<crate::model::pattern::TriplePattern, OxirsError> {
418 use crate::model::pattern::*;
419
420 let subject = match &pattern.subject {
421 SparqlTermPattern::Variable(v) => Some(SubjectPattern::Variable(v.clone())),
422 SparqlTermPattern::NamedNode(n) => Some(SubjectPattern::NamedNode(n.clone())),
423 SparqlTermPattern::BlankNode(b) => Some(SubjectPattern::BlankNode(b.clone())),
424 _ => None,
425 };
426
427 let predicate = match &pattern.predicate {
428 SparqlTermPattern::Variable(v) => Some(PredicatePattern::Variable(v.clone())),
429 SparqlTermPattern::NamedNode(n) => Some(PredicatePattern::NamedNode(n.clone())),
430 _ => None,
431 };
432
433 let object = match &pattern.object {
434 SparqlTermPattern::Variable(v) => Some(ObjectPattern::Variable(v.clone())),
435 SparqlTermPattern::NamedNode(n) => Some(ObjectPattern::NamedNode(n.clone())),
436 SparqlTermPattern::BlankNode(b) => Some(ObjectPattern::BlankNode(b.clone())),
437 SparqlTermPattern::Literal(l) => Some(ObjectPattern::Literal(l.clone())),
438 #[cfg(feature = "sparql-12")]
439 SparqlTermPattern::Triple(_) => {
440 None
442 }
443 };
444
445 Ok(crate::model::pattern::TriplePattern {
446 subject,
447 predicate,
448 object,
449 })
450 }
451
452 #[allow(dead_code)]
454 fn convert_triple_pattern(
455 &self,
456 pattern: &AlgebraTriplePattern,
457 ) -> Result<crate::model::pattern::TriplePattern, OxirsError> {
458 use crate::model::pattern::*;
459
460 let subject = match &pattern.subject {
461 TermPattern::Variable(v) => Some(SubjectPattern::Variable(v.clone())),
462 TermPattern::NamedNode(n) => Some(SubjectPattern::NamedNode(n.clone())),
463 TermPattern::BlankNode(b) => Some(SubjectPattern::BlankNode(b.clone())),
464 _ => None,
465 };
466
467 let predicate = match &pattern.predicate {
468 TermPattern::Variable(v) => Some(PredicatePattern::Variable(v.clone())),
469 TermPattern::NamedNode(n) => Some(PredicatePattern::NamedNode(n.clone())),
470 _ => None,
471 };
472
473 let object = match &pattern.object {
474 TermPattern::Variable(v) => Some(ObjectPattern::Variable(v.clone())),
475 TermPattern::NamedNode(n) => Some(ObjectPattern::NamedNode(n.clone())),
476 TermPattern::BlankNode(b) => Some(ObjectPattern::BlankNode(b.clone())),
477 TermPattern::Literal(l) => Some(ObjectPattern::Literal(l.clone())),
478 };
479
480 Ok(crate::model::pattern::TriplePattern {
481 subject,
482 predicate,
483 object,
484 })
485 }
486
487 fn find_join_variables(&self, _left: &ExecutionPlan, _right: &ExecutionPlan) -> Vec<Variable> {
489 Vec::new()
491 }
492
493 #[allow(clippy::only_used_in_recursion)]
495 fn convert_expression(
496 &self,
497 expr: sparql_algebra::Expression,
498 ) -> Result<AlgebraExpression, OxirsError> {
499 use sparql_algebra::Expression as SparqlExpr;
500 use AlgebraExpression as AlgebraExpr;
501
502 match expr {
503 SparqlExpr::NamedNode(n) => Ok(AlgebraExpr::Term(crate::model::Term::NamedNode(n))),
504 SparqlExpr::Literal(l) => Ok(AlgebraExpr::Term(crate::model::Term::Literal(l))),
505 SparqlExpr::Variable(v) => Ok(AlgebraExpr::Variable(v)),
506 SparqlExpr::Or(left, right) => {
507 let left_expr = self.convert_expression(*left)?;
508 let right_expr = self.convert_expression(*right)?;
509 Ok(AlgebraExpr::Or(Box::new(left_expr), Box::new(right_expr)))
510 }
511 SparqlExpr::And(left, right) => {
512 let left_expr = self.convert_expression(*left)?;
513 let right_expr = self.convert_expression(*right)?;
514 Ok(AlgebraExpr::And(Box::new(left_expr), Box::new(right_expr)))
515 }
516 SparqlExpr::Equal(left, right) => {
517 let left_expr = self.convert_expression(*left)?;
518 let right_expr = self.convert_expression(*right)?;
519 Ok(AlgebraExpr::Equal(
520 Box::new(left_expr),
521 Box::new(right_expr),
522 ))
523 }
524 SparqlExpr::SameTerm(left, right) => {
525 let left_expr = self.convert_expression(*left)?;
526 let right_expr = self.convert_expression(*right)?;
527 Ok(AlgebraExpr::Equal(
528 Box::new(left_expr),
529 Box::new(right_expr),
530 )) }
532 SparqlExpr::Greater(left, right) => {
533 let left_expr = self.convert_expression(*left)?;
534 let right_expr = self.convert_expression(*right)?;
535 Ok(AlgebraExpr::Greater(
536 Box::new(left_expr),
537 Box::new(right_expr),
538 ))
539 }
540 SparqlExpr::GreaterOrEqual(left, right) => {
541 let left_expr = self.convert_expression(*left)?;
542 let right_expr = self.convert_expression(*right)?;
543 Ok(AlgebraExpr::GreaterOrEqual(
544 Box::new(left_expr),
545 Box::new(right_expr),
546 ))
547 }
548 SparqlExpr::Less(left, right) => {
549 let left_expr = self.convert_expression(*left)?;
550 let right_expr = self.convert_expression(*right)?;
551 Ok(AlgebraExpr::Less(Box::new(left_expr), Box::new(right_expr)))
552 }
553 SparqlExpr::LessOrEqual(left, right) => {
554 let left_expr = self.convert_expression(*left)?;
555 let right_expr = self.convert_expression(*right)?;
556 Ok(AlgebraExpr::LessOrEqual(
557 Box::new(left_expr),
558 Box::new(right_expr),
559 ))
560 }
561 SparqlExpr::Not(inner) => {
562 let inner_expr = self.convert_expression(*inner)?;
563 Ok(AlgebraExpr::Not(Box::new(inner_expr)))
564 }
565 _ => {
566 Err(OxirsError::Query(format!(
568 "Expression type not yet supported in conversion: {expr:?}"
569 )))
570 }
571 }
572 }
573
574 fn extract_variables(&self, pattern: &SparqlGraphPattern) -> Vec<Variable> {
576 let mut variables = Vec::new();
577 self.collect_variables_from_pattern(pattern, &mut variables);
578 variables.sort_by_key(|v: &Variable| v.name().to_owned());
579 variables.dedup();
580 variables
581 }
582
583 fn collect_variables_from_pattern(
585 &self,
586 pattern: &SparqlGraphPattern,
587 variables: &mut Vec<Variable>,
588 ) {
589 match pattern {
590 SparqlGraphPattern::Bgp { patterns } => {
591 for triple_pattern in patterns {
592 self.collect_variables_from_triple_pattern(triple_pattern, variables);
593 }
594 }
595 SparqlGraphPattern::Join { left, right } => {
596 self.collect_variables_from_pattern(left, variables);
597 self.collect_variables_from_pattern(right, variables);
598 }
599 SparqlGraphPattern::Filter { inner, .. } => {
600 self.collect_variables_from_pattern(inner, variables);
601 }
602 SparqlGraphPattern::Union { left, right } => {
603 self.collect_variables_from_pattern(left, variables);
604 self.collect_variables_from_pattern(right, variables);
605 }
606 SparqlGraphPattern::Project {
607 inner,
608 variables: proj_vars,
609 } => {
610 self.collect_variables_from_pattern(inner, variables);
611 variables.extend(proj_vars.iter().cloned());
612 }
613 SparqlGraphPattern::Distinct { inner } => {
614 self.collect_variables_from_pattern(inner, variables);
615 }
616 SparqlGraphPattern::Slice { inner, .. } => {
617 self.collect_variables_from_pattern(inner, variables);
618 }
619 _ => {
620 }
622 }
623 }
624
625 fn collect_variables_from_triple_pattern(
627 &self,
628 pattern: &SparqlTriplePattern,
629 variables: &mut Vec<Variable>,
630 ) {
631 if let SparqlTermPattern::Variable(v) = &pattern.subject {
632 variables.push(v.clone());
633 }
634 if let SparqlTermPattern::Variable(v) = &pattern.predicate {
635 variables.push(v.clone());
636 }
637 if let SparqlTermPattern::Variable(v) = &pattern.object {
638 variables.push(v.clone());
639 }
640 }
641
642 fn instantiate_triple_pattern(
644 &self,
645 pattern: &SparqlTriplePattern,
646 solution: &Solution,
647 ) -> Result<Option<crate::model::Triple>, OxirsError> {
648 use crate::model::*;
649
650 let subject = match &pattern.subject {
651 SparqlTermPattern::Variable(v) => {
652 if let Some(term) = solution.get(v) {
653 match term {
654 Term::NamedNode(n) => Subject::NamedNode(n.clone()),
655 Term::BlankNode(b) => Subject::BlankNode(b.clone()),
656 _ => return Ok(None), }
658 } else {
659 return Ok(None); }
661 }
662 SparqlTermPattern::NamedNode(n) => Subject::NamedNode(n.clone()),
663 SparqlTermPattern::BlankNode(b) => Subject::BlankNode(b.clone()),
664 _ => return Ok(None), };
666
667 let predicate = match &pattern.predicate {
668 SparqlTermPattern::Variable(v) => {
669 if let Some(Term::NamedNode(n)) = solution.get(v) {
670 Predicate::NamedNode(n.clone())
671 } else {
672 return Ok(None); }
674 }
675 SparqlTermPattern::NamedNode(n) => Predicate::NamedNode(n.clone()),
676 _ => return Ok(None), };
678
679 let object = match &pattern.object {
680 SparqlTermPattern::Variable(v) => {
681 if let Some(term) = solution.get(v) {
682 match term {
683 Term::NamedNode(n) => Object::NamedNode(n.clone()),
684 Term::BlankNode(b) => Object::BlankNode(b.clone()),
685 Term::Literal(l) => Object::Literal(l.clone()),
686 _ => return Ok(None), }
688 } else {
689 return Ok(None); }
691 }
692 SparqlTermPattern::NamedNode(n) => Object::NamedNode(n.clone()),
693 SparqlTermPattern::BlankNode(b) => Object::BlankNode(b.clone()),
694 SparqlTermPattern::Literal(l) => Object::Literal(l.clone()),
695 #[cfg(feature = "sparql-12")]
696 SparqlTermPattern::Triple(_) => {
697 return Ok(None);
699 }
700 };
701
702 Ok(Some(Triple::new(subject, predicate, object)))
703 }
704
705 pub async fn query_async(
707 &self,
708 query_str: &str,
709 store: &dyn Store,
710 ) -> Result<QueryResult, OxirsError> {
711 let parsed_query = self.parser.parse(query_str)?;
713
714 self.execute_query_async(&parsed_query, store).await
716 }
717
718 pub async fn execute_query_async(
720 &self,
721 query: &sparql_query::Query,
722 store: &dyn Store,
723 ) -> Result<QueryResult, OxirsError> {
724 match query {
725 sparql_query::Query::Select {
726 pattern, dataset, ..
727 } => {
728 self.execute_select_query_async(pattern, dataset.as_ref(), store)
729 .await
730 }
731 sparql_query::Query::Ask {
732 pattern, dataset, ..
733 } => {
734 self.execute_ask_query_async(pattern, dataset.as_ref(), store)
735 .await
736 }
737 sparql_query::Query::Construct {
738 template,
739 pattern,
740 dataset,
741 ..
742 } => {
743 self.execute_construct_query_async(template, pattern, dataset.as_ref(), store)
744 .await
745 }
746 sparql_query::Query::Describe {
747 pattern, dataset, ..
748 } => {
749 self.execute_describe_query_async(pattern, dataset.as_ref(), store)
750 .await
751 }
752 }
753 }
754
755 async fn execute_select_query_async(
757 &self,
758 pattern: &SparqlGraphPattern,
759 _dataset: Option<&QueryDataset>,
760 store: &dyn Store,
761 ) -> Result<QueryResult, OxirsError> {
762 if self.contains_service_clause(pattern) {
764 return self.execute_federated_select(pattern, store).await;
766 }
767
768 self.execute_select_query(pattern, _dataset, store)
770 }
771
772 async fn execute_ask_query_async(
774 &self,
775 pattern: &SparqlGraphPattern,
776 dataset: Option<&QueryDataset>,
777 store: &dyn Store,
778 ) -> Result<QueryResult, OxirsError> {
779 if self.contains_service_clause(pattern) {
780 let result = self.execute_federated_select(pattern, store).await?;
781 if let QueryResult::Select { bindings, .. } = result {
782 return Ok(QueryResult::Ask(!bindings.is_empty()));
783 }
784 }
785 self.execute_ask_query(pattern, dataset, store)
786 }
787
788 async fn execute_construct_query_async(
790 &self,
791 template: &[SparqlTriplePattern],
792 pattern: &SparqlGraphPattern,
793 dataset: Option<&QueryDataset>,
794 store: &dyn Store,
795 ) -> Result<QueryResult, OxirsError> {
796 if self.contains_service_clause(pattern) {
797 return Err(OxirsError::Federation(
798 "CONSTRUCT with SERVICE is not yet fully supported".to_string(),
799 ));
800 }
801 self.execute_construct_query(template, pattern, dataset, store)
802 }
803
804 async fn execute_describe_query_async(
806 &self,
807 pattern: &SparqlGraphPattern,
808 dataset: Option<&QueryDataset>,
809 store: &dyn Store,
810 ) -> Result<QueryResult, OxirsError> {
811 if self.contains_service_clause(pattern) {
812 return Err(OxirsError::Federation(
813 "DESCRIBE with SERVICE is not yet fully supported".to_string(),
814 ));
815 }
816 self.execute_describe_query(pattern, dataset, store)
817 }
818
819 fn contains_service_clause(&self, pattern: &SparqlGraphPattern) -> bool {
821
822
823 matches!(pattern, SparqlGraphPattern::Service { .. })
827 || self.pattern_contains_service_recursive(pattern)
828 }
829
830 fn pattern_contains_service_recursive(&self, pattern: &SparqlGraphPattern) -> bool {
832 match pattern {
833 SparqlGraphPattern::Service { .. } => true,
834 SparqlGraphPattern::Join { left, right }
835 | SparqlGraphPattern::Union { left, right } => {
836 self.pattern_contains_service_recursive(left)
837 || self.pattern_contains_service_recursive(right)
838 }
839 SparqlGraphPattern::Filter { inner, .. }
840 | SparqlGraphPattern::Distinct { inner }
841 | SparqlGraphPattern::Reduced { inner }
842 | SparqlGraphPattern::Project { inner, .. } => {
843 self.pattern_contains_service_recursive(inner)
844 }
845 SparqlGraphPattern::LeftJoin { left, right, .. } => {
846 self.pattern_contains_service_recursive(left)
847 || self.pattern_contains_service_recursive(right)
848 }
849 _ => false,
850 }
851 }
852
853 async fn execute_federated_select(
855 &self,
856 pattern: &SparqlGraphPattern,
857 store: &dyn Store,
858 ) -> Result<QueryResult, OxirsError> {
859 let federation_executor = self.federation_executor.as_ref().ok_or_else(|| {
860 OxirsError::Federation("Federation executor not available".to_string())
861 })?;
862
863 let local_bindings = Vec::new();
865
866 let bindings = self
868 .execute_pattern_with_federation(pattern, local_bindings, federation_executor, store)
869 .await?;
870
871 let variables = self
873 .extract_variables(pattern)
874 .into_iter()
875 .map(|v| v.name().to_string())
876 .collect();
877
878 Ok(QueryResult::Select {
879 variables,
880 bindings,
881 })
882 }
883
884 fn execute_pattern_with_federation<'a>(
886 &'a self,
887 pattern: &'a SparqlGraphPattern,
888 current_bindings: Vec<HashMap<String, Term>>,
889 federation_executor: &'a crate::federation::FederationExecutor,
890 store: &'a dyn Store,
891 ) -> Pin<Box<dyn Future<Output = Result<Vec<HashMap<String, Term>>, OxirsError>> + 'a>> {
892 Box::pin(async move {
893 let current_bindings = current_bindings;
894 match pattern {
895 SparqlGraphPattern::Service {
896 name,
897 inner,
898 silent,
899 } => {
900 let remote_bindings = federation_executor
902 .execute_service(name, inner, *silent, ¤t_bindings)
903 .await?;
904
905 if current_bindings.is_empty() {
907 Ok(remote_bindings)
908 } else {
909 Ok(federation_executor.merge_bindings(current_bindings, remote_bindings))
910 }
911 }
912 SparqlGraphPattern::Join { left, right } => {
913 let left_bindings = self
915 .execute_pattern_with_federation(
916 left,
917 current_bindings,
918 federation_executor,
919 store,
920 )
921 .await?;
922
923 self.execute_pattern_with_federation(
925 right,
926 left_bindings,
927 federation_executor,
928 store,
929 )
930 .await
931 }
932 _ => {
933 let executor = QueryExecutor::new(store);
935 let plan = self.pattern_to_plan(pattern)?;
936 let solutions = executor.execute(&plan)?;
937
938 let bindings: Vec<HashMap<String, Term>> = solutions
939 .into_iter()
940 .take(self.executor_config.max_results)
941 .map(|sol| {
942 sol.iter()
943 .map(|(var, term)| (var.name().to_string(), term.clone()))
944 .collect()
945 })
946 .collect();
947
948 if current_bindings.is_empty() {
949 Ok(bindings)
950 } else {
951 Ok(federation_executor.merge_bindings(current_bindings, bindings))
953 }
954 }
955 }
956 })
957 }
958
959 fn triple_involves_term(&self, triple: &crate::model::Triple, term: &Term) -> bool {
961 match term {
962 Term::NamedNode(n) => {
963 matches!(triple.subject(), Subject::NamedNode(sn) if sn == n)
964 || matches!(triple.predicate(), Predicate::NamedNode(pn) if pn == n)
965 || matches!(triple.object(), Object::NamedNode(on) if on == n)
966 }
967 Term::BlankNode(b) => {
968 matches!(triple.subject(), Subject::BlankNode(sb) if sb == b)
969 || matches!(triple.object(), Object::BlankNode(ob) if ob == b)
970 }
971 Term::Literal(l) => {
972 matches!(triple.object(), Object::Literal(ol) if ol == l)
973 }
974 _ => false,
975 }
976 }
977}