datafusion_python/expr/
table_scan.rs1use std::fmt::{self, Display, Formatter};
19
20use datafusion::common::TableReference;
21use datafusion::logical_expr::logical_plan::TableScan;
22use pyo3::IntoPyObjectExt;
23use pyo3::prelude::*;
24
25use crate::common::df_schema::PyDFSchema;
26use crate::expr::PyExpr;
27use crate::expr::logical_node::LogicalNode;
28use crate::sql::logical::PyLogicalPlan;
29
30#[pyclass(
31 from_py_object,
32 frozen,
33 name = "TableScan",
34 module = "datafusion.expr",
35 subclass
36)]
37#[derive(Clone)]
38pub struct PyTableScan {
39 table_scan: TableScan,
40}
41
42impl PyTableScan {
43 pub fn new(table_scan: TableScan) -> Self {
44 Self { table_scan }
45 }
46}
47
48impl From<PyTableScan> for TableScan {
49 fn from(tbl_scan: PyTableScan) -> TableScan {
50 tbl_scan.table_scan
51 }
52}
53
54impl From<TableScan> for PyTableScan {
55 fn from(table_scan: TableScan) -> PyTableScan {
56 PyTableScan { table_scan }
57 }
58}
59
60impl Display for PyTableScan {
61 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
62 write!(
63 f,
64 "TableScan\nTable Name: {}
65 Projections: {:?}
66 Projected Schema: {:?}
67 Filters: {:?}",
68 &self.table_scan.table_name,
69 &self.py_projections(),
70 &self.py_schema(),
71 &self.py_filters(),
72 )
73 }
74}
75
76#[pymethods]
77impl PyTableScan {
78 #[pyo3(name = "table_name")]
80 fn py_table_name(&self) -> PyResult<String> {
81 Ok(format!("{}", self.table_scan.table_name))
82 }
83
84 #[pyo3(name = "fqn")]
85 fn fqn(&self) -> PyResult<(Option<String>, Option<String>, String)> {
86 let table_ref: TableReference = self.table_scan.table_name.clone();
87 Ok(match table_ref {
88 TableReference::Bare { table } => (None, None, table.to_string()),
89 TableReference::Partial { schema, table } => {
90 (None, Some(schema.to_string()), table.to_string())
91 }
92 TableReference::Full {
93 catalog,
94 schema,
95 table,
96 } => (
97 Some(catalog.to_string()),
98 Some(schema.to_string()),
99 table.to_string(),
100 ),
101 })
102 }
103
104 #[pyo3(name = "projection")]
110 fn py_projections(&self) -> PyResult<Vec<(usize, String)>> {
111 match &self.table_scan.projection {
112 Some(indices) => {
113 let schema = self.table_scan.source.schema();
114 Ok(indices
115 .iter()
116 .map(|i| (*i, schema.field(*i).name().to_string()))
117 .collect())
118 }
119 None => Ok(vec![]),
120 }
121 }
122
123 #[pyo3(name = "schema")]
125 fn py_schema(&self) -> PyResult<PyDFSchema> {
126 Ok((*self.table_scan.projected_schema).clone().into())
127 }
128
129 #[pyo3(name = "filters")]
132 fn py_filters(&self) -> PyResult<Vec<PyExpr>> {
133 Ok(self
134 .table_scan
135 .filters
136 .iter()
137 .map(|expr| PyExpr::from(expr.clone()))
138 .collect())
139 }
140
141 #[pyo3(name = "fetch")]
143 fn py_fetch(&self) -> PyResult<Option<usize>> {
144 Ok(self.table_scan.fetch)
145 }
146
147 fn __repr__(&self) -> PyResult<String> {
148 Ok(format!("TableScan({self})"))
149 }
150}
151
152impl LogicalNode for PyTableScan {
153 fn inputs(&self) -> Vec<PyLogicalPlan> {
154 vec![]
156 }
157
158 fn to_variant<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyAny>> {
159 self.clone().into_bound_py_any(py)
160 }
161}