Skip to main content

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

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