Skip to content

Commit c1aff57

Browse files
committed
Rename reader.execute to reader.execute_sql
1 parent 3bc3645 commit c1aff57

12 files changed

Lines changed: 55 additions & 55 deletions

File tree

CLAUDE.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ let json = prepared.render(&writer)?;
207207

208208
**Reader trait** (data source abstraction):
209209

210-
- `execute(sql)` - Run SQL, return DataFrame
210+
- `execute_sql(sql)` - Run SQL, return DataFrame
211211
- `register(name, df)` - Register DataFrame as table
212212
- Implementation: `DuckDBReader`
213213

@@ -505,7 +505,7 @@ pub type Result<T> = std::result::Result<T, GgsqlError>;
505505

506506
```rust
507507
pub trait Reader {
508-
fn execute(&self, sql: &str) -> Result<DataFrame>;
508+
fn execute_sql(&self, sql: &str) -> Result<DataFrame>;
509509
fn supports_query(&self, sql: &str) -> bool;
510510
}
511511
```
@@ -871,7 +871,7 @@ When running in Positron IDE, the extension provides enhanced functionality:
871871
- PyO3-based Rust bindings compiled to a native Python extension
872872
- Two-stage API mirroring the Rust API: `prepare()``render()`
873873
- DuckDB reader with DataFrame registration
874-
- Custom Python reader support: any object with `execute(sql) -> DataFrame` method
874+
- Custom Python reader support: any object with `execute_sql(sql) -> DataFrame` method
875875
- Works with any narwhals-compatible DataFrame (polars, pandas, etc.)
876876
- LazyFrames are collected automatically
877877
- Returns native `altair.Chart` objects via `render_altair()` convenience function
@@ -976,7 +976,7 @@ print(f"Errors: {validated.errors()}")
976976

977977
**Custom Python Readers**:
978978

979-
Any Python object with an `execute(sql: str) -> polars.DataFrame` method can be used as a reader:
979+
Any Python object with an `execute_sql(sql: str) -> polars.DataFrame` method can be used as a reader:
980980

981981
```python
982982
import ggsql
@@ -985,7 +985,7 @@ import polars as pl
985985
class MyReader:
986986
"""Custom reader that returns static data."""
987987

988-
def execute(self, sql: str) -> pl.DataFrame:
988+
def execute_sql(self, sql: str) -> pl.DataFrame:
989989
return pl.DataFrame({"x": [1, 2, 3], "y": [10, 20, 30]})
990990

991991
# Use custom reader with prepare()

ggsql-jupyter/src/executor.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ impl QueryExecutor {
6060
// 2. Check if there's a visualization
6161
if !validated.has_visual() {
6262
// Pure SQL query - execute directly and return DataFrame
63-
let df = self.reader.execute(code)?;
63+
let df = self.reader.execute_sql(code)?;
6464
tracing::info!(
6565
"Pure SQL executed: {} rows, {} cols",
6666
df.height(),

ggsql-python/README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ reader = ggsql.DuckDBReader("duckdb:///path/to/file.db") # File database
127127
**Methods:**
128128

129129
- `register(name: str, df: polars.DataFrame)` - Register a DataFrame as a queryable table
130-
- `execute(sql: str) -> polars.DataFrame` - Execute SQL and return results
130+
- `execute_sql(sql: str) -> polars.DataFrame` - Execute SQL and return results
131131
- `supports_register() -> bool` - Check if registration is supported
132132

133133
#### `VegaLiteWriter()`
@@ -236,7 +236,7 @@ ggsql.render_altair(df, "VISUALISE x, y, category AS color DRAW point")
236236

237237
### Custom Readers
238238

239-
You can use any Python object with an `execute(sql: str) -> polars.DataFrame` method as a reader. This enables integration with any data source.
239+
You can use any Python object with an `execute_sql(sql: str) -> polars.DataFrame` method as a reader. This enables integration with any data source.
240240

241241
```python
242242
import ggsql
@@ -248,7 +248,7 @@ class CSVReader:
248248
def __init__(self, data_dir: str):
249249
self.data_dir = data_dir
250250

251-
def execute(self, sql: str) -> pl.DataFrame:
251+
def execute_sql(self, sql: str) -> pl.DataFrame:
252252
# Simple implementation: ignore SQL and return fixed data
253253
# A real implementation would parse SQL to determine which file to load
254254
return pl.read_csv(f"{self.data_dir}/data.csv")
@@ -275,7 +275,7 @@ class AdvancedReader:
275275
def __init__(self):
276276
self.tables = {}
277277

278-
def execute(self, sql: str) -> pl.DataFrame:
278+
def execute_sql(self, sql: str) -> pl.DataFrame:
279279
# Your SQL execution logic here
280280
...
281281

ggsql-python/src/lib.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ fn py_to_polars_inner(df: &Bound<'_, PyAny>) -> PyResult<DataFrame> {
6262

6363
df.call_method1("write_ipc", (&bytes_io,)).map_err(|_| {
6464
PyErr::new::<pyo3::exceptions::PyTypeError, _>(
65-
"Reader.execute() must return a polars.DataFrame",
65+
"Reader.execute_sql() must return a polars.DataFrame",
6666
)
6767
})?;
6868

@@ -127,12 +127,12 @@ struct PyReaderBridge {
127127
}
128128

129129
impl Reader for PyReaderBridge {
130-
fn execute(&self, sql: &str) -> ggsql::Result<DataFrame> {
130+
fn execute_sql(&self, sql: &str) -> ggsql::Result<DataFrame> {
131131
Python::attach(|py| {
132132
let bound = self.obj.bind(py);
133133
let result = bound
134-
.call_method1("execute", (sql,))
135-
.map_err(|e| GgsqlError::ReaderError(format!("Reader.execute() failed: {}", e)))?;
134+
.call_method1("execute_sql", (sql,))
135+
.map_err(|e| GgsqlError::ReaderError(format!("Reader.execute_sql() failed: {}", e)))?;
136136
py_to_polars_inner(&result).map_err(|e| GgsqlError::ReaderError(e.to_string()))
137137
})
138138
}
@@ -190,11 +190,11 @@ macro_rules! try_native_readers {
190190
/// Examples
191191
/// --------
192192
/// >>> reader = DuckDBReader("duckdb://memory")
193-
/// >>> df = reader.execute("SELECT 1 as x, 2 as y")
193+
/// >>> df = reader.execute_sql("SELECT 1 as x, 2 as y")
194194
///
195195
/// >>> reader = DuckDBReader("duckdb://memory")
196196
/// >>> reader.register("data", pl.DataFrame({"x": [1, 2, 3]}))
197-
/// >>> df = reader.execute("SELECT * FROM data WHERE x > 1")
197+
/// >>> df = reader.execute_sql("SELECT * FROM data WHERE x > 1")
198198
#[pyclass(name = "DuckDBReader", unsendable)]
199199
struct PyDuckDBReader {
200200
inner: RustDuckDBReader,
@@ -264,10 +264,10 @@ impl PyDuckDBReader {
264264
/// ------
265265
/// ValueError
266266
/// If the SQL is invalid or execution fails.
267-
fn execute(&self, py: Python<'_>, sql: &str) -> PyResult<Py<PyAny>> {
267+
fn execute_sql(&self, py: Python<'_>, sql: &str) -> PyResult<Py<PyAny>> {
268268
let df = self
269269
.inner
270-
.execute(sql)
270+
.execute_sql(sql)
271271
.map_err(|e| PyErr::new::<pyo3::exceptions::PyValueError, _>(e.to_string()))?;
272272
polars_to_py(py, &df)
273273
}

ggsql-python/tests/test_ggsql.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ def test_create_in_memory(self):
6262

6363
def test_execute_simple_query(self):
6464
reader = ggsql.DuckDBReader("duckdb://memory")
65-
df = reader.execute("SELECT 1 AS x, 2 AS y")
65+
df = reader.execute_sql("SELECT 1 AS x, 2 AS y")
6666
assert isinstance(df, pl.DataFrame)
6767
assert df.shape == (1, 2)
6868
assert list(df.columns) == ["x", "y"]
@@ -72,7 +72,7 @@ def test_register_and_query(self):
7272
df = pl.DataFrame({"x": [1, 2, 3], "y": [10, 20, 30]})
7373
reader.register("my_data", df)
7474

75-
result = reader.execute("SELECT * FROM my_data WHERE x > 1")
75+
result = reader.execute_sql("SELECT * FROM my_data WHERE x > 1")
7676
assert isinstance(result, pl.DataFrame)
7777
assert result.shape == (2, 2)
7878

@@ -406,7 +406,7 @@ def test_simple_custom_reader(self):
406406
"""Custom reader with execute() method works."""
407407

408408
class SimpleReader:
409-
def execute(self, sql: str) -> pl.DataFrame:
409+
def execute_sql(self, sql: str) -> pl.DataFrame:
410410
return pl.DataFrame({"x": [1, 2, 3], "y": [10, 20, 30]})
411411

412412
reader = SimpleReader()
@@ -420,7 +420,7 @@ class RegisterReader:
420420
def __init__(self):
421421
self.tables = {}
422422

423-
def execute(self, sql: str) -> pl.DataFrame:
423+
def execute_sql(self, sql: str) -> pl.DataFrame:
424424
# Simple: just return the first registered table
425425
if self.tables:
426426
return next(iter(self.tables.values()))
@@ -442,7 +442,7 @@ def test_custom_reader_error_handling(self):
442442
"""Custom reader errors are propagated."""
443443

444444
class ErrorReader:
445-
def execute(self, sql: str) -> pl.DataFrame:
445+
def execute_sql(self, sql: str) -> pl.DataFrame:
446446
raise ValueError("Custom reader error")
447447

448448
reader = ErrorReader()
@@ -453,7 +453,7 @@ def test_custom_reader_wrong_return_type(self):
453453
"""Custom reader returning wrong type raises TypeError."""
454454

455455
class WrongTypeReader:
456-
def execute(self, sql: str):
456+
def execute_sql(self, sql: str):
457457
return {"x": [1, 2, 3]} # dict, not DataFrame
458458

459459
reader = WrongTypeReader()
@@ -472,7 +472,7 @@ def test_custom_reader_can_render(self):
472472
"""Custom reader result can be rendered to Vega-Lite."""
473473

474474
class StaticReader:
475-
def execute(self, sql: str) -> pl.DataFrame:
475+
def execute_sql(self, sql: str) -> pl.DataFrame:
476476
return pl.DataFrame(
477477
{
478478
"x": [1, 2, 3, 4, 5],
@@ -501,7 +501,7 @@ class RecordingReader:
501501
def __init__(self):
502502
self.execute_calls = []
503503

504-
def execute(self, sql: str) -> pl.DataFrame:
504+
def execute_sql(self, sql: str) -> pl.DataFrame:
505505
self.execute_calls.append(sql)
506506
return pl.DataFrame({"x": [1], "y": [2]})
507507

src/api.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ pub fn prepare(query: &str, reader: &dyn Reader) -> Result<Prepared> {
245245
let warnings: Vec<ValidationWarning> = validated.warnings().to_vec();
246246

247247
// Prepare data (this also validates, but we want the warnings from above)
248-
let prepared_data = prepare_data_with_executor(query, |sql| reader.execute(sql))?;
248+
let prepared_data = prepare_data_with_executor(query, |sql| reader.execute_sql(sql))?;
249249

250250
Ok(Prepared::new(
251251
prepared_data.spec,

src/cli.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ fn print_table_fallback(query: &str, reader: &DuckDBReader, max_rows: usize) {
335335
}
336336
let parsed = parsed.unwrap();
337337

338-
let data = reader.execute(&parsed);
338+
let data = reader.execute_sql(&parsed);
339339
if let Err(e) = data {
340340
eprintln!("Failed to execute SQL query: {}", e);
341341
std::process::exit(1)

src/doc/API.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ pub struct Location {
374374
```rust
375375
pub trait Reader {
376376
/// Execute a SQL query and return a DataFrame
377-
fn execute(&self, sql: &str) -> Result<DataFrame>;
377+
fn execute_sql(&self, sql: &str) -> Result<DataFrame>;
378378

379379
/// Register a DataFrame as a queryable table
380380
fn register(&mut self, name: &str, df: DataFrame) -> Result<()>;
@@ -425,7 +425,7 @@ class DuckDBReader:
425425
df: Polars DataFrame or narwhals-compatible DataFrame
426426
"""
427427

428-
def execute(self, sql: str) -> polars.DataFrame:
428+
def execute_sql(self, sql: str) -> polars.DataFrame:
429429
"""Execute SQL and return a Polars DataFrame."""
430430

431431
def supports_register(self) -> bool:

src/execute.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1185,7 +1185,7 @@ where
11851185
/// Convenience wrapper around `prepare_data_with_executor` for direct DuckDB reader usage.
11861186
#[cfg(feature = "duckdb")]
11871187
pub fn prepare_data(query: &str, reader: &DuckDBReader) -> Result<PreparedData> {
1188-
prepare_data_with_executor(query, |sql| reader.execute(sql))
1188+
prepare_data_with_executor(query, |sql| reader.execute_sql(sql))
11891189
}
11901190

11911191
#[cfg(test)]

src/lib.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ mod integration_tests {
116116
FROM generate_series(0, 4) as t(n)
117117
"#;
118118

119-
let df = reader.execute(sql).unwrap();
119+
let df = reader.execute_sql(sql).unwrap();
120120

121121
// Verify DataFrame has temporal type (DuckDB returns Datetime for DATE + INTERVAL)
122122
assert_eq!(df.get_column_names(), vec!["date", "revenue"]);
@@ -176,7 +176,7 @@ mod integration_tests {
176176
FROM generate_series(0, 3) as t(n)
177177
"#;
178178

179-
let df = reader.execute(sql).unwrap();
179+
let df = reader.execute_sql(sql).unwrap();
180180

181181
// Verify DataFrame has Datetime type
182182
let timestamp_col = df.column("timestamp").unwrap();
@@ -224,7 +224,7 @@ mod integration_tests {
224224

225225
// Real SQL that users would write
226226
let sql = "SELECT 1 as int_col, 2.5 as float_col, true as bool_col";
227-
let df = reader.execute(sql).unwrap();
227+
let df = reader.execute_sql(sql).unwrap();
228228

229229
// Verify types are preserved
230230
// DuckDB treats numeric literals as DECIMAL, which we convert to Float64
@@ -279,7 +279,7 @@ mod integration_tests {
279279
let reader = DuckDBReader::from_connection_string("duckdb://memory").unwrap();
280280

281281
let sql = "SELECT * FROM (VALUES (1, 2.5, 'a'), (2, NULL, 'b'), (NULL, 3.5, NULL)) AS t(int_col, float_col, str_col)";
282-
let df = reader.execute(sql).unwrap();
282+
let df = reader.execute_sql(sql).unwrap();
283283

284284
// Verify types
285285
assert!(matches!(
@@ -329,7 +329,7 @@ mod integration_tests {
329329
let reader = DuckDBReader::from_connection_string("duckdb://memory").unwrap();
330330

331331
let sql = "SELECT * FROM (VALUES ('A', 10), ('B', 20), ('A', 15), ('C', 30)) AS t(category, value)";
332-
let df = reader.execute(sql).unwrap();
332+
let df = reader.execute_sql(sql).unwrap();
333333

334334
let mut spec = Plot::new();
335335
let layer = Layer::new(Geom::bar())
@@ -375,7 +375,7 @@ mod integration_tests {
375375
GROUP BY day
376376
"#;
377377

378-
let df = reader.execute(sql).unwrap();
378+
let df = reader.execute_sql(sql).unwrap();
379379

380380
// Verify temporal type is preserved through aggregation
381381
// DATE_TRUNC returns Date type (not Datetime)
@@ -413,7 +413,7 @@ mod integration_tests {
413413
let reader = DuckDBReader::from_connection_string("duckdb://memory").unwrap();
414414

415415
let sql = "SELECT 0.1 as small, 123.456 as medium, 999999.999999 as large";
416-
let df = reader.execute(sql).unwrap();
416+
let df = reader.execute_sql(sql).unwrap();
417417

418418
// All should be Float64
419419
assert!(matches!(
@@ -465,7 +465,7 @@ mod integration_tests {
465465
let reader = DuckDBReader::from_connection_string("duckdb://memory").unwrap();
466466

467467
let sql = "SELECT CAST(1 AS TINYINT) as tiny, CAST(1000 AS SMALLINT) as small, CAST(1000000 AS INTEGER) as int, CAST(1000000000000 AS BIGINT) as big";
468-
let df = reader.execute(sql).unwrap();
468+
let df = reader.execute_sql(sql).unwrap();
469469

470470
// Verify types
471471
assert!(matches!(
@@ -533,7 +533,7 @@ mod integration_tests {
533533

534534
// Prepare data - this parses, injects constants into global data, and replaces literals with columns
535535
let prepared =
536-
execute::prepare_data_with_executor(query, |sql| reader.execute(sql)).unwrap();
536+
execute::prepare_data_with_executor(query, |sql| reader.execute_sql(sql)).unwrap();
537537

538538
// Verify constants were injected into global data (not layer-specific data)
539539
// Both layers share __global__ data for faceting compatibility
@@ -641,7 +641,7 @@ mod integration_tests {
641641
"#;
642642

643643
let prepared =
644-
execute::prepare_data_with_executor(query, |sql| reader.execute(sql)).unwrap();
644+
execute::prepare_data_with_executor(query, |sql| reader.execute_sql(sql)).unwrap();
645645

646646
// All layers should use global data for faceting to work
647647
assert!(
@@ -729,7 +729,7 @@ mod integration_tests {
729729
"#;
730730

731731
let prepared =
732-
execute::prepare_data_with_executor(query, |sql| reader.execute(sql)).unwrap();
732+
execute::prepare_data_with_executor(query, |sql| reader.execute_sql(sql)).unwrap();
733733

734734
// Should have global data with the constant injected
735735
assert!(

0 commit comments

Comments
 (0)