use crate::optimizer::heuristic::context::RewriteContext;
use crate::optimizer::heuristic::pattern::Pattern;
use crate::optimizer::heuristic::result::{MatchedResult, RewriteResult, TransformResult};
use crate::planning::plan::PlanNodeEnum;
pub trait RewriteRule: std::fmt::Debug + Send + Sync {
fn name(&self) -> &'static str;
fn pattern(&self) -> Pattern;
fn apply(
&self,
ctx: &mut RewriteContext,
node: &PlanNodeEnum,
) -> RewriteResult<Option<TransformResult>>;
fn match_pattern(&self, node: &PlanNodeEnum) -> RewriteResult<Option<MatchedResult>> {
if self.pattern().matches(node) {
let mut result = MatchedResult::new();
result.add_node(node.clone());
for dep in node.dependencies() {
result.add_dependency(dep.clone());
}
result.set_root_node(node.clone());
Ok(Some(result))
} else {
Ok(None)
}
}
fn matches(&self, node: &PlanNodeEnum) -> bool {
self.pattern().matches(node)
}
}
pub trait BaseRewriteRule: RewriteRule {}
pub trait MergeRule: RewriteRule {
fn can_merge(&self, parent: &PlanNodeEnum, child: &PlanNodeEnum) -> bool;
fn create_merged_node(
&self,
ctx: &mut RewriteContext,
parent: &PlanNodeEnum,
child: &PlanNodeEnum,
) -> RewriteResult<Option<TransformResult>>;
}
pub trait PushDownRule: RewriteRule {
fn can_push_down(&self, node: &PlanNodeEnum, target: &PlanNodeEnum) -> bool;
fn push_down(
&self,
ctx: &mut RewriteContext,
node: &PlanNodeEnum,
target: &PlanNodeEnum,
) -> RewriteResult<Option<TransformResult>>;
}
pub trait EliminationRule: RewriteRule {
fn can_eliminate(&self, node: &PlanNodeEnum) -> bool;
fn eliminate(
&self,
ctx: &mut RewriteContext,
node: &PlanNodeEnum,
) -> RewriteResult<Option<TransformResult>>;
}
#[derive(Debug)]
pub struct RuleWrapper<T: RewriteRule> {
inner: T,
}
impl<T: RewriteRule> RuleWrapper<T> {
pub fn new(rule: T) -> Self {
Self { inner: rule }
}
pub fn into_inner(self) -> T {
self.inner
}
}
impl<T: RewriteRule> RewriteRule for RuleWrapper<T> {
fn name(&self) -> &'static str {
self.inner.name()
}
fn pattern(&self) -> Pattern {
self.inner.pattern()
}
fn apply(
&self,
ctx: &mut RewriteContext,
node: &PlanNodeEnum,
) -> RewriteResult<Option<TransformResult>> {
self.inner.apply(ctx, node)
}
}
pub trait IntoRuleWrapper: RewriteRule + Sized {
fn into_wrapper(self) -> RuleWrapper<Self> {
RuleWrapper::new(self)
}
}
impl<T: RewriteRule + Sized> IntoRuleWrapper for T {}
#[cfg(test)]
mod tests {
use super::*;
use crate::planning::plan::core::nodes::access::graph_scan_node::ScanVerticesNode;
#[derive(Debug)]
struct TestRule;
impl RewriteRule for TestRule {
fn name(&self) -> &'static str {
"TestRule"
}
fn pattern(&self) -> Pattern {
Pattern::new_with_name("ScanVertices")
}
fn apply(
&self,
_ctx: &mut RewriteContext,
_node: &PlanNodeEnum,
) -> RewriteResult<Option<TransformResult>> {
Ok(None)
}
}
#[test]
fn test_rule_name() {
let rule = TestRule;
assert_eq!(rule.name(), "TestRule");
}
#[test]
fn test_rule_matches() {
let rule = TestRule;
let node = PlanNodeEnum::ScanVertices(ScanVerticesNode::new(1, "default"));
assert!(rule.matches(&node));
}
#[test]
fn test_rule_wrapper() {
let rule = TestRule;
let wrapper = rule.into_wrapper();
assert_eq!(wrapper.name(), "TestRule");
}
}