datafusion_python/expr/
explain.rs1use std::fmt::{self, Display, Formatter};
19
20use datafusion::logical_expr::{logical_plan::Explain, LogicalPlan};
21use pyo3::{prelude::*, IntoPyObjectExt};
22
23use crate::{common::df_schema::PyDFSchema, errors::py_type_err, sql::logical::PyLogicalPlan};
24
25use super::logical_node::LogicalNode;
26
27#[pyclass(name = "Explain", module = "datafusion.expr", subclass)]
28#[derive(Clone)]
29pub struct PyExplain {
30 explain: Explain,
31}
32
33impl From<PyExplain> for Explain {
34 fn from(explain: PyExplain) -> Self {
35 explain.explain
36 }
37}
38
39impl From<Explain> for PyExplain {
40 fn from(explain: Explain) -> PyExplain {
41 PyExplain { explain }
42 }
43}
44
45impl Display for PyExplain {
46 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
47 write!(
48 f,
49 "Explain
50 verbose: {:?}
51 plan: {:?}
52 stringified_plans: {:?}
53 schema: {:?}
54 logical_optimization_succeeded: {:?}",
55 &self.explain.verbose,
56 &self.explain.plan,
57 &self.explain.stringified_plans,
58 &self.explain.schema,
59 &self.explain.logical_optimization_succeeded
60 )
61 }
62}
63
64#[pymethods]
65impl PyExplain {
66 fn explain_string(&self) -> PyResult<Vec<String>> {
67 let mut string_plans: Vec<String> = Vec::new();
68 for stringified_plan in &self.explain.stringified_plans {
69 string_plans.push((*stringified_plan.plan).clone());
70 }
71 Ok(string_plans)
72 }
73
74 fn verbose(&self) -> bool {
75 self.explain.verbose
76 }
77
78 fn plan(&self) -> PyResult<PyLogicalPlan> {
79 Ok(PyLogicalPlan::from((*self.explain.plan).clone()))
80 }
81
82 fn schema(&self) -> PyDFSchema {
83 (*self.explain.schema).clone().into()
84 }
85
86 fn logical_optimization_succceeded(&self) -> bool {
87 self.explain.logical_optimization_succeeded
88 }
89}
90
91impl TryFrom<LogicalPlan> for PyExplain {
92 type Error = PyErr;
93
94 fn try_from(logical_plan: LogicalPlan) -> Result<Self, Self::Error> {
95 match logical_plan {
96 LogicalPlan::Explain(explain) => Ok(PyExplain { explain }),
97 _ => Err(py_type_err("unexpected plan")),
98 }
99 }
100}
101
102impl LogicalNode for PyExplain {
103 fn inputs(&self) -> Vec<PyLogicalPlan> {
104 vec![]
105 }
106
107 fn to_variant<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyAny>> {
108 self.clone().into_bound_py_any(py)
109 }
110}