use std::fmt;
use crate::logical_expr::{StringifiedPlan, ToStringifiedPlan};
use super::{accept, ExecutionPlan, ExecutionPlanVisitor};
#[derive(Debug, Clone, Copy)]
pub enum DisplayFormatType {
Default,
}
pub struct DisplayableExecutionPlan<'a> {
inner: &'a dyn ExecutionPlan,
show_metrics: ShowMetrics,
}
impl<'a> DisplayableExecutionPlan<'a> {
pub fn new(inner: &'a dyn ExecutionPlan) -> Self {
Self {
inner,
show_metrics: ShowMetrics::None,
}
}
pub fn with_metrics(inner: &'a dyn ExecutionPlan) -> Self {
Self {
inner,
show_metrics: ShowMetrics::Aggregated,
}
}
pub fn with_full_metrics(inner: &'a dyn ExecutionPlan) -> Self {
Self {
inner,
show_metrics: ShowMetrics::Full,
}
}
pub fn indent(&self) -> impl fmt::Display + 'a {
struct Wrapper<'a> {
plan: &'a dyn ExecutionPlan,
show_metrics: ShowMetrics,
}
impl<'a> fmt::Display for Wrapper<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let t = DisplayFormatType::Default;
let mut visitor = IndentVisitor {
t,
f,
indent: 0,
show_metrics: self.show_metrics,
};
accept(self.plan, &mut visitor)
}
}
Wrapper {
plan: self.inner,
show_metrics: self.show_metrics,
}
}
pub fn one_line(&self) -> impl fmt::Display + 'a {
struct Wrapper<'a> {
plan: &'a dyn ExecutionPlan,
show_metrics: ShowMetrics,
}
impl<'a> fmt::Display for Wrapper<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut visitor = IndentVisitor {
f,
t: DisplayFormatType::Default,
indent: 0,
show_metrics: self.show_metrics,
};
visitor.pre_visit(self.plan)?;
Ok(())
}
}
Wrapper {
plan: self.inner,
show_metrics: self.show_metrics,
}
}
}
#[derive(Debug, Clone, Copy)]
enum ShowMetrics {
None,
Aggregated,
Full,
}
struct IndentVisitor<'a, 'b> {
t: DisplayFormatType,
f: &'a mut fmt::Formatter<'b>,
indent: usize,
show_metrics: ShowMetrics,
}
impl<'a, 'b> ExecutionPlanVisitor for IndentVisitor<'a, 'b> {
type Error = fmt::Error;
fn pre_visit(&mut self, plan: &dyn ExecutionPlan) -> Result<bool, Self::Error> {
write!(self.f, "{:indent$}", "", indent = self.indent * 2)?;
plan.fmt_as(self.t, self.f)?;
match self.show_metrics {
ShowMetrics::None => {}
ShowMetrics::Aggregated => {
if let Some(metrics) = plan.metrics() {
let metrics = metrics
.aggregate_by_name()
.sorted_for_display()
.timestamps_removed();
write!(self.f, ", metrics=[{metrics}]")?;
} else {
write!(self.f, ", metrics=[]")?;
}
}
ShowMetrics::Full => {
if let Some(metrics) = plan.metrics() {
write!(self.f, ", metrics=[{metrics}]")?;
} else {
write!(self.f, ", metrics=[]")?;
}
}
}
writeln!(self.f)?;
self.indent += 1;
Ok(true)
}
fn post_visit(&mut self, _plan: &dyn ExecutionPlan) -> Result<bool, Self::Error> {
self.indent -= 1;
Ok(true)
}
}
impl<'a> ToStringifiedPlan for DisplayableExecutionPlan<'a> {
fn to_stringified(
&self,
plan_type: crate::logical_expr::PlanType,
) -> StringifiedPlan {
StringifiedPlan::new(plan_type, self.indent().to_string())
}
}