#[derive(Debug, thiserror::Error)]
pub enum RewriteError {
#[error("Invalid plan node: {0}")]
InvalidNode(String),
#[error("Rewrite failed: {0}")]
RewriteFailed(String),
#[error("Unsupported node types: {0}")]
UnsupportedNodeType(String),
#[error("Optimizer error: {0}")]
OptimizerError(String),
#[error("Loop detection: node {0}")]
CycleDetected(usize),
#[error("Invalid program structure: {0}")]
InvalidPlanStructure(String),
}
impl RewriteError {
pub fn invalid_node(msg: impl Into<String>) -> Self {
Self::InvalidNode(msg.into())
}
pub fn rewrite_failed(msg: impl Into<String>) -> Self {
Self::RewriteFailed(msg.into())
}
pub fn unsupported_node_type(name: impl Into<String>) -> Self {
Self::UnsupportedNodeType(name.into())
}
pub fn optimizer_error(msg: impl Into<String>) -> Self {
Self::OptimizerError(msg.into())
}
pub fn cycle_detected(node_id: usize) -> Self {
Self::CycleDetected(node_id)
}
pub fn invalid_plan_structure(msg: impl Into<String>) -> Self {
Self::InvalidPlanStructure(msg.into())
}
}
pub type RewriteResult<T> = std::result::Result<T, RewriteError>;
#[derive(Debug, Default, Clone)]
pub struct TransformResult {
pub erase_curr: bool,
pub erase_all: bool,
pub new_nodes: Vec<crate::planning::plan::PlanNodeEnum>,
pub new_dependencies: Vec<usize>,
pub has_folded: bool,
}
impl TransformResult {
pub fn new() -> Self {
Self::default()
}
pub fn with_erase_curr(mut self, erase_curr: bool) -> Self {
self.erase_curr = erase_curr;
self
}
pub fn with_erase_all(mut self, erase_all: bool) -> Self {
self.erase_all = erase_all;
self
}
pub fn add_new_node(&mut self, node: crate::planning::plan::PlanNodeEnum) {
self.new_nodes.push(node);
}
pub fn add_new_dependency(&mut self, dep_id: usize) {
self.new_dependencies.push(dep_id);
}
pub fn with_erased(mut self) -> Self {
self.erase_curr = true;
self
}
pub fn mark_folded(&mut self) {
self.has_folded = true;
}
pub fn has_new_nodes(&self) -> bool {
!self.new_nodes.is_empty()
}
pub fn first_new_node(&self) -> Option<&crate::planning::plan::PlanNodeEnum> {
self.new_nodes.first()
}
}
#[derive(Debug, Default, Clone)]
pub struct MatchedResult {
pub nodes: Vec<crate::planning::plan::PlanNodeEnum>,
pub dependencies: Vec<crate::planning::plan::PlanNodeEnum>,
pub root_node: Option<crate::planning::plan::PlanNodeEnum>,
}
impl MatchedResult {
pub fn new() -> Self {
Self::default()
}
pub fn add_node(&mut self, node: crate::planning::plan::PlanNodeEnum) {
self.nodes.push(node);
}
pub fn add_dependency(&mut self, node: crate::planning::plan::PlanNodeEnum) {
self.dependencies.push(node);
}
pub fn set_root_node(&mut self, node: crate::planning::plan::PlanNodeEnum) {
self.root_node = Some(node);
}
pub fn has_matches(&self) -> bool {
!self.nodes.is_empty()
}
pub fn first_node(&self) -> Option<&crate::planning::plan::PlanNodeEnum> {
self.nodes.first()
}
pub fn first_dependency(&self) -> Option<&crate::planning::plan::PlanNodeEnum> {
self.dependencies.first()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::planning::plan::core::nodes::access::graph_scan_node::ScanVerticesNode;
#[test]
fn test_transform_result() {
let mut result = TransformResult::new();
assert!(!result.has_new_nodes());
assert!(!result.has_folded);
let node =
crate::planning::plan::PlanNodeEnum::ScanVertices(ScanVerticesNode::new(1, "default"));
result.add_new_node(node);
assert!(result.has_new_nodes());
assert!(result.first_new_node().is_some());
result.mark_folded();
assert!(result.has_folded);
}
#[test]
fn test_matched_result() {
let mut result = MatchedResult::new();
assert!(!result.has_matches());
let node =
crate::planning::plan::PlanNodeEnum::ScanVertices(ScanVerticesNode::new(1, "default"));
result.add_node(node);
assert!(result.has_matches());
assert!(result.first_node().is_some());
}
#[test]
fn test_rewrite_error() {
let err = RewriteError::invalid_node("test node");
assert!(err.to_string().contains("test node"));
let err = RewriteError::cycle_detected(42);
assert!(err.to_string().contains("42"));
}
}