gluesql_core/plan/statement/query/join/
inner.rs1use {
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}