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