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()))
54      .join(T::to_query_with_binding(object.clone()));
55
56    (construct_query, object)
57  }
58
59  pub fn join_with_binding<T: ToConstructQuery>(
60    self,
61    subject: Variable,
62    predicate: NamedNode,
63  ) -> (Self, Variable) {
64    let object = Variable::new_unchecked(spargebra::term::BlankNode::default().into_string());
65
66    let construct_query = self
67      .join(Self::new(subject, predicate, object.clone()))
68      .join(T::to_query_with_binding(object.clone()));
69
70    (construct_query, object)
71  }
72
73  pub fn left_join_with_binding<T: ToConstructQuery>(
74    self,
75    subject: Variable,
76    predicate: NamedNode,
77  ) -> (Self, Variable) {
78    let object = Variable::new_unchecked(spargebra::term::BlankNode::default().into_string());
79
80    let construct_query = self
81      .left_join(Self::new(subject, predicate, object.clone()))
82      .join(T::to_query_with_binding(object.clone()));
83
84    (construct_query, object)
85  }
86
87  pub fn join_with(self, subject: Variable, predicate: NamedNode, object: NamedNode) -> Self {
88    self.join(Self::new(subject, predicate, object))
89  }
90
91  pub fn filter_variable(self, variable: Variable, id: NamedNode) -> Self {
92    let expr = Expression::Equal(
93      Box::new(Expression::Variable(variable)),
94      Box::new(Expression::NamedNode(id)),
95    );
96    Self {
97      construct_template: self.construct_template,
98      where_pattern: GraphPattern::Filter {
99        expr,
100        inner: Box::new(self.where_pattern),
101      },
102    }
103  }
104}
105
106impl From<ConstructQuery> for Query {
107  fn from(value: ConstructQuery) -> Self {
108    Query::Construct {
109      template: value.construct_template,
110      dataset: None,
111      pattern: value.where_pattern,
112      base_iri: None,
113    }
114  }
115}
116
117impl ToConstructQuery for Variable {
118  fn to_query_with_binding(_: Variable) -> ConstructQuery {
119    ConstructQuery::default()
120  }
121}
122
123macro_rules! to_construct_query_datatypes {
124  ($($t:ty),*) => {
125    $(
126      impl ToConstructQuery for $t {
127        fn to_query_with_binding(_: Variable) -> ConstructQuery {
128          ConstructQuery::default()
129        }
130      }
131    )*
132  };
133}
134
135to_construct_query_datatypes!(
136  u8,
137  u16,
138  u32,
139  u64,
140  i8,
141  i16,
142  i32,
143  i64,
144  String,
145  xsd_types::DateTime
146);
147
148impl<T: ToConstructQuery> ToConstructQuery for Option<T> {
149  fn to_query_with_binding(variable: Variable) -> ConstructQuery {
150    T::to_query_with_binding(variable)
151  }
152}
153
154impl<T: ToConstructQuery> ToConstructQuery for Vec<T> {
155  fn to_query_with_binding(variable: Variable) -> ConstructQuery {
156    T::to_query_with_binding(variable)
157  }
158}
159
160impl<T: ToConstructQuery> ToConstructQuery for std::collections::HashSet<T> {
161  fn to_query_with_binding(variable: Variable) -> ConstructQuery {
162    T::to_query_with_binding(variable)
163  }
164}
165
166impl Join for ConstructQuery {
167  fn join(mut self, other: Self) -> Self {
168    self.construct_template.extend(other.construct_template);
169    self.where_pattern = self.where_pattern.join(other.where_pattern);
170    self
171  }
172}
173
174impl LeftJoin for ConstructQuery {
175  fn left_join(mut self, other: Self) -> Self {
176    self.construct_template.extend(other.construct_template);
177    self.where_pattern = self.where_pattern.left_join(other.where_pattern);
178    self
179  }
180}
181
182impl Union for ConstructQuery {
183  fn union(mut self, other: Self) -> Self {
184    self.construct_template.extend(other.construct_template);
185    self.where_pattern = self.where_pattern.union(other.where_pattern);
186    self
187  }
188}
189
190impl And for Vec<TriplePattern> {
191  fn and(mut self, other: Self) -> Self {
192    self.extend(other);
193    self
194  }
195}
196
197impl Join for GraphPattern {
198  fn join(self, other: Self) -> Self {
199    GraphPattern::Join {
200      left: Box::new(self),
201      right: Box::new(other),
202    }
203  }
204}
205
206impl LeftJoin for GraphPattern {
207  fn left_join(self, other: Self) -> Self {
208    GraphPattern::LeftJoin {
209      left: Box::new(self),
210      right: Box::new(other),
211      expression: None,
212    }
213  }
214}
215
216impl Union for GraphPattern {
217  fn union(self, other: Self) -> Self {
218    GraphPattern::Union {
219      left: Box::new(self),
220      right: Box::new(other),
221    }
222  }
223}