1use compact_str::CompactString;
7
8use crate::api_request::range::Range;
9use crate::api_request::types::{Alias, FieldName, Hint, JoinType};
10use crate::schema_cache::relationship::AnyRelationship;
11use crate::types::identifiers::QualifiedIdentifier;
12
13use super::types::*;
14
15pub type NodeName = CompactString;
17
18#[derive(Debug, Clone)]
27pub struct ReadPlanTree {
28 pub node: ReadPlan,
30 pub forest: Vec<ReadPlanTree>,
32}
33
34impl ReadPlanTree {
35 pub fn leaf(node: ReadPlan) -> Self {
37 Self {
38 node,
39 forest: Vec::new(),
40 }
41 }
42
43 pub fn with_children(node: ReadPlan, forest: Vec<ReadPlanTree>) -> Self {
45 Self { node, forest }
46 }
47
48 pub fn node_mut(&mut self) -> &mut ReadPlan {
50 &mut self.node
51 }
52
53 pub fn children(&self) -> &[ReadPlanTree] {
55 &self.forest
56 }
57
58 pub fn children_mut(&mut self) -> &mut Vec<ReadPlanTree> {
60 &mut self.forest
61 }
62
63 pub fn iter(&self) -> ReadPlanTreeIter<'_> {
65 ReadPlanTreeIter { stack: vec![self] }
66 }
67
68 pub fn node_count(&self) -> usize {
70 1 + self.forest.iter().map(|c| c.node_count()).sum::<usize>()
71 }
72
73 pub fn max_depth(&self) -> usize {
75 if self.forest.is_empty() {
76 self.node.depth
77 } else {
78 self.forest.iter().map(|c| c.max_depth()).max().unwrap_or(0)
79 }
80 }
81}
82
83pub struct ReadPlanTreeIter<'a> {
85 stack: Vec<&'a ReadPlanTree>,
86}
87
88impl<'a> Iterator for ReadPlanTreeIter<'a> {
89 type Item = &'a ReadPlan;
90
91 fn next(&mut self) -> Option<Self::Item> {
92 let tree = self.stack.pop()?;
93 for child in tree.forest.iter().rev() {
95 self.stack.push(child);
96 }
97 Some(&tree.node)
98 }
99}
100
101#[derive(Debug, Clone)]
107pub struct JoinCondition {
108 pub parent: (QualifiedIdentifier, FieldName),
110 pub child: (QualifiedIdentifier, FieldName),
112}
113
114#[derive(Debug, Clone)]
123pub struct ReadPlan {
124 pub select: Vec<CoercibleSelectField>,
126 pub from: QualifiedIdentifier,
128 pub from_alias: Option<Alias>,
130 pub where_: Vec<CoercibleLogicTree>,
132 pub order: Vec<CoercibleOrderTerm>,
134 pub range: Range,
136 pub rel_name: NodeName,
138 pub rel_to_parent: Option<AnyRelationship>,
140 pub rel_join_conds: Vec<JoinCondition>,
142 pub rel_alias: Option<Alias>,
144 pub rel_agg_alias: Alias,
146 pub rel_hint: Option<Hint>,
148 pub rel_join_type: Option<JoinType>,
150 pub rel_spread: Option<SpreadType>,
152 pub rel_select: Vec<RelSelectField>,
154 pub depth: usize,
156}
157
158impl ReadPlan {
159 pub fn root(qi: QualifiedIdentifier) -> Self {
161 let name = qi.name.clone();
162 Self {
163 select: Vec::new(),
164 from: qi,
165 from_alias: None,
166 where_: Vec::new(),
167 order: Vec::new(),
168 range: Range::all(),
169 rel_name: name,
170 rel_to_parent: None,
171 rel_join_conds: Vec::new(),
172 rel_alias: None,
173 rel_agg_alias: CompactString::from("dbrst_agg"),
174 rel_hint: None,
175 rel_join_type: None,
176 rel_spread: None,
177 rel_select: Vec::new(),
178 depth: 0,
179 }
180 }
181
182 pub fn child(qi: QualifiedIdentifier, rel_name: NodeName, depth: usize) -> Self {
184 Self {
185 select: Vec::new(),
186 from: qi,
187 from_alias: None,
188 where_: Vec::new(),
189 order: Vec::new(),
190 range: Range::all(),
191 rel_name,
192 rel_to_parent: None,
193 rel_join_conds: Vec::new(),
194 rel_alias: None,
195 rel_agg_alias: CompactString::from(format!("dbrst_agg_{}", depth)),
196 rel_hint: None,
197 rel_join_type: None,
198 rel_spread: None,
199 rel_select: Vec::new(),
200 depth,
201 }
202 }
203}
204
205#[cfg(test)]
210mod tests {
211 use super::*;
212
213 fn test_qi(name: &str) -> QualifiedIdentifier {
214 QualifiedIdentifier::new("public", name)
215 }
216
217 #[test]
218 fn test_read_plan_root() {
219 let plan = ReadPlan::root(test_qi("users"));
220 assert_eq!(plan.from.name.as_str(), "users");
221 assert_eq!(plan.depth, 0);
222 assert!(plan.rel_to_parent.is_none());
223 assert_eq!(plan.rel_name.as_str(), "users");
224 }
225
226 #[test]
227 fn test_read_plan_child() {
228 let plan = ReadPlan::child(test_qi("posts"), "posts".into(), 1);
229 assert_eq!(plan.depth, 1);
230 assert_eq!(plan.rel_agg_alias.as_str(), "dbrst_agg_1");
231 }
232
233 #[test]
234 fn test_read_plan_tree_leaf() {
235 let tree = ReadPlanTree::leaf(ReadPlan::root(test_qi("users")));
236 assert_eq!(tree.node_count(), 1);
237 assert!(tree.children().is_empty());
238 }
239
240 #[test]
241 fn test_read_plan_tree_with_children() {
242 let root = ReadPlan::root(test_qi("users"));
243 let child1 = ReadPlanTree::leaf(ReadPlan::child(test_qi("posts"), "posts".into(), 1));
244 let child2 = ReadPlanTree::leaf(ReadPlan::child(test_qi("comments"), "comments".into(), 1));
245
246 let tree = ReadPlanTree::with_children(root, vec![child1, child2]);
247 assert_eq!(tree.node_count(), 3);
248 assert_eq!(tree.children().len(), 2);
249 }
250
251 #[test]
252 fn test_read_plan_tree_nested() {
253 let grandchild = ReadPlanTree::leaf(ReadPlan::child(test_qi("tags"), "tags".into(), 2));
254 let child = ReadPlanTree::with_children(
255 ReadPlan::child(test_qi("posts"), "posts".into(), 1),
256 vec![grandchild],
257 );
258 let tree = ReadPlanTree::with_children(ReadPlan::root(test_qi("users")), vec![child]);
259
260 assert_eq!(tree.node_count(), 3);
261 assert_eq!(tree.max_depth(), 2);
262 }
263
264 #[test]
265 fn test_read_plan_tree_iter() {
266 let child = ReadPlanTree::leaf(ReadPlan::child(test_qi("posts"), "posts".into(), 1));
267 let tree = ReadPlanTree::with_children(ReadPlan::root(test_qi("users")), vec![child]);
268
269 let names: Vec<&str> = tree.iter().map(|p| p.rel_name.as_str()).collect();
270 assert_eq!(names, vec!["users", "posts"]);
271 }
272
273 #[test]
274 fn test_join_condition() {
275 let jc = JoinCondition {
276 parent: (test_qi("users"), "id".into()),
277 child: (test_qi("posts"), "user_id".into()),
278 };
279 assert_eq!(jc.parent.1.as_str(), "id");
280 assert_eq!(jc.child.1.as_str(), "user_id");
281 }
282}