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