Skip to content

Commit 7eaab8e

Browse files
committed
Move validation to validate.rs
1 parent f652acc commit 7eaab8e

5 files changed

Lines changed: 155 additions & 165 deletions

File tree

ggsql-python/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use pyo3::prelude::*;
66
use pyo3::types::{PyBytes, PyDict, PyList};
77
use std::io::Cursor;
88

9-
use ggsql::api::{validate as rust_validate, ValidationWarning};
9+
use ggsql::validate::{validate as rust_validate, ValidationWarning};
1010
use ggsql::reader::Spec;
1111
use ggsql::reader::{DuckDBReader as RustDuckDBReader, Reader};
1212
use ggsql::writer::VegaLiteWriter as RustVegaLiteWriter;

src/lib.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,15 @@ pub mod writer;
4646
#[cfg(feature = "duckdb")]
4747
pub mod execute;
4848

49-
pub mod api;
49+
pub mod validate;
5050

5151
// Re-export key types for convenience
5252
pub use plot::{
5353
AestheticValue, DataSource, Facet, Geom, Layer, Mappings, Plot, Scale, SqlExpression,
5454
};
5555

56-
// Re-export API types and functions
57-
pub use api::{validate, Location, Validated, ValidationError, ValidationWarning};
56+
// Re-export validation types and functions
57+
pub use validate::{validate, Location, Validated, ValidationError, ValidationWarning};
5858

5959
// Re-export reader types
6060
pub use reader::{Metadata, Spec};
@@ -779,4 +779,5 @@ mod integration_tests {
779779
assert_eq!(data["__ggsql_const_stroke_0__"], "value");
780780
assert_eq!(data["__ggsql_const_stroke_1__"], "value");
781781
}
782+
782783
}

src/reader/mod.rs

Lines changed: 145 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
3434
use std::collections::HashMap;
3535

36-
use crate::api::{validate, ValidationWarning};
36+
use crate::validate::{validate, ValidationWarning};
3737
use crate::execute::prepare_data_with_executor;
3838
use crate::plot::Plot;
3939
use crate::{DataFrame, GgsqlError, Result};
@@ -208,3 +208,147 @@ pub trait Reader {
208208
))
209209
}
210210
}
211+
212+
#[cfg(test)]
213+
#[cfg(all(feature = "duckdb", feature = "vegalite"))]
214+
mod tests {
215+
use super::*;
216+
use crate::writer::VegaLiteWriter;
217+
218+
#[test]
219+
fn test_execute_and_render() {
220+
let reader = DuckDBReader::from_connection_string("duckdb://memory").unwrap();
221+
let spec = reader
222+
.execute("SELECT 1 as x, 2 as y VISUALISE x, y DRAW point")
223+
.unwrap();
224+
225+
assert_eq!(spec.plot().layers.len(), 1);
226+
assert_eq!(spec.metadata().layer_count, 1);
227+
assert!(spec.data().is_some());
228+
229+
let writer = VegaLiteWriter::new();
230+
let result = spec.render(&writer).unwrap();
231+
assert!(result.contains("point"));
232+
}
233+
234+
#[test]
235+
fn test_execute_metadata() {
236+
let reader = DuckDBReader::from_connection_string("duckdb://memory").unwrap();
237+
let spec = reader
238+
.execute(
239+
"SELECT * FROM (VALUES (1, 10), (2, 20), (3, 30)) AS t(x, y) VISUALISE x, y DRAW point",
240+
)
241+
.unwrap();
242+
243+
let metadata = spec.metadata();
244+
assert_eq!(metadata.rows, 3);
245+
assert_eq!(metadata.columns.len(), 2);
246+
assert!(metadata.columns.contains(&"x".to_string()));
247+
assert!(metadata.columns.contains(&"y".to_string()));
248+
assert_eq!(metadata.layer_count, 1);
249+
}
250+
251+
#[test]
252+
fn test_execute_with_cte() {
253+
let reader = DuckDBReader::from_connection_string("duckdb://memory").unwrap();
254+
let query = r#"
255+
WITH data AS (
256+
SELECT * FROM (VALUES (1, 10), (2, 20)) AS t(x, y)
257+
)
258+
SELECT * FROM data
259+
VISUALISE x, y DRAW point
260+
"#;
261+
262+
let spec = reader.execute(query).unwrap();
263+
264+
assert_eq!(spec.plot().layers.len(), 1);
265+
assert!(spec.data().is_some());
266+
let df = spec.data().unwrap();
267+
assert_eq!(df.height(), 2);
268+
}
269+
270+
#[test]
271+
fn test_render_multi_layer() {
272+
let reader = DuckDBReader::from_connection_string("duckdb://memory").unwrap();
273+
let query = r#"
274+
SELECT * FROM (VALUES (1, 10), (2, 20), (3, 30)) AS t(x, y)
275+
VISUALISE
276+
DRAW point MAPPING x AS x, y AS y
277+
DRAW line MAPPING x AS x, y AS y
278+
"#;
279+
280+
let spec = reader.execute(query).unwrap();
281+
let writer = VegaLiteWriter::new();
282+
let result = spec.render(&writer).unwrap();
283+
284+
assert!(result.contains("layer"));
285+
}
286+
287+
#[test]
288+
fn test_register_and_query() {
289+
use polars::prelude::*;
290+
291+
let mut reader = DuckDBReader::from_connection_string("duckdb://memory").unwrap();
292+
293+
let df = df! {
294+
"x" => [1i32, 2, 3],
295+
"y" => [10i32, 20, 30],
296+
}
297+
.unwrap();
298+
299+
reader.register("my_data", df).unwrap();
300+
301+
let query = "SELECT * FROM my_data VISUALISE x, y DRAW point";
302+
let spec = reader.execute(query).unwrap();
303+
304+
assert_eq!(spec.metadata().rows, 3);
305+
assert!(spec.metadata().columns.contains(&"x".to_string()));
306+
307+
let writer = VegaLiteWriter::new();
308+
let result = spec.render(&writer).unwrap();
309+
assert!(result.contains("point"));
310+
}
311+
312+
#[test]
313+
fn test_register_and_join() {
314+
use polars::prelude::*;
315+
316+
let mut reader = DuckDBReader::from_connection_string("duckdb://memory").unwrap();
317+
318+
let sales = df! {
319+
"id" => [1i32, 2, 3],
320+
"amount" => [100i32, 200, 300],
321+
"product_id" => [1i32, 1, 2],
322+
}
323+
.unwrap();
324+
325+
let products = df! {
326+
"id" => [1i32, 2],
327+
"name" => ["Widget", "Gadget"],
328+
}
329+
.unwrap();
330+
331+
reader.register("sales", sales).unwrap();
332+
reader.register("products", products).unwrap();
333+
334+
let query = r#"
335+
SELECT s.id, s.amount, p.name
336+
FROM sales s
337+
JOIN products p ON s.product_id = p.id
338+
VISUALISE id AS x, amount AS y
339+
DRAW bar
340+
"#;
341+
342+
let spec = reader.execute(query).unwrap();
343+
assert_eq!(spec.metadata().rows, 3);
344+
}
345+
346+
#[test]
347+
fn test_execute_no_viz_fails() {
348+
let reader = DuckDBReader::from_connection_string("duckdb://memory").unwrap();
349+
let query = "SELECT 1 as x, 2 as y";
350+
351+
let result = reader.execute(query);
352+
assert!(result.is_err());
353+
}
354+
}

src/reader/spec.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use std::collections::HashMap;
44

5-
use crate::api::ValidationWarning;
5+
use crate::validate::ValidationWarning;
66
use crate::naming;
77
use crate::plot::Plot;
88
use crate::writer::Writer;

src/api.rs renamed to src/validate.rs

Lines changed: 4 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
//! High-level ggsql API.
1+
//! Query validation without SQL execution.
22
//!
3-
//! Validation and query inspection without SQL execution.
3+
//! This module provides query syntax and semantic validation without executing
4+
//! any SQL. Use this for IDE integration, syntax checking, and query inspection.
45
56
use crate::parser;
67
use crate::Result;
@@ -79,7 +80,7 @@ pub struct Location {
7980
}
8081

8182
// ============================================================================
82-
// High-Level API Functions
83+
// Validation Function
8384
// ============================================================================
8485

8586
/// Validate query syntax and semantics without executing SQL.
@@ -249,162 +250,6 @@ mod tests {
249250
assert!(!validated.errors().is_empty());
250251
}
251252

252-
#[cfg(all(feature = "duckdb", feature = "vegalite"))]
253-
#[test]
254-
fn test_execute_and_render() {
255-
use crate::reader::{DuckDBReader, Reader};
256-
use crate::writer::VegaLiteWriter;
257-
258-
let reader = DuckDBReader::from_connection_string("duckdb://memory").unwrap();
259-
let spec = reader.execute("SELECT 1 as x, 2 as y VISUALISE x, y DRAW point").unwrap();
260-
261-
assert_eq!(spec.plot().layers.len(), 1);
262-
assert_eq!(spec.metadata().layer_count, 1);
263-
assert!(spec.data().is_some());
264-
265-
let writer = VegaLiteWriter::new();
266-
let result = spec.render(&writer).unwrap();
267-
assert!(result.contains("point"));
268-
}
269-
270-
#[cfg(all(feature = "duckdb", feature = "vegalite"))]
271-
#[test]
272-
fn test_execute_metadata() {
273-
use crate::reader::{DuckDBReader, Reader};
274-
275-
let reader = DuckDBReader::from_connection_string("duckdb://memory").unwrap();
276-
let spec = reader.execute(
277-
"SELECT * FROM (VALUES (1, 10), (2, 20), (3, 30)) AS t(x, y) VISUALISE x, y DRAW point",
278-
)
279-
.unwrap();
280-
281-
let metadata = spec.metadata();
282-
assert_eq!(metadata.rows, 3);
283-
assert_eq!(metadata.columns.len(), 2);
284-
assert!(metadata.columns.contains(&"x".to_string()));
285-
assert!(metadata.columns.contains(&"y".to_string()));
286-
assert_eq!(metadata.layer_count, 1);
287-
}
288-
289-
#[cfg(all(feature = "duckdb", feature = "vegalite"))]
290-
#[test]
291-
fn test_execute_with_cte() {
292-
use crate::reader::{DuckDBReader, Reader};
293-
294-
let reader = DuckDBReader::from_connection_string("duckdb://memory").unwrap();
295-
let query = r#"
296-
WITH data AS (
297-
SELECT * FROM (VALUES (1, 10), (2, 20)) AS t(x, y)
298-
)
299-
SELECT * FROM data
300-
VISUALISE x, y DRAW point
301-
"#;
302-
303-
let spec = reader.execute(query).unwrap();
304-
305-
assert_eq!(spec.plot().layers.len(), 1);
306-
assert!(spec.data().is_some());
307-
let df = spec.data().unwrap();
308-
assert_eq!(df.height(), 2);
309-
}
310-
311-
#[cfg(all(feature = "duckdb", feature = "vegalite"))]
312-
#[test]
313-
fn test_render_multi_layer() {
314-
use crate::reader::{DuckDBReader, Reader};
315-
use crate::writer::VegaLiteWriter;
316-
317-
let reader = DuckDBReader::from_connection_string("duckdb://memory").unwrap();
318-
let query = r#"
319-
SELECT * FROM (VALUES (1, 10), (2, 20), (3, 30)) AS t(x, y)
320-
VISUALISE
321-
DRAW point MAPPING x AS x, y AS y
322-
DRAW line MAPPING x AS x, y AS y
323-
"#;
324-
325-
let spec = reader.execute(query).unwrap();
326-
let writer = VegaLiteWriter::new();
327-
let result = spec.render(&writer).unwrap();
328-
329-
assert!(result.contains("layer"));
330-
}
331-
332-
#[cfg(all(feature = "duckdb", feature = "vegalite"))]
333-
#[test]
334-
fn test_register_and_query() {
335-
use crate::reader::{DuckDBReader, Reader};
336-
use crate::writer::VegaLiteWriter;
337-
use polars::prelude::*;
338-
339-
let mut reader = DuckDBReader::from_connection_string("duckdb://memory").unwrap();
340-
341-
let df = df! {
342-
"x" => [1i32, 2, 3],
343-
"y" => [10i32, 20, 30],
344-
}
345-
.unwrap();
346-
347-
reader.register("my_data", df).unwrap();
348-
349-
let query = "SELECT * FROM my_data VISUALISE x, y DRAW point";
350-
let spec = reader.execute(query).unwrap();
351-
352-
assert_eq!(spec.metadata().rows, 3);
353-
assert!(spec.metadata().columns.contains(&"x".to_string()));
354-
355-
let writer = VegaLiteWriter::new();
356-
let result = spec.render(&writer).unwrap();
357-
assert!(result.contains("point"));
358-
}
359-
360-
#[cfg(all(feature = "duckdb", feature = "vegalite"))]
361-
#[test]
362-
fn test_register_and_join() {
363-
use crate::reader::{DuckDBReader, Reader};
364-
use polars::prelude::*;
365-
366-
let mut reader = DuckDBReader::from_connection_string("duckdb://memory").unwrap();
367-
368-
let sales = df! {
369-
"id" => [1i32, 2, 3],
370-
"amount" => [100i32, 200, 300],
371-
"product_id" => [1i32, 1, 2],
372-
}
373-
.unwrap();
374-
375-
let products = df! {
376-
"id" => [1i32, 2],
377-
"name" => ["Widget", "Gadget"],
378-
}
379-
.unwrap();
380-
381-
reader.register("sales", sales).unwrap();
382-
reader.register("products", products).unwrap();
383-
384-
let query = r#"
385-
SELECT s.id, s.amount, p.name
386-
FROM sales s
387-
JOIN products p ON s.product_id = p.id
388-
VISUALISE id AS x, amount AS y
389-
DRAW bar
390-
"#;
391-
392-
let spec = reader.execute(query).unwrap();
393-
assert_eq!(spec.metadata().rows, 3);
394-
}
395-
396-
#[cfg(feature = "duckdb")]
397-
#[test]
398-
fn test_execute_no_viz_fails() {
399-
use crate::reader::{DuckDBReader, Reader};
400-
401-
let reader = DuckDBReader::from_connection_string("duckdb://memory").unwrap();
402-
let query = "SELECT 1 as x, 2 as y";
403-
404-
let result = reader.execute(query);
405-
assert!(result.is_err());
406-
}
407-
408253
#[test]
409254
fn test_validate_sql_and_visual_content() {
410255
let query = "SELECT 1 as x, 2 as y VISUALISE DRAW point MAPPING x AS x, y AS y DRAW line MAPPING x AS x, y AS y";

0 commit comments

Comments
 (0)