Skip to content

Commit 8746253

Browse files
committed
apply suggestions from code review
1 parent 2a8d588 commit 8746253

5 files changed

Lines changed: 69 additions & 80 deletions

File tree

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ palette = { version = "0.7", default-features = false, features = ["std", "appro
5959

6060
# Spatial
6161
geozero = { version = "0.14", default-features = false }
62-
hex = "0.4"
6362

6463
# Utilities
6564
regex = "1.10"

src/execute/mod.rs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -369,18 +369,6 @@ fn detect_geometry_column(schema: &Schema) -> Option<String> {
369369
return Some(candidates[0].name.clone());
370370
}
371371

372-
// Fall back to name-only match (e.g. extension types we don't recognise)
373-
if candidates.is_empty() {
374-
let by_name: Vec<_> = schema
375-
.iter()
376-
.filter(|c| looks_like_geometry(&c.name))
377-
.collect();
378-
379-
if by_name.len() == 1 {
380-
return Some(by_name[0].name.clone());
381-
}
382-
}
383-
384372
None
385373
}
386374

src/reader/data.rs

Lines changed: 0 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -60,66 +60,6 @@ pub fn builtin_parquet_bytes(name: &str) -> Option<&'static [u8]> {
6060
}
6161
}
6262

63-
// =============================================================================
64-
// DuckDB builtin data registration (requires duckdb + builtin-data)
65-
// =============================================================================
66-
67-
/// Register any builtin datasets referenced in the SQL with a DuckDB connection.
68-
///
69-
/// Finds `ggsql:X` patterns in the SQL, writes the embedded parquet data to
70-
/// a temp file, and creates a table named `__ggsql_data_X__` in DuckDB.
71-
#[cfg(all(feature = "duckdb", feature = "builtin-data"))]
72-
pub fn register_builtin_datasets_duckdb(
73-
sql: &str,
74-
conn: &duckdb::Connection,
75-
) -> Result<(), GgsqlError> {
76-
use std::{env, fs};
77-
78-
let dataset_names = extract_builtin_dataset_names(sql)?;
79-
80-
// Load spatial extension before registering datasets that contain
81-
// geometry columns, so DuckDB reads them as GEOMETRY rather than BLOB.
82-
if dataset_names.iter().any(|n| n == "world") {
83-
let _ = conn.execute("LOAD spatial", duckdb::params![]);
84-
}
85-
86-
for name in dataset_names {
87-
let Some(parquet_bytes) = builtin_parquet_bytes(&name) else {
88-
continue;
89-
};
90-
91-
let table_name = naming::builtin_data_table(&name);
92-
93-
// Write parquet to temp file for DuckDB's read_parquet
94-
let mut tmp_path = env::temp_dir();
95-
tmp_path.push(format!("{}.parquet", name));
96-
if !tmp_path.exists() {
97-
fs::write(&tmp_path, parquet_bytes).map_err(|e| {
98-
GgsqlError::ReaderError(format!(
99-
"Failed to write builtin dataset '{}' to {}: {}",
100-
name,
101-
tmp_path.display(),
102-
e
103-
))
104-
})?;
105-
}
106-
107-
let create_sql = format!(
108-
"CREATE TABLE IF NOT EXISTS {} AS SELECT * FROM read_parquet('{}')",
109-
naming::quote_ident(&table_name),
110-
tmp_path.display()
111-
);
112-
113-
conn.execute(&create_sql, duckdb::params![]).map_err(|e| {
114-
GgsqlError::ReaderError(format!(
115-
"Failed to register builtin dataset '{}': {}",
116-
name, e
117-
))
118-
})?;
119-
}
120-
Ok(())
121-
}
122-
12363
// =============================================================================
12464
// Arrow-based builtin data loading
12565
// =============================================================================

src/reader/duckdb.rs

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,66 @@ use std::cell::RefCell;
1313
use std::collections::HashSet;
1414
use std::sync::Arc;
1515

16+
// =============================================================================
17+
// DuckDB builtin data registration
18+
// =============================================================================
19+
20+
/// Register any builtin datasets referenced in the SQL with a DuckDB connection.
21+
///
22+
/// Finds `ggsql:X` patterns in the SQL, writes the embedded parquet data to
23+
/// a temp file, and creates a table named `__ggsql_data_X__` in DuckDB.
24+
#[cfg(feature = "builtin-data")]
25+
fn register_builtin_datasets_duckdb(
26+
sql: &str,
27+
conn: &Connection,
28+
) -> Result<()> {
29+
use std::{env, fs};
30+
31+
let dataset_names = super::data::extract_builtin_dataset_names(sql)?;
32+
33+
// Load spatial extension before registering datasets that contain
34+
// geometry columns, so DuckDB reads them as GEOMETRY rather than BLOB.
35+
if dataset_names.iter().any(|n| n == "world") {
36+
let _ = conn.execute("LOAD spatial", params![]);
37+
}
38+
39+
for name in dataset_names {
40+
let Some(parquet_bytes) = super::data::builtin_parquet_bytes(&name) else {
41+
continue;
42+
};
43+
44+
let table_name = naming::builtin_data_table(&name);
45+
46+
// Write parquet to temp file for DuckDB's read_parquet
47+
let mut tmp_path = env::temp_dir();
48+
tmp_path.push(format!("{}.parquet", name));
49+
if !tmp_path.exists() {
50+
fs::write(&tmp_path, parquet_bytes).map_err(|e| {
51+
GgsqlError::ReaderError(format!(
52+
"Failed to write builtin dataset '{}' to {}: {}",
53+
name,
54+
tmp_path.display(),
55+
e
56+
))
57+
})?;
58+
}
59+
60+
let create_sql = format!(
61+
"CREATE TABLE IF NOT EXISTS {} AS SELECT * FROM read_parquet('{}')",
62+
naming::quote_ident(&table_name),
63+
tmp_path.display()
64+
);
65+
66+
conn.execute(&create_sql, params![]).map_err(|e| {
67+
GgsqlError::ReaderError(format!(
68+
"Failed to register builtin dataset '{}': {}",
69+
name, e
70+
))
71+
})?;
72+
}
73+
Ok(())
74+
}
75+
1676
/// DuckDB SQL dialect with native function support.
1777
///
1878
/// Overrides SQL generation methods to use DuckDB-native functions
@@ -214,7 +274,7 @@ impl Reader for DuckDBReader {
214274
fn execute_sql(&self, sql: &str) -> Result<DataFrame> {
215275
// Register builtin datasets if referenced
216276
#[cfg(feature = "builtin-data")]
217-
super::data::register_builtin_datasets_duckdb(sql, &self.conn)?;
277+
register_builtin_datasets_duckdb(sql, &self.conn)?;
218278

219279
// Rewrite ggsql:name → __ggsql_data_name__ in SQL
220280
let sql = super::data::rewrite_namespaced_sql(sql)?;

src/writer/vegalite/layer.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2220,8 +2220,6 @@ impl GeomRenderer for SpatialRenderer {
22202220
let mut feature = serde_json::Map::new();
22212221
feature.insert("type".to_string(), json!("Feature"));
22222222

2223-
let mut properties = serde_json::Map::new();
2224-
22252223
for col_name in &col_names {
22262224
let col = df.column(col_name).map_err(|e| {
22272225
GgsqlError::WriterError(format!(
@@ -2233,14 +2231,18 @@ impl GeomRenderer for SpatialRenderer {
22332231
if *col_name == geometry_col {
22342232
let geom = Self::parse_geometry_from_array(col, row_idx)?;
22352233
feature.insert("geometry".to_string(), geom);
2236-
} else {
2234+
} else if !matches!(
2235+
// These are reserved names for the geojson format, so
2236+
// we shouldn't be inserting columns with that name.
2237+
// Our naming module should prevent such collisions,
2238+
// so this is purely defensive.
2239+
col_name.as_str(),
2240+
"type" | "geometry" | "properties" | "bbox" | "id"
2241+
) {
22372242
let value = super::data::series_value_at(col, row_idx)?;
2238-
properties.insert(col_name.clone(), value.clone());
22392243
feature.insert(col_name.clone(), value);
22402244
}
22412245
}
2242-
2243-
feature.insert("properties".to_string(), Value::Object(properties));
22442246
features.push(Value::Object(feature));
22452247
}
22462248

0 commit comments

Comments
 (0)