codd/expression/
difference.rs

1use super::{view::ViewRef, Expression, IntoExpression, Visitor};
2use crate::Tuple;
3use std::marker::PhantomData;
4
5/// Evaluates to the tuples that are in its `left` but not in its `right` sub-expressions (`left - right`).
6///
7/// **Example**:
8/// ```rust
9/// use codd::{Database, expression::Difference};
10///
11/// let mut db = Database::new();
12/// let r = db.add_relation::<i32>("R").unwrap();
13/// let s = db.add_relation::<i32>("S").unwrap();
14///
15/// db.insert(&r, vec![0, 1, 2].into());
16/// db.insert(&s, vec![2, 4].into());
17///
18/// let r_s = Difference::new(&r, &s);
19/// let s_r = Difference::new(&s, &r);
20///
21/// assert_eq!(vec![0, 1], db.evaluate(&r_s).unwrap().into_tuples());
22/// assert_eq!(vec![4], db.evaluate(&s_r).unwrap().into_tuples());
23/// ```
24#[derive(Clone, Debug)]
25pub struct Difference<T, L, R>
26where
27    T: Tuple,
28    L: Expression<T>,
29    R: Expression<T>,
30{
31    left: L,
32    right: R,
33    relation_deps: Vec<String>,
34    view_deps: Vec<ViewRef>,
35    _marker: PhantomData<T>,
36}
37
38impl<T, L, R> Difference<T, L, R>
39where
40    T: Tuple,
41    L: Expression<T>,
42    R: Expression<T>,
43{
44    /// Creates a new instance of `Difference` corresponding to
45    /// `left` - `right`.
46    pub fn new<IL, IR>(left: IL, right: IR) -> Self
47    where
48        IL: IntoExpression<T, L>,
49        IR: IntoExpression<T, R>,
50    {
51        use super::dependency;
52
53        let left = left.into_expression();
54        let right = right.into_expression();
55
56        let mut deps = dependency::DependencyVisitor::new();
57        left.visit(&mut deps);
58        right.visit(&mut deps);
59        let (relation_deps, view_deps) = deps.into_dependencies();
60
61        Self {
62            left,
63            right,
64            relation_deps: relation_deps.into_iter().collect(),
65            view_deps: view_deps.into_iter().collect(),
66            _marker: PhantomData,
67        }
68    }
69
70    /// Returns a reference to the left sub-expression.
71    #[inline(always)]
72    pub fn left(&self) -> &L {
73        &self.left
74    }
75
76    /// Returns a reference to the right sub-expression.
77    #[inline(always)]
78    pub fn right(&self) -> &R {
79        &self.right
80    }
81
82    /// Returns a reference to the relation dependencies of the receiver.
83    #[inline(always)]
84    pub(crate) fn relation_deps(&self) -> &[String] {
85        &self.relation_deps
86    }
87
88    /// Returns a reference to the view dependencies of the receiver.
89    #[inline(always)]
90    pub(crate) fn view_deps(&self) -> &[ViewRef] {
91        &self.view_deps
92    }
93}
94
95impl<T, L, R> Expression<T> for Difference<T, L, R>
96where
97    T: Tuple,
98    L: Expression<T>,
99    R: Expression<T>,
100{
101    fn visit<V>(&self, visitor: &mut V)
102    where
103        V: Visitor,
104    {
105        visitor.visit_difference(&self);
106    }
107}
108
109#[cfg(test)]
110mod tests {
111    use super::*;
112    use crate::{Database, Tuples};
113
114    #[test]
115    fn test_clone() {
116        let mut database = Database::new();
117        let r = database.add_relation::<i32>("r").unwrap();
118        let s = database.add_relation::<i32>("s").unwrap();
119        database.insert(&r, vec![1, 2, 3, 6].into()).unwrap();
120        database.insert(&s, vec![1, 4, 3, 5].into()).unwrap();
121        let u = Difference::new(&r, &s).clone();
122        assert_eq!(
123            Tuples::<i32>::from(vec![2, 6]),
124            database.evaluate(&u).unwrap()
125        );
126    }
127}