use crate::optimizer::heuristic::macros::define_rewrite_pushdown_rule;
use crate::optimizer::heuristic::result::TransformResult;
use crate::planning::plan::core::nodes::access::{IndexScanNode, OrderByItem};
use crate::planning::plan::core::nodes::operation::sort_node::TopNNode;
define_rewrite_pushdown_rule! {
name: PushTopNDownIndexScanRule,
parent_node: TopN,
child_node: IndexScan,
apply: |_ctx, topn_node: &TopNNode, index_scan_node: &IndexScanNode| {
let limit_rows = topn_node.limit();
if let Some(existing_limit) = index_scan_node.limit() {
if limit_rows >= existing_limit {
return Ok(None::<TransformResult>);
}
}
if !index_scan_node.order_by().is_empty() {
return Ok(None::<TransformResult>);
}
let mut order_by_items = Vec::with_capacity(topn_node.sort_items().len());
for item in topn_node.sort_items() {
match item.column_name() {
Some(col_name) => {
order_by_items.push(OrderByItem::new(col_name.to_string(), item.direction));
}
None => {
return Ok(None::<TransformResult>);
}
}
}
let mut new_index_scan = index_scan_node.clone();
new_index_scan.set_limit(limit_rows);
new_index_scan.set_order_by(order_by_items);
let mut result = TransformResult::new();
result.erase_all = true;
result.add_new_node(PlanNodeEnum::IndexScan(new_index_scan));
Ok(Some(result))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::optimizer::heuristic::rule::RewriteRule;
#[test]
fn test_rule_name() {
let rule = PushTopNDownIndexScanRule::new();
assert_eq!(rule.name(), "PushTopNDownIndexScanRule");
}
#[test]
fn test_rule_pattern() {
let rule = PushTopNDownIndexScanRule::new();
let pattern = rule.pattern();
assert!(pattern.node.is_some());
}
}