query-forge 0.2.0

Run SQL queries on XLSX/XML/CSV/JSON/JSONL/Markdown inputs and export results as text, CSV, JSONL, Markdown, XML, or XLSX
Documentation

query-forge

Crates.io Docs.rs License: MIT

Rust CLI to run SQL queries on one or more XLSX/XML/CSV/JSON/JSONL/Markdown inputs and produce output in text, CSV, JSONL, Markdown, XML, or a new XLSX file.

Installation

From crates.io:

cargo install query-forge

From source (local development):

cargo install --path .

Quick start

Run an inline query:

qf \

  --input ./input.xlsx:Sheet1 \

  --query "SELECT * FROM table WHERE amount > 10"

Or load the query from an SQL file:

qf \

  --input ./input.xlsx \

  --query-file ./query.sql

Key features

  • SQL queries on XLSX/XML/CSV/JSON/JSONL/Markdown data using in-memory SQLite.
  • Multi-file support with automatic table mapping: table/table1, table2, table3, ...
  • Explicit table naming: name=file.xlsx assigns a custom SQL table name for readability.
  • Sheet selection with file.xlsx:SheetName or file.xlsx#SheetName.
  • For XML inputs, if no sheet/tag is provided the whole file is used; if a sheet is provided, only the subtree inside that XML tag is used.
  • CSV, JSON, JSONL and Markdown inputs are supported directly (.csv, .json, .jsonl, .md, .markdown) and can be mixed with XLSX/XML in the same query.
  • In qf query, sheet/tag/key selection is expressed via file:selector or file#selector (XLSX, XML, JSON, Markdown; for Markdown, selector is 1-based table index); CSV/JSONL do not support selector syntax.
  • Named SQL parameters from CLI with --param.
  • Output export in txt, csv, jsonl, markdown, xml, xlsx.
  • Support for headerless sheets with --no-headers (column1, column2, ...).

Examples

Multiple inputs

qf \

  --input ./consuntivo.xlsx:Consuntivo \

  --input ./wkl.xlsx:WKL \

  --query-file ./wbs-cons-and-wkl-by-month.sql \

  --param wbs=TEST_VAL

Explicit table names

Assign readable names to each input for use in SQL queries:

qf \

  --input sales=./sales.xlsx:Q1 \

  --input costs=./costs.csv \

  --query "SELECT * FROM sales JOIN costs ON sales.id = costs.id"

Without a name prefix, tables are automatically named table, table2, table3, etc.

Parameterized query

SELECT *
FROM table
WHERE "Elemento WBS" LIKE '%' || :wbs || '%'
  AND CAST("ore" AS REAL) > :min_ore;

Parameters:

--param wbs=TEST_VAL --param min_ore=8

Multiple values for the same parameter (separated by , or ;):

--param "wbs=TEST_VAL,IEV092500011.2.3"

XML input

Use the whole XML file:

qf \

  --input ./inventory.xml \

  --query "SELECT name, price FROM table WHERE active = 1 ORDER BY price DESC"

Use only a specific XML tag as sheet:

qf \

  --input ./inventory.xml:Inventory \

  --query "SELECT name, price FROM table ORDER BY price DESC"

CSV/JSON/JSONL/Markdown input

CSV:

qf \

  --input ./inventory.csv \

  --query "SELECT product, price FROM table WHERE active = 1 ORDER BY price DESC"

JSONL:

qf \

  --input ./inventory.jsonl \

  --query "SELECT product, price FROM table WHERE active = 1 ORDER BY price DESC"

JSON (array at root):

qf \

  --input ./inventory.json \

  --query "SELECT product, price FROM table WHERE active = 1 ORDER BY price DESC"

JSON with key selection as sheet:

qf \

  --input ./inventory.json:Inventory \

  --query "SELECT product, price FROM table ORDER BY price DESC"

Markdown (first table by default):

qf \

  --input ./inventory.md \

  --query "SELECT product, price FROM table WHERE active = 1 ORDER BY price DESC"

Markdown with table index key (second table):

qf \

  --input ./inventory.md:2 \

  --query "SELECT product, price FROM table"

Export

CSV:

qf \

  --input ./input.xlsx:Sheet1 \

  --query "SELECT name, amount FROM table ORDER BY amount DESC" \

  --output ./result.csv \

  --format csv

JSONL:

qf \

  --input ./input.xlsx:Sheet1 \

  --query "SELECT name, amount FROM table ORDER BY amount DESC" \

  --output ./result.jsonl \

  --format jsonl

Markdown:

qf \

  --input ./input.xlsx:Sheet1 \

  --query "SELECT name, amount FROM table ORDER BY amount DESC" \

  --output ./result.md \

  --format markdown

XML:

qf \

  --input ./input.xlsx:Sheet1 \

  --query "SELECT name, amount FROM table ORDER BY amount DESC" \

  --output ./result.xml \

  --format xml

XLSX:

qf \

  --input ./input.xlsx:Sheet1 \

  --query "SELECT name, amount FROM table" \

  --output ./result.xlsx

Ready-to-use examples

The examples/ folder contains:

  • inventory.xlsx, inventory.xml, inventory.csv, inventory.json, inventory.jsonl, inventory.md as inputs.
  • active-products.txt, active-products.csv, active-products.jsonl, active-products.md, active-products.xml, active-products-from-xml.csv, active-products-from-csv.csv, active-products-from-json.csv, active-products-from-jsonl.csv, active-products-from-markdown.csv, stock-by-category.xlsx as generated outputs.
  • commands.sh with runnable commands from the repository root.

Regenerate the examples locally:

./scripts/regenerate_examples.sh

Documentation

Comparison

query-forge is designed as a focused CLI for running SQL queries across heterogeneous local files with a uniform --input model. Nearby tools exist, but they usually cover only part of the same problem.

Tool SQL queries XLSX XML CSV JSON/JSONL Markdown tables Primary focus
query-forge Yes Yes Yes Yes Yes Yes Unified SQL CLI over heterogeneous document-style inputs
duckdb Yes Partial Partial Yes Yes No General-purpose analytical SQL engine
csvkit Partial Via conversion No Yes Limited No CSV tooling and CSV-oriented SQL workflows
qsv / xsv / miller Limited / No No No Yes Limited No Fast tabular text processing
jq No No No No Yes No JSON transformation and filtering
xmlstarlet No No Yes No No No XML querying and transformation
VisiData Partial / Interactive Yes Limited Yes Yes Limited Interactive data exploration

Notes:

  • duckdb is the closest alternative when the core requirement is "run SQL on local data files", especially for CSV and JSON, but it does not provide the same single-purpose workflow for XLSX/XML/Markdown inputs.
  • csvkit, qsv, xsv, and miller are strong tabular-data tools, but they are centered on delimited text rather than a unified multi-format SQL interface.
  • jq and xmlstarlet are powerful for JSON and XML respectively, but they use format-specific query languages instead of SQL.
  • VisiData is excellent for interactive inspection, while query-forge is oriented to batch execution and scriptable SQL queries.

License

Released under the MIT license. See LICENSE.