use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use std::sync::Arc;
use crate::planning::plan::PlanNodeEnum;
use linkrs_core::types::expr::expression_context::ExpressionAnalysisContext;
#[derive(Debug)]
pub struct RewriteContext {
node_id_counter: usize,
plan_node_to_id: RefCell<HashMap<usize, usize>>,
nodes_by_id: RefCell<HashMap<usize, Rc<RefCell<PlanNodeWrapper>>>>,
expr_context: Arc<ExpressionAnalysisContext>,
current_node_id: usize,
}
#[derive(Debug, Clone)]
pub struct PlanNodeWrapper {
pub id: usize,
pub plan_node: PlanNodeEnum,
pub dependencies: Vec<usize>,
}
impl PlanNodeWrapper {
pub fn new(id: usize, plan_node: PlanNodeEnum) -> Self {
Self {
id,
plan_node,
dependencies: Vec::new(),
}
}
}
impl Default for RewriteContext {
fn default() -> Self {
Self {
node_id_counter: 0,
plan_node_to_id: RefCell::new(HashMap::new()),
nodes_by_id: RefCell::new(HashMap::new()),
expr_context: Arc::new(ExpressionAnalysisContext::new()),
current_node_id: usize::MAX,
}
}
}
impl RewriteContext {
pub fn new() -> Self {
Self::default()
}
pub fn with_expr_context(expr_context: Arc<ExpressionAnalysisContext>) -> Self {
Self {
node_id_counter: 0,
plan_node_to_id: RefCell::new(HashMap::new()),
nodes_by_id: RefCell::new(HashMap::new()),
expr_context,
current_node_id: usize::MAX,
}
}
pub fn allocate_node_id(&mut self) -> usize {
let id = self.node_id_counter;
self.node_id_counter += 1;
id
}
pub fn register_node(
&mut self,
node_id: usize,
plan_node: PlanNodeEnum,
) -> Rc<RefCell<PlanNodeWrapper>> {
let wrapper = Rc::new(RefCell::new(PlanNodeWrapper::new(node_id, plan_node)));
self.nodes_by_id
.borrow_mut()
.insert(node_id, wrapper.clone());
wrapper
}
pub fn set_current_node_id(&mut self, node_id: usize) {
self.current_node_id = node_id;
}
pub fn current_node_id(&self) -> usize {
self.current_node_id
}
pub fn find_node_by_id(&self, id: usize) -> Option<Rc<RefCell<PlanNodeWrapper>>> {
self.nodes_by_id.borrow().get(&id).cloned()
}
pub fn add_plan_node_mapping(&self, plan_node_id: usize, rewrite_node_id: usize) {
self.plan_node_to_id
.borrow_mut()
.insert(plan_node_id, rewrite_node_id);
}
pub fn find_rewrite_id_by_plan_id(&self, plan_node_id: usize) -> Option<usize> {
self.plan_node_to_id.borrow().get(&plan_node_id).copied()
}
pub fn node_count(&self) -> usize {
self.node_id_counter
}
pub fn expr_context(&self) -> Arc<ExpressionAnalysisContext> {
self.expr_context.clone()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::planning::plan::core::nodes::access::graph_scan_node::ScanVerticesNode;
#[test]
fn test_context_creation() {
let ctx = RewriteContext::new();
assert_eq!(ctx.node_count(), 0);
}
#[test]
fn test_allocate_node_id() {
let mut ctx = RewriteContext::new();
assert_eq!(ctx.allocate_node_id(), 0);
assert_eq!(ctx.allocate_node_id(), 1);
assert_eq!(ctx.allocate_node_id(), 2);
}
#[test]
fn test_register_and_find_node() {
let mut ctx = RewriteContext::new();
let node_id = ctx.allocate_node_id();
let plan_node = PlanNodeEnum::ScanVertices(ScanVerticesNode::new(1, "default"));
let wrapper = ctx.register_node(node_id, plan_node);
assert_eq!(wrapper.borrow().id, node_id);
let found = ctx.find_node_by_id(node_id);
assert!(found.is_some());
assert_eq!(found.expect("Failed to find node").borrow().id, node_id);
}
}