Skip to main content

gluesql_core/plan/statement/query/join/
inner.rs

1use {
2    super::{HashJoinPlan, JoinConditionPlan, NestedLoopJoinPlan},
3    crate::plan::SourcePlan,
4    serde::{Deserialize, Serialize},
5};
6
7#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
8pub enum InnerJoinInputPlan {
9    NestedLoop(NestedLoopJoinPlan),
10    Hash(HashJoinPlan),
11    Condition(JoinConditionPlan),
12}
13
14#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
15pub struct InnerJoinPlan {
16    pub input: InnerJoinInputPlan,
17}
18
19impl InnerJoinPlan {
20    pub(crate) fn base_source(&self) -> &SourcePlan {
21        match &self.input {
22            InnerJoinInputPlan::NestedLoop(join) => join.base_source(),
23            InnerJoinInputPlan::Hash(join) => join.base_source(),
24            InnerJoinInputPlan::Condition(condition) => condition.base_source(),
25        }
26    }
27
28    pub(crate) fn base_source_mut(&mut self) -> &mut SourcePlan {
29        match &mut self.input {
30            InnerJoinInputPlan::NestedLoop(join) => join.base_source_mut(),
31            InnerJoinInputPlan::Hash(join) => join.base_source_mut(),
32            InnerJoinInputPlan::Condition(condition) => condition.base_source_mut(),
33        }
34    }
35
36    pub(crate) fn joined_sources(&self) -> Vec<&SourcePlan> {
37        match &self.input {
38            InnerJoinInputPlan::NestedLoop(join) => join.joined_sources(),
39            InnerJoinInputPlan::Hash(join) => join.joined_sources(),
40            InnerJoinInputPlan::Condition(condition) => condition.joined_sources(),
41        }
42    }
43}
44
45#[cfg(test)]
46mod tests {
47    use {
48        super::{InnerJoinInputPlan, InnerJoinPlan},
49        crate::{
50            data::Value,
51            plan::{
52                ExprPlan, HashJoinInputPlan, HashJoinPlan, JoinConditionInputPlan,
53                JoinConditionPlan, NestedLoopJoinInputPlan, NestedLoopJoinPlan, SourcePlan,
54                TableAccessPlan, TableSourcePlan,
55            },
56        },
57        pretty_assertions::assert_eq,
58    };
59
60    fn table(name: &str) -> SourcePlan {
61        SourcePlan::Table(TableSourcePlan {
62            name: name.to_owned(),
63            alias: None,
64            access: TableAccessPlan::FullScan,
65        })
66    }
67
68    fn expr() -> ExprPlan {
69        ExprPlan::Value(Value::Bool(true))
70    }
71
72    fn nested_loop() -> NestedLoopJoinPlan {
73        NestedLoopJoinPlan {
74            input: NestedLoopJoinInputPlan::Source(table("A")),
75            right: table("B"),
76        }
77    }
78
79    fn hash() -> HashJoinPlan {
80        HashJoinPlan {
81            input: HashJoinInputPlan::Source(table("A")),
82            right: table("B"),
83            input_key: expr(),
84            right_key: expr(),
85            right_filter: None,
86        }
87    }
88
89    fn condition() -> JoinConditionPlan {
90        JoinConditionPlan {
91            input: JoinConditionInputPlan::NestedLoop(nested_loop()),
92            expr: expr(),
93        }
94    }
95
96    #[test]
97    fn accepts_each_input() {
98        let mut actual = InnerJoinPlan {
99            input: InnerJoinInputPlan::NestedLoop(nested_loop()),
100        };
101        let expected = InnerJoinInputPlan::NestedLoop(nested_loop());
102        assert_eq!(actual.input, expected);
103        assert_eq!(actual.base_source(), &table("A"));
104        let expected = [table("B")];
105        assert_eq!(actual.joined_sources(), expected.iter().collect::<Vec<_>>());
106        *actual.base_source_mut() = table("nested-loop");
107        assert_eq!(actual.base_source(), &table("nested-loop"));
108
109        let mut actual = InnerJoinPlan {
110            input: InnerJoinInputPlan::Hash(hash()),
111        };
112        let expected = InnerJoinInputPlan::Hash(hash());
113        assert_eq!(actual.input, expected);
114        assert_eq!(actual.base_source(), &table("A"));
115        let expected = [table("B")];
116        assert_eq!(actual.joined_sources(), expected.iter().collect::<Vec<_>>());
117        *actual.base_source_mut() = table("hash");
118        assert_eq!(actual.base_source(), &table("hash"));
119
120        let mut actual = InnerJoinPlan {
121            input: InnerJoinInputPlan::Condition(condition()),
122        };
123        let expected = InnerJoinInputPlan::Condition(condition());
124        assert_eq!(actual.input, expected);
125        assert_eq!(actual.base_source(), &table("A"));
126        let expected = [table("B")];
127        assert_eq!(actual.joined_sources(), expected.iter().collect::<Vec<_>>());
128        *actual.base_source_mut() = table("condition");
129        assert_eq!(actual.base_source(), &table("condition"));
130    }
131}