linked_data_sparql/
construct_query.rs

1use crate::construct_query::left_join::LeftJoin;
2use crate::to_construct_query::ToConstructQuery;
3use and::And;
4use join::Join;
5use spargebra::Query;
6use spargebra::algebra::{Expression, GraphPattern};
7use spargebra::term::{NamedNode, NamedNodePattern, TermPattern, TriplePattern, Variable};
8use union::Union;
9
10pub mod and;
11pub mod join;
12pub mod left_join;
13pub mod union;
14
15#[derive(Default, Debug)]
16pub struct ConstructQuery {
17  construct_template: Vec<TriplePattern>,
18  where_pattern: GraphPattern,
19}
20
21impl ConstructQuery {
22  pub fn new(
23    subject: impl Into<TermPattern>,
24    predicate: impl Into<NamedNodePattern>,
25    object: impl Into<TermPattern>,
26  ) -> Self {
27    let patterns = vec![TriplePattern {
28      subject: subject.into(),
29      predicate: predicate.into(),
30      object: object.into(),
31    }];
32
33    Self {
34      construct_template: patterns.clone(),
35      where_pattern: GraphPattern::Bgp { patterns },
36    }
37  }
38
39  pub fn new_with_binding<T: ToConstructQuery>(subject: Variable, predicate: NamedNode) -> Self {
40    let object = Variable::new_unchecked(spargebra::term::BlankNode::default().into_string());
41
42    Self::new(subject, predicate, object.clone()).join(T::to_query_with_binding(object))
43  }
44
45  pub fn union_with_binding<T: ToConstructQuery>(
46    self,
47    subject: Variable,
48    predicate: NamedNode,
49  ) -> (Self, Variable) {
50    let object = Variable::new_unchecked(spargebra::term::BlankNode::default().into_string());
51
52    let construct_query = self
53      .union(Self::new(subject, predicate, object.clone()).join(T::to_query_with_binding(object.clone())));
54
55    (construct_query, object)
56  }
57
58  pub fn join_with_binding<T: ToConstructQuery>(
59    self,
60    subject: Variable,
61    predicate: NamedNode,
62  ) -> (Self, Variable) {
63    let object = Variable::new_unchecked(spargebra::term::BlankNode::default().into_string());
64
65    let construct_query = self
66      .join(Self::new(subject, predicate, object.clone()).join(T::to_query_with_binding(object.clone())));
67
68    (construct_query, object)
69  }
70
71  pub fn left_join_with_binding<T: ToConstructQuery>(
72    self,
73    subject: Variable,
74    predicate: NamedNode,
75  ) -> (Self, Variable) {
76    let object = Variable::new_unchecked(spargebra::term::BlankNode::default().into_string());
77
78    let construct_query = self.left_join(
79      Self::new(subject, predicate, object.clone()).join(T::to_query_with_binding(object.clone())),
80    );
81
82    (construct_query, object)
83  }
84
85  pub fn join_with(self, subject: Variable, predicate: NamedNode, object: NamedNode) -> Self {
86    self.join(Self::new(subject, predicate, object))
87  }
88
89  pub fn filter_variable(self, variable: Variable, id: NamedNode) -> Self {
90    let expr = Expression::Equal(
91      Box::new(Expression::Variable(variable)),
92      Box::new(Expression::NamedNode(id)),
93    );
94    Self {
95      construct_template: self.construct_template,
96      where_pattern: GraphPattern::Filter {
97        expr,
98        inner: Box::new(self.where_pattern),
99      },
100    }
101  }
102}
103
104impl From<ConstructQuery> for Query {
105  fn from(value: ConstructQuery) -> Self {
106    Query::Construct {
107      template: value.construct_template,
108      dataset: None,
109      pattern: value.where_pattern,
110      base_iri: None,
111    }
112  }
113}
114
115impl ToConstructQuery for Variable {
116  fn to_query_with_binding(_: Variable) -> ConstructQuery {
117    ConstructQuery::default()
118  }
119}
120
121macro_rules! to_construct_query_datatypes {
122  ($($t:ty),*) => {
123    $(
124      impl ToConstructQuery for $t {
125        fn to_query_with_binding(_: Variable) -> ConstructQuery {
126          ConstructQuery::default()
127        }
128      }
129    )*
130  };
131}
132
133to_construct_query_datatypes!(
134  u8,
135  u16,
136  u32,
137  u64,
138  i8,
139  i16,
140  i32,
141  i64,
142  String,
143  xsd_types::DateTime
144);
145
146impl<T: ToConstructQuery> ToConstructQuery for Option<T> {
147  fn to_query_with_binding(variable: Variable) -> ConstructQuery {
148    T::to_query_with_binding(variable)
149  }
150}
151
152impl<T: ToConstructQuery> ToConstructQuery for Vec<T> {
153  fn to_query_with_binding(variable: Variable) -> ConstructQuery {
154    T::to_query_with_binding(variable)
155  }
156}
157
158impl<T: ToConstructQuery> ToConstructQuery for std::collections::HashSet<T> {
159  fn to_query_with_binding(variable: Variable) -> ConstructQuery {
160    T::to_query_with_binding(variable)
161  }
162}
163
164impl Join for ConstructQuery {
165  fn join(mut self, other: Self) -> Self {
166    self.construct_template.extend(other.construct_template);
167    self.where_pattern = self.where_pattern.join(other.where_pattern);
168    self
169  }
170}
171
172impl LeftJoin for ConstructQuery {
173  fn left_join(mut self, other: Self) -> Self {
174    self.construct_template.extend(other.construct_template);
175    self.where_pattern = self.where_pattern.left_join(other.where_pattern);
176    self
177  }
178}
179
180impl Union for ConstructQuery {
181  fn union(mut self, other: Self) -> Self {
182    self.construct_template.extend(other.construct_template);
183    self.where_pattern = self.where_pattern.union(other.where_pattern);
184    self
185  }
186}
187
188impl And for Vec<TriplePattern> {
189  fn and(mut self, other: Self) -> Self {
190    self.extend(other);
191    self
192  }
193}
194
195impl Join for GraphPattern {
196  fn join(self, other: Self) -> Self {
197    GraphPattern::Join {
198      left: Box::new(self),
199      right: Box::new(other),
200    }
201  }
202}
203
204impl LeftJoin for GraphPattern {
205  fn left_join(self, other: Self) -> Self {
206    GraphPattern::LeftJoin {
207      left: Box::new(self),
208      right: Box::new(other),
209      expression: None,
210    }
211  }
212}
213
214impl Union for GraphPattern {
215  fn union(self, other: Self) -> Self {
216    GraphPattern::Union {
217      left: Box::new(self),
218      right: Box::new(other),
219    }
220  }
221}