Skip to main content

gluesql_core/plan/statement/query/
project.rs

1use {
2    super::{AggregationPlan, FilterPlan, HavingPlan},
3    crate::plan::{InnerJoinPlan, LeftOuterJoinPlan, ProjectionPlan, SourcePlan},
4    serde::{Deserialize, Serialize},
5};
6
7#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
8pub enum ProjectInputPlan {
9    Source(SourcePlan),
10    InnerJoin(Box<InnerJoinPlan>),
11    LeftOuterJoin(Box<LeftOuterJoinPlan>),
12    Filter(FilterPlan),
13    Aggregation(AggregationPlan),
14    Having(HavingPlan),
15}
16
17impl ProjectInputPlan {
18    pub fn base_source(&self) -> &SourcePlan {
19        match self {
20            Self::Source(source) => source,
21            Self::InnerJoin(join) => join.base_source(),
22            Self::LeftOuterJoin(join) => join.base_source(),
23            Self::Filter(filter) => filter.input.base_source(),
24            Self::Aggregation(aggregation) => aggregation.input.base_source(),
25            Self::Having(having) => having.input.input.base_source(),
26        }
27    }
28
29    pub(crate) fn joined_sources(&self) -> Vec<&SourcePlan> {
30        match self {
31            Self::Source(_) => Vec::new(),
32            Self::InnerJoin(join) => join.joined_sources(),
33            Self::LeftOuterJoin(join) => join.joined_sources(),
34            Self::Filter(filter) => filter.input.joined_sources(),
35            Self::Aggregation(aggregation) => aggregation.input.joined_sources(),
36            Self::Having(having) => having.input.input.joined_sources(),
37        }
38    }
39}
40
41#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
42pub struct ProjectPlan {
43    pub input: ProjectInputPlan,
44    pub projection: ProjectionPlan,
45}
46
47#[cfg(test)]
48mod tests {
49    use {
50        super::{ProjectInputPlan, ProjectPlan},
51        crate::{
52            data::Value,
53            plan::{
54                AggregationInputPlan, AggregationPlan, ExprPlan, FilterInputPlan, FilterPlan,
55                HavingPlan, InnerJoinInputPlan, InnerJoinPlan, LeftOuterJoinInputPlan,
56                LeftOuterJoinPlan, NestedLoopJoinInputPlan, NestedLoopJoinPlan, ProjectionPlan,
57                SourcePlan, TableAccessPlan, TableSourcePlan,
58            },
59        },
60        pretty_assertions::assert_eq,
61    };
62
63    fn table(name: &str) -> SourcePlan {
64        SourcePlan::Table(TableSourcePlan {
65            name: name.to_owned(),
66            alias: None,
67            access: TableAccessPlan::FullScan,
68        })
69    }
70
71    #[test]
72    fn project_accepts_each_typed_source_input() {
73        let inner_join = InnerJoinPlan {
74            input: InnerJoinInputPlan::NestedLoop(NestedLoopJoinPlan {
75                input: NestedLoopJoinInputPlan::Source(table("A")),
76                right: table("B"),
77            }),
78        };
79        let left_outer_join = LeftOuterJoinPlan {
80            input: LeftOuterJoinInputPlan::NestedLoop(NestedLoopJoinPlan {
81                input: NestedLoopJoinInputPlan::Source(table("A")),
82                right: table("B"),
83            }),
84        };
85        let filter = FilterPlan {
86            input: FilterInputPlan::InnerJoin(Box::new(inner_join.clone())),
87            expr: ExprPlan::Value(Value::Bool(true)),
88        };
89        let aggregation = AggregationPlan {
90            input: AggregationInputPlan::Filter(filter.clone()),
91            group_by: Vec::new(),
92            aggregate_slots: Vec::new(),
93        };
94        let having_plan = HavingPlan {
95            input: aggregation.clone(),
96            expr: ExprPlan::Value(Value::Bool(true)),
97        };
98        let projection = ProjectionPlan::SelectItems(Vec::new());
99
100        let relation = ProjectPlan {
101            input: ProjectInputPlan::Source(table("A")),
102            projection: projection.clone(),
103        };
104        let inner = ProjectPlan {
105            input: ProjectInputPlan::InnerJoin(Box::new(inner_join.clone())),
106            projection: projection.clone(),
107        };
108        let left_outer = ProjectPlan {
109            input: ProjectInputPlan::LeftOuterJoin(Box::new(left_outer_join.clone())),
110            projection: projection.clone(),
111        };
112        let filtered = ProjectPlan {
113            input: ProjectInputPlan::Filter(filter.clone()),
114            projection: projection.clone(),
115        };
116        let aggregated = ProjectPlan {
117            input: ProjectInputPlan::Aggregation(aggregation.clone()),
118            projection: projection.clone(),
119        };
120        let having = ProjectPlan {
121            input: ProjectInputPlan::Having(having_plan.clone()),
122            projection,
123        };
124
125        assert_eq!(relation.input, ProjectInputPlan::Source(table("A")));
126        assert_eq!(
127            inner.input,
128            ProjectInputPlan::InnerJoin(Box::new(inner_join))
129        );
130        assert_eq!(
131            left_outer.input,
132            ProjectInputPlan::LeftOuterJoin(Box::new(left_outer_join))
133        );
134        assert_eq!(filtered.input, ProjectInputPlan::Filter(filter));
135        assert_eq!(aggregated.input, ProjectInputPlan::Aggregation(aggregation));
136        assert_eq!(having.input, ProjectInputPlan::Having(having_plan));
137
138        assert_eq!(relation.input.base_source(), &table("A"));
139        assert_eq!(relation.input.joined_sources(), Vec::<&SourcePlan>::new());
140        assert_eq!(inner.input.base_source(), &table("A"));
141        let expected = [table("B")];
142        assert_eq!(
143            inner.input.joined_sources(),
144            expected.iter().collect::<Vec<_>>()
145        );
146        assert_eq!(left_outer.input.base_source(), &table("A"));
147        let expected = [table("B")];
148        assert_eq!(
149            left_outer.input.joined_sources(),
150            expected.iter().collect::<Vec<_>>()
151        );
152        assert_eq!(filtered.input.base_source(), &table("A"));
153        let expected = [table("B")];
154        assert_eq!(
155            filtered.input.joined_sources(),
156            expected.iter().collect::<Vec<_>>()
157        );
158        assert_eq!(aggregated.input.base_source(), &table("A"));
159        let expected = [table("B")];
160        assert_eq!(
161            aggregated.input.joined_sources(),
162            expected.iter().collect::<Vec<_>>()
163        );
164        assert_eq!(having.input.base_source(), &table("A"));
165        let expected = [table("B")];
166        assert_eq!(
167            having.input.joined_sources(),
168            expected.iter().collect::<Vec<_>>()
169        );
170    }
171}