Context
Core infrastructure for the DuckDB file query engine epic. All other sub-issues (filtering #53, sorting #54, aggregation #55, query editor UI) depend on this.
What to build
A FileQueryEngine struct owned by the host, one instance per open file tab.
Format detection
On file open, detect whether DuckDB can read the format natively:
| Format |
DuckDB function |
| JSON / NDJSON |
read_json_auto('path') |
| CSV / TSV |
read_csv_auto('path') |
| Parquet |
read_parquet('path') |
| Arrow IPC |
read_arrow('path') |
| Excel |
st_read('path') (spatial ext) |
| Other |
fallback: get-range ingestion |
For native formats, register a view: CREATE VIEW data AS SELECT * FROM read_json_auto('/path/to/file.json'). DuckDB scans lazily — no full load upfront.
For plugin-loaded formats, bulk-pull via get-range and insert into an in-memory table. Show a progress indicator during ingestion; do this async off the UI thread.
FileQueryEngine API
pub struct FileQueryEngine { /* DuckDB connection, ingestion state */ }
impl FileQueryEngine {
pub fn open_native(path: &Path, format: NativeFormat) -> Result<Self>;
pub fn ingest_from_plugin(records: Vec<String>) -> Result<Self>;
pub fn query(&self, sql: &str) -> Result<QueryResult>;
pub fn schema(&self) -> Result<Vec<ColumnInfo>>; // for editor autocomplete
}
Changes
- Add
duckdb crate to Cargo.toml (feature flags: bundled for static linking)
src/query/engine.rs — FileQueryEngine
src/query/mod.rs — format detection, ingestion coordinator
- Host file-open path: after plugin
open(), attempt native DuckDB open; fall back to plugin ingestion
Acceptance criteria
Context
Core infrastructure for the DuckDB file query engine epic. All other sub-issues (filtering #53, sorting #54, aggregation #55, query editor UI) depend on this.
What to build
A
FileQueryEnginestruct owned by the host, one instance per open file tab.Format detection
On file open, detect whether DuckDB can read the format natively:
read_json_auto('path')read_csv_auto('path')read_parquet('path')read_arrow('path')st_read('path')(spatial ext)get-rangeingestionFor native formats, register a view:
CREATE VIEW data AS SELECT * FROM read_json_auto('/path/to/file.json'). DuckDB scans lazily — no full load upfront.For plugin-loaded formats, bulk-pull via
get-rangeand insert into an in-memory table. Show a progress indicator during ingestion; do this async off the UI thread.FileQueryEngine API
Changes
duckdbcrate toCargo.toml(feature flags:bundledfor static linking)src/query/engine.rs—FileQueryEnginesrc/query/mod.rs— format detection, ingestion coordinatoropen(), attempt native DuckDB open; fall back to plugin ingestionAcceptance criteria
get-rangeinto an in-memory table asyncquery(sql)returns typed rows (not stringified)schema()returns column names and DuckDB-inferred types