standing_relations/convenience/
join.rs1use std::hash::Hash;
2
3use crate::{pair::Pair, Op, Relation};
4
5impl<K: Clone + Eq + Hash, V: Clone + Eq + Hash, C: Op<D = (K, V)>> Relation<C> {
6 pub fn semijoin(self, other: Relation<impl Op<D = K>>) -> Relation<impl Op<D = (K, V)>> {
7 self.join(other.map_h(|x| (x, ())))
8 .map_h(|(k, v, ())| (k, v))
9 .type_named("semijoin")
10 }
11 pub fn join_values<V2: Clone + Eq + Hash>(
12 self,
13 other: Relation<impl Op<D = (K, V2)>>,
14 ) -> Relation<impl Op<D = (V, V2)>> {
15 self.join(other).map_h(|(_, v1, v2)| (v1, v2))
16 }
17 pub fn left_join<V2: Clone + Eq + Hash>(
19 self,
20 other: Relation<impl Op<D = (K, V2)>>,
21 ) -> Relation<impl Op<D = (K, V, Option<V2>)>> {
22 let self_saved = self.save();
23 let other_saved = other.save();
24 self_saved
25 .get()
26 .join(other_saved.get())
27 .map_h(|(k, l, r)| (k, l, Some(r)))
28 .concat(
29 self_saved
30 .get()
31 .antijoin(other_saved.get().map(Pair::fst))
32 .map(|(k, l)| (k, l, None)),
33 )
34 }
35}
36
37impl<C: Op> Relation<C>
38where
39 C::D: Clone + Eq + Hash,
40{
41 pub fn intersection(self, other: Relation<impl Op<D = C::D>>) -> Relation<impl Op<D = C::D>> {
42 self.map_h(|x| (x, ()))
43 .semijoin(other)
44 .map_h(|(x, ())| x)
45 .type_named("intersection")
46 }
47 pub fn set_minus(self, other: Relation<impl Op<D = C::D>>) -> Relation<impl Op<D = C::D>> {
48 self.map_h(|x| (x, ()))
49 .antijoin(other)
50 .map_h(|(x, ())| x)
51 .type_named("set_minus")
52 }
53}