codd/expression/builder.rs
1use super::*;
2use crate::Tuple;
3use std::marker::PhantomData;
4
5/// Is a builder for building [`Expression`] values.
6///
7/// [`Expression`]: ./trait.Expression.html
8pub struct Builder<L, Left>
9where
10 L: Tuple,
11 Left: Expression<L>,
12{
13 /// Is the expression constructed by this builder.
14 expression: Left,
15 _marker: PhantomData<L>,
16}
17
18impl<L, Left> Builder<L, Left>
19where
20 L: Tuple,
21 Left: Expression<L>,
22{
23 /// Builds a [`Project`] expression over the receiver's expression.
24 ///
25 /// [`Project`]: ./struct.Project.html
26 ///
27 /// **Example**:
28 /// ```rust
29 /// use codd::{Database, Expression};
30 ///
31 /// let mut db = Database::new();
32 /// let fruit = db.add_relation::<String>("R").unwrap();
33 ///
34 /// db.insert(&fruit, vec!["Apple".to_string(), "BANANA".into(), "cherry".into()].into());
35 ///
36 /// let lower = fruit.builder().project(|t| t.to_lowercase()).build();
37 ///
38 /// assert_eq!(vec!["apple", "banana", "cherry"], db.evaluate(&lower).unwrap().into_tuples());
39 /// ```
40 pub fn project<T>(self, f: impl FnMut(&L) -> T + 'static) -> Builder<T, Project<L, T, Left>>
41 where
42 T: Tuple,
43 {
44 Builder {
45 expression: Project::new(self.expression, f),
46 _marker: PhantomData,
47 }
48 }
49
50 /// Builds a [`Select`] expression over the receiver's expression.
51 ///
52 /// [`Select`]: ./struct.Select.html
53 ///
54 /// **Example**:
55 /// ```rust
56 /// use codd::{Database, Expression};
57 ///
58 /// let mut db = Database::new();
59 /// let fruit = db.add_relation::<String>("Fruit").unwrap();
60 ///
61 /// db.insert(&fruit, vec!["Apple".to_string(), "BANANA".into(), "cherry".into()].into());
62 ///
63 /// let select = fruit.builder().select(|t| t.contains('A')).build();
64 ///
65 /// assert_eq!(vec!["Apple", "BANANA"], db.evaluate(&select).unwrap().into_tuples());
66 /// ```
67 pub fn select(self, f: impl FnMut(&L) -> bool + 'static) -> Builder<L, Select<L, Left>> {
68 Builder {
69 expression: Select::new(self.expression, f),
70 _marker: PhantomData,
71 }
72 }
73
74 /// Builds an [`Intersect`] expression with the receiver's expression on left and `other` on right.
75 ///
76 /// [`Intersect`]: ./struct.Intersect.html
77 ///
78 /// **Example**:
79 /// ```rust
80 /// use codd::{Database, Expression};
81 ///
82 /// let mut db = Database::new();
83 /// let r = db.add_relation::<i32>("R").unwrap();
84 /// let s = db.add_relation::<i32>("S").unwrap();
85 ///
86 /// db.insert(&r, vec![0, 1, 2].into());
87 /// db.insert(&s, vec![2, 4].into());
88 ///
89 /// let intersect = r.builder().intersect(s).build();
90 ///
91 /// assert_eq!(vec![2], db.evaluate(&intersect).unwrap().into_tuples());
92 /// ```
93 pub fn intersect<Right, I>(self, other: I) -> Builder<L, Intersect<L, Left, Right>>
94 where
95 Right: Expression<L>,
96 I: IntoExpression<L, Right>,
97 {
98 Builder {
99 expression: Intersect::new(self.expression, other.into_expression()),
100 _marker: PhantomData,
101 }
102 }
103
104 /// Builds a [`Difference`] expression with the receiver's expression on left and `other` on right.
105 ///
106 /// [`Difference`]: ./struct.Difference.html
107 ///
108 /// **Example**:
109 /// ```rust
110 /// use codd::{Database, Expression};
111 ///
112 /// let mut db = Database::new();
113 /// let r = db.add_relation::<i32>("R").unwrap();
114 /// let s = db.add_relation::<i32>("S").unwrap();
115 ///
116 /// db.insert(&r, vec![0, 1, 2].into());
117 /// db.insert(&s, vec![2, 4].into());
118 ///
119 /// let r_s = r.builder().difference(&s).build();
120 /// let s_r = s.builder().difference(r).build();
121 ///
122 /// assert_eq!(vec![0, 1], db.evaluate(&r_s).unwrap().into_tuples());
123 /// assert_eq!(vec![4], db.evaluate(&s_r).unwrap().into_tuples());
124 /// ```
125 pub fn difference<Right, I>(self, other: I) -> Builder<L, Difference<L, Left, Right>>
126 where
127 Right: Expression<L>,
128 I: IntoExpression<L, Right>,
129 {
130 Builder {
131 expression: Difference::new(self.expression, other.into_expression()),
132 _marker: PhantomData,
133 }
134 }
135
136 /// Builds a [`Union`] expression with the receiver's expression on left and `other` on right.
137 ///
138 /// [`Union`]: ./struct.Union.html
139 ///
140 /// **Example**:
141 /// ```rust
142 /// use codd::{Database, Expression};
143 ///
144 /// let mut db = Database::new();
145 /// let r = db.add_relation::<i32>("R").unwrap();
146 /// let s = db.add_relation::<i32>("S").unwrap();
147 ///
148 /// db.insert(&r, vec![0, 1, 2].into());
149 /// db.insert(&s, vec![2, 4].into());
150 ///
151 /// let union = r.builder().union(s).build();
152 ///
153 /// assert_eq!(vec![0, 1, 2, 4], db.evaluate(&union).unwrap().into_tuples());
154 /// ```
155 pub fn union<Right, I>(self, other: I) -> Builder<L, Union<L, Left, Right>>
156 where
157 Right: Expression<L>,
158 I: IntoExpression<L, Right>,
159 {
160 Builder {
161 expression: Union::new(self.expression, other.into_expression()),
162 _marker: PhantomData,
163 }
164 }
165
166 /// Combines the receiver's expression with `other` in a temporary builder, which then can be turned into
167 /// a [`Product`] expression using a combining closure provided by method `on`.
168 ///
169 /// [`Product`]: ./struct.Product.html
170 ///
171 /// **Example**:
172 /// ```rust
173 /// use codd::{Database, Expression};
174 ///
175 /// let mut db = Database::new();
176 /// let r = db.add_relation::<i32>("R").unwrap();
177 /// let s = db.add_relation::<i32>("S").unwrap();
178 ///
179 /// db.insert(&r, vec![0, 1, 2].into());
180 /// db.insert(&s, vec![2, 4].into());
181 ///
182 /// let prod = r.builder().product(s).on(|l, r| l*r).build();
183 ///
184 /// assert_eq!(vec![0, 2, 4, 8], db.evaluate(&prod).unwrap().into_tuples());
185 /// ```
186 pub fn product<R, Right, I>(self, other: I) -> ProductBuilder<L, R, Left, Right>
187 where
188 R: Tuple,
189 Right: Expression<R>,
190 I: IntoExpression<R, Right>,
191 {
192 ProductBuilder {
193 left: self.expression,
194 right: other.into_expression(),
195 _marker: PhantomData,
196 }
197 }
198
199 /// Combines the receiver's expression with closure `f` as the join key. This value can then be joined with
200 /// another expression and it's key to create a temporary join builder. Finally, the temporary builder
201 /// can be turned into a [`Join`] expression using a combining closure provided by method `on`.
202 ///
203 /// [`Join`]: ./struct.Join.html
204 ///
205 /// **Example**:
206 /// ```rust
207 /// use codd::{Database, Expression};
208 ///
209 /// let mut db = Database::new();
210 /// let fruit = db.add_relation::<(i32, String)>("R").unwrap();
211 /// let numbers = db.add_relation::<i32>("S").unwrap();
212 ///
213 /// db.insert(&fruit, vec![
214 /// (0, "Apple".to_string()),
215 /// (1, "Banana".into()),
216 /// (2, "Cherry".into())
217 /// ].into());
218 /// db.insert(&numbers, vec![0, 2].into());
219 ///
220 /// let join = fruit
221 /// .builder()
222 /// .with_key(|t| t.0) // first element of tuples in `r` is the key for join
223 /// .join(numbers.builder().with_key(|&t| t))
224 /// .on(|k, l, r| format!("{}{}", l.1, k + r))
225 /// // combine the key `k`, left tuple `l` and right tuple `r`:
226 /// .build();
227 ///
228 /// assert_eq!(vec!["Apple0", "Cherry4"], db.evaluate(&join).unwrap().into_tuples());
229 /// ```
230 pub fn with_key<K>(self, f: impl FnMut(&L) -> K + 'static) -> WithKeyBuilder<K, L, Left>
231 where
232 K: Tuple,
233 {
234 WithKeyBuilder {
235 expression: self.expression,
236 key: Box::new(f),
237 }
238 }
239
240 /// Builds an expression from the receiver.
241 pub fn build(self) -> Left {
242 self.into_expression()
243 }
244}
245
246impl<T, E> IntoExpression<T, E> for Builder<T, E>
247where
248 T: Tuple,
249 E: Expression<T>,
250{
251 fn into_expression(self) -> E {
252 self.expression
253 }
254}
255
256impl<T, E> From<E> for Builder<T, E>
257where
258 T: Tuple,
259 E: Expression<T>,
260{
261 fn from(expression: E) -> Self {
262 Builder {
263 expression,
264 _marker: PhantomData,
265 }
266 }
267}
268
269pub struct ProductBuilder<L, R, Left, Right>
270where
271 L: Tuple,
272 R: Tuple,
273 Left: Expression<L>,
274 Right: Expression<R>,
275{
276 left: Left,
277 right: Right,
278 _marker: PhantomData<(L, R)>,
279}
280
281impl<L, R, Left, Right> ProductBuilder<L, R, Left, Right>
282where
283 L: Tuple,
284 R: Tuple,
285 Left: Expression<L>,
286 Right: Expression<R>,
287{
288 pub fn on<T: Tuple>(
289 self,
290 f: impl FnMut(&L, &R) -> T + 'static,
291 ) -> Builder<T, Product<L, R, Left, Right, T>> {
292 Builder {
293 expression: Product::new(self.left, self.right, f),
294 _marker: PhantomData,
295 }
296 }
297}
298
299pub struct WithKeyBuilder<K, L, Left>
300where
301 K: Tuple + 'static,
302 L: Tuple + 'static,
303 Left: Expression<L>,
304{
305 expression: Left,
306 key: Box<dyn FnMut(&L) -> K>,
307}
308
309impl<K, L, Left> WithKeyBuilder<K, L, Left>
310where
311 K: Tuple,
312 L: Tuple,
313 Left: Expression<L>,
314{
315 pub fn join<R, Right>(
316 self,
317 other: WithKeyBuilder<K, R, Right>,
318 ) -> JoinBuilder<K, L, R, Left, Right>
319 where
320 R: Tuple,
321 Right: Expression<R>,
322 {
323 JoinBuilder {
324 left: self,
325 right: other,
326 }
327 }
328}
329
330pub struct JoinBuilder<K, L, R, Left, Right>
331where
332 K: Tuple + 'static,
333 L: Tuple + 'static,
334 R: Tuple + 'static,
335 Left: Expression<L>,
336 Right: Expression<R>,
337{
338 left: WithKeyBuilder<K, L, Left>,
339 right: WithKeyBuilder<K, R, Right>,
340}
341
342impl<K, L, R, Left, Right> JoinBuilder<K, L, R, Left, Right>
343where
344 K: Tuple + 'static,
345 L: Tuple + 'static,
346 R: Tuple + 'static,
347 Left: Expression<L>,
348 Right: Expression<R>,
349{
350 pub fn on<T: Tuple>(
351 self,
352 f: impl FnMut(&K, &L, &R) -> T + 'static,
353 ) -> Builder<T, Join<K, L, R, Left, Right, T>> {
354 Builder {
355 expression: Join::new(
356 self.left.expression,
357 self.right.expression,
358 self.left.key,
359 self.right.key,
360 f,
361 ),
362 _marker: PhantomData,
363 }
364 }
365}