#![cfg(feature = "python")]
use pyo3::prelude::*;
use pyo3::exceptions::PyRuntimeError;
use crate::DuckTable;
#[pyclass]
pub struct PyDuckTable {
inner: DuckTable,
}
#[pymethods]
impl PyDuckTable {
#[new]
fn new() -> PyResult<Self> {
DuckTable::new()
.map(|inner| Self { inner })
.map_err(|e| PyRuntimeError::new_err(e.to_string()))
}
#[staticmethod]
fn with_file(path: &str) -> PyResult<Self> {
DuckTable::with_file(path)
.map(|inner| Self { inner })
.map_err(|e| PyRuntimeError::new_err(e.to_string()))
}
fn query(&self, sql: &str) -> PyResult<String> {
self.inner.query(sql)
.map_err(|e| PyRuntimeError::new_err(e.to_string()))
}
fn query_raw(&self, sql: &str) -> PyResult<PyQueryResult> {
self.inner.query_raw(sql)
.map(|r| PyQueryResult {
column_names: r.column_names,
rows: r.rows,
})
.map_err(|e| PyRuntimeError::new_err(e.to_string()))
}
}
#[pyclass]
#[derive(Clone)]
pub struct PyQueryResult {
#[pyo3(get)]
pub column_names: Vec<String>,
#[pyo3(get)]
pub rows: Vec<Vec<String>>,
}
#[pymethods]
impl PyQueryResult {
fn __len__(&self) -> usize {
self.rows.len()
}
fn __repr__(&self) -> String {
format!(
"QueryResult(columns={}, rows={})",
self.column_names.len(),
self.rows.len()
)
}
}
#[cfg(feature = "gui")]
#[pyclass]
pub struct PyVizBuilder {
inner: crate::VizBuilder,
}
#[cfg(feature = "gui")]
#[pymethods]
impl PyVizBuilder {
#[new]
fn new() -> Self {
Self {
inner: crate::VizBuilder::new(),
}
}
fn add_query(&mut self, sql: &str) {
self.inner = self.inner.clone().add_query(sql);
}
fn with_chart(
&mut self,
chart_type: &str,
x_column: &str,
y_column: &str,
) -> PyResult<()> {
let chart_type = match chart_type {
"Bar" => crate::ChartType::Bar,
"Line" => crate::ChartType::Line,
"Area" => crate::ChartType::Area,
"Scatter" => crate::ChartType::Scatter,
_ => {
return Err(PyRuntimeError::new_err(format!(
"Invalid chart type: '{}'. Must be one of: 'Bar', 'Line', 'Area', 'Scatter'",
chart_type
)))
}
};
self.inner = self.inner.clone().with_chart(chart_type, x_column, y_column);
Ok(())
}
fn launch(&self) -> PyResult<()> {
self.inner
.clone()
.launch()
.map_err(|e| PyRuntimeError::new_err(e.to_string()))
}
fn __repr__(&self) -> String {
"VizBuilder()".to_string()
}
}
#[pyfunction]
fn vizcreate(sql: String) -> PyResult<()> {
#[cfg(feature = "gui")]
{
crate::vizcreate(sql)
.map_err(|e| PyRuntimeError::new_err(e.to_string()))
}
#[cfg(not(feature = "gui"))]
{
Err(PyRuntimeError::new_err(
"GUI feature not enabled. Build with: maturin develop --features gui"
))
}
}
#[pymodule]
fn sql2viz(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_class::<PyDuckTable>()?;
m.add_class::<PyQueryResult>()?;
#[cfg(feature = "gui")]
m.add_class::<PyVizBuilder>()?;
m.add_function(wrap_pyfunction!(vizcreate, m)?)?;
m.add("__version__", "0.2.0")?;
Ok(())
}