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}