Skip to main content

datafusion_python/expr/
explain.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use std::fmt::{self, Display, Formatter};
19
20use datafusion::logical_expr::LogicalPlan;
21use datafusion::logical_expr::logical_plan::Explain;
22use pyo3::IntoPyObjectExt;
23use pyo3::prelude::*;
24
25use super::logical_node::LogicalNode;
26use crate::common::df_schema::PyDFSchema;
27use crate::errors::py_type_err;
28use crate::sql::logical::PyLogicalPlan;
29
30#[pyclass(
31    from_py_object,
32    frozen,
33    name = "Explain",
34    module = "datafusion.expr",
35    subclass
36)]
37#[derive(Clone)]
38pub struct PyExplain {
39    explain: Explain,
40}
41
42impl From<PyExplain> for Explain {
43    fn from(explain: PyExplain) -> Self {
44        explain.explain
45    }
46}
47
48impl From<Explain> for PyExplain {
49    fn from(explain: Explain) -> PyExplain {
50        PyExplain { explain }
51    }
52}
53
54impl Display for PyExplain {
55    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
56        write!(
57            f,
58            "Explain
59            verbose: {:?}
60            plan: {:?}
61            stringified_plans: {:?}
62            schema: {:?}
63            logical_optimization_succeeded: {:?}",
64            &self.explain.verbose,
65            &self.explain.plan,
66            &self.explain.stringified_plans,
67            &self.explain.schema,
68            &self.explain.logical_optimization_succeeded
69        )
70    }
71}
72
73#[pymethods]
74impl PyExplain {
75    fn explain_string(&self) -> PyResult<Vec<String>> {
76        let mut string_plans: Vec<String> = Vec::new();
77        for stringified_plan in &self.explain.stringified_plans {
78            string_plans.push((*stringified_plan.plan).clone());
79        }
80        Ok(string_plans)
81    }
82
83    fn verbose(&self) -> bool {
84        self.explain.verbose
85    }
86
87    fn plan(&self) -> PyResult<PyLogicalPlan> {
88        Ok(PyLogicalPlan::from((*self.explain.plan).clone()))
89    }
90
91    fn schema(&self) -> PyDFSchema {
92        (*self.explain.schema).clone().into()
93    }
94
95    fn logical_optimization_succceeded(&self) -> bool {
96        self.explain.logical_optimization_succeeded
97    }
98}
99
100impl TryFrom<LogicalPlan> for PyExplain {
101    type Error = PyErr;
102
103    fn try_from(logical_plan: LogicalPlan) -> Result<Self, Self::Error> {
104        match logical_plan {
105            LogicalPlan::Explain(explain) => Ok(PyExplain { explain }),
106            _ => Err(py_type_err("unexpected plan")),
107        }
108    }
109}
110
111impl LogicalNode for PyExplain {
112    fn inputs(&self) -> Vec<PyLogicalPlan> {
113        vec![]
114    }
115
116    fn to_variant<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyAny>> {
117        self.clone().into_bound_py_any(py)
118    }
119}