linkrs_query/optimizer/heuristic/
context.rs1use std::cell::RefCell;
7use std::collections::HashMap;
8use std::rc::Rc;
9use std::sync::Arc;
10
11use crate::planning::plan::PlanNodeEnum;
12use linkrs_core::types::expr::expression_context::ExpressionAnalysisContext;
13
14#[derive(Debug)]
20pub struct RewriteContext {
21 node_id_counter: usize,
23 plan_node_to_id: RefCell<HashMap<usize, usize>>,
25 nodes_by_id: RefCell<HashMap<usize, Rc<RefCell<PlanNodeWrapper>>>>,
27 expr_context: Arc<ExpressionAnalysisContext>,
29 current_node_id: usize,
33}
34
35#[derive(Debug, Clone)]
39pub struct PlanNodeWrapper {
40 pub id: usize,
41 pub plan_node: PlanNodeEnum,
42 pub dependencies: Vec<usize>,
43}
44
45impl PlanNodeWrapper {
46 pub fn new(id: usize, plan_node: PlanNodeEnum) -> Self {
47 Self {
48 id,
49 plan_node,
50 dependencies: Vec::new(),
51 }
52 }
53}
54
55impl Default for RewriteContext {
56 fn default() -> Self {
57 Self {
58 node_id_counter: 0,
59 plan_node_to_id: RefCell::new(HashMap::new()),
60 nodes_by_id: RefCell::new(HashMap::new()),
61 expr_context: Arc::new(ExpressionAnalysisContext::new()),
62 current_node_id: usize::MAX,
63 }
64 }
65}
66
67impl RewriteContext {
68 pub fn new() -> Self {
70 Self::default()
71 }
72
73 pub fn with_expr_context(expr_context: Arc<ExpressionAnalysisContext>) -> Self {
75 Self {
76 node_id_counter: 0,
77 plan_node_to_id: RefCell::new(HashMap::new()),
78 nodes_by_id: RefCell::new(HashMap::new()),
79 expr_context,
80 current_node_id: usize::MAX,
81 }
82 }
83
84 pub fn allocate_node_id(&mut self) -> usize {
86 let id = self.node_id_counter;
87 self.node_id_counter += 1;
88 id
89 }
90
91 pub fn register_node(
93 &mut self,
94 node_id: usize,
95 plan_node: PlanNodeEnum,
96 ) -> Rc<RefCell<PlanNodeWrapper>> {
97 let wrapper = Rc::new(RefCell::new(PlanNodeWrapper::new(node_id, plan_node)));
98 self.nodes_by_id
99 .borrow_mut()
100 .insert(node_id, wrapper.clone());
101 wrapper
102 }
103
104 pub fn set_current_node_id(&mut self, node_id: usize) {
106 self.current_node_id = node_id;
107 }
108
109 pub fn current_node_id(&self) -> usize {
112 self.current_node_id
113 }
114
115 pub fn find_node_by_id(&self, id: usize) -> Option<Rc<RefCell<PlanNodeWrapper>>> {
117 self.nodes_by_id.borrow().get(&id).cloned()
118 }
119
120 pub fn add_plan_node_mapping(&self, plan_node_id: usize, rewrite_node_id: usize) {
122 self.plan_node_to_id
123 .borrow_mut()
124 .insert(plan_node_id, rewrite_node_id);
125 }
126
127 pub fn find_rewrite_id_by_plan_id(&self, plan_node_id: usize) -> Option<usize> {
129 self.plan_node_to_id.borrow().get(&plan_node_id).copied()
130 }
131
132 pub fn node_count(&self) -> usize {
134 self.node_id_counter
135 }
136
137 pub fn expr_context(&self) -> Arc<ExpressionAnalysisContext> {
139 self.expr_context.clone()
140 }
141}
142
143#[cfg(test)]
144mod tests {
145 use super::*;
146 use crate::planning::plan::core::nodes::access::graph_scan_node::ScanVerticesNode;
147
148 #[test]
149 fn test_context_creation() {
150 let ctx = RewriteContext::new();
151 assert_eq!(ctx.node_count(), 0);
152 }
153
154 #[test]
155 fn test_allocate_node_id() {
156 let mut ctx = RewriteContext::new();
157 assert_eq!(ctx.allocate_node_id(), 0);
158 assert_eq!(ctx.allocate_node_id(), 1);
159 assert_eq!(ctx.allocate_node_id(), 2);
160 }
161
162 #[test]
163 fn test_register_and_find_node() {
164 let mut ctx = RewriteContext::new();
165 let node_id = ctx.allocate_node_id();
166 let plan_node = PlanNodeEnum::ScanVertices(ScanVerticesNode::new(1, "default"));
167
168 let wrapper = ctx.register_node(node_id, plan_node);
169 assert_eq!(wrapper.borrow().id, node_id);
170
171 let found = ctx.find_node_by_id(node_id);
172 assert!(found.is_some());
173 assert_eq!(found.expect("Failed to find node").borrow().id, node_id);
174 }
175}