datafusion-query-builder
A programmatic, injection-safe builder for DataFusion SQL — a typed Rust core with a pyo3-exposed Python API. It replaces hand-rolled f-string / template-literal SQL with a typed, composable surface, while still emitting SQL text (so the SQL stays visible in logs/traces, greppable, and cache-keyable).
Values are escaped by construction, so untrusted input (column values, user filters) is safe to
embed. Strings, arrays, and numbers are quoted/encoded for you; an explicit raw(...) escape hatch
is the only unescaped path.
Install
pip install datafusion-query-builder
Prebuilt abi3 wheels are published for CPython 3.9+ on macOS (Apple Silicon + Intel) and Linux
(x86_64 + aarch64).
Quick start (Python)
from datafusion_query_builder import col, lit, param, raw, when, and_, table
from datafusion_query_builder import functions as f
q = (
table("records")
.filter((col("kind") == "span") & col("deployment_environment").is_in(["prod", "staging"]))
.select(
f.coalesce(col("service_name"), "(unknown)").alias("service"),
f.approx_distinct(col("trace_id")).alias("request_count"),
f.approx_percentile_cont(col("duration"), 0.95).alias("p95"),
)
.group_by(col("service_name"))
.order_by(col("request_count").desc())
.limit(200)
)
print(q.to_sql())
Bare Python scalars auto-promote to literals (so col("x") == "prod" works), and string/array
literals are escaped — values are injection-safe by construction. Reach for raw(...) (a SQL
fragment), f.call("name", ...) (any function), or param("name") (a ${name} placeholder) when
you step outside the v1 grammar.
A raw(...) fragment must be one complete SQL expression. The builder parses it on its own, drops
any comments, and adds brackets where its top-level operator binds looser than the surrounding
one, as it does for native expressions. Pass a user-written predicate as raw(predicate), not
raw(f"({predicate})"). Text wrapping breaks on a trailing -- comment, and a predicate such as
1=1) OR (1=1 can close the bracket.
The JSONB key-exists operators are first-class: col("attributes").has_key("gen_ai.input.messages")
renders attributes ? 'gen_ai.input.messages' — a cheap presence check that never extracts the
value (contrast raw("attributes ->> 'k'").is_not_null(), which reads the whole value out just to
test it). has_any_key and has_all_keys render ?| / ?&.
CTEs default to leaving materialization up to the engine. Use
table("chosen").with_cte("chosen", source, materialized=True) to emit
AS MATERIALIZED, or materialized=False to emit AS NOT MATERIALIZED.
Omitting the keyword (or passing None) preserves plain AS (...) SQL.
These directives require engine support; rendering them does not guarantee that
an engine honors them. Rust callers can use with_cte_materialization(name, source, Some(true));
the existing two-argument with_cte method is unchanged.
Architecture
façade types ──lower.rs──▶ sqlparser::ast ──Display──▶ SQL text
expr.rs / query.rs / functions.rs (the only file that names sqlparser::ast)
expr.rs,query.rs,functions.rs— span-free,Default-friendly façade enums. Immutable / generative: every method returns a new value.lower.rs— the single boundary tosqlparser::ast. Asqlparserversion bump surfaces here and nowhere else.render.rs—to_sql()plusvalidate()(renders then re-parses to prove well-formedness).python.rs—Expr/Querywrappers, thef.*functions namespace, operator overloading with scalar→literal coercion. Gated behind thepythonfeature.
sqlparser is pinned to the pydantic dollar-brace-0.62.0 fork via [patch.crates-io] — the same
parser the DataFusion ecosystem uses, including the ${var} placeholder extension. The crate does
not depend on DataFusion itself (only the test oracle does, optionally).
Develop & test
# Rust core (no Python toolchain needed):
cargo test --test core # rendering snapshots + regressions
cargo test --features datafusion-oracle --test properties # property tests, see below
cargo clippy --all-targets --features datafusion-oracle -- -D warnings
# Coercion tests against a real embedded interpreter (needs PYO3_PYTHON -> a 3.9+ interpreter):
PYO3_PYTHON=$PWD/.venv/bin/python cargo test --lib --features test-embed
# Python extension:
uv venv && uvx maturin develop
python tests/test_python.py
How the tests are layered
The crate is correctness-critical (it generates SQL from user-controlled input), so the test surface is layered:
tests/properties.rs(proptest, behinddatafusion-oracle) uses DataFusion itself as the oracle — it renders a query to SQL, then plans + executes it through real DataFusion and reads the value back. This upgrades "the SQL re-parses" to "the value survives a real engine round-trip", catching silent mis-encoding (escaping, float formatting, operator precedence). DataFusion is an optional, test-only dependency — never compiled into the lib or the wheel.tests/properties.proptest-regressionspins seeds that previously found bugs.src/python.rscoercion_tests(behindtest-embed) unit-test the Python-type → façade-literal boundary that can only be exercised with real Python objects (bool-before-int, big ints, non-finite floats,list/tuple). They compose with the property tests: coercion proves "Python value → correct value", the property tests prove "value → correct SQL → correct result".
When a property/coercion test finds a bug, fix it in the crate — that is the whole point of the library: one fix covers every caller.
Release
Wheels are built and published to PyPI by CI (.github/workflows/ci.yml) on a v* tag, using
PyPI Trusted Publishing (OIDC) — no API tokens. To cut a release: bump version in
Cargo.toml and pyproject.toml, tag vX.Y.Z, and push the tag.
License
MIT
Metadata
Release files for datafusion-query-builder 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| datafusion_query_builder-0.4.0.tar.gz | 67.1 kB | With provenance | Details for datafusion_query_builder-0.4.0.tar.gz |
Built distributions (wheels)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| datafusion_query_builder-0.4.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.9 | abi3 | Linux glibc 2.17+ x86-64 | Details for datafusion_query_builder-0.4.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
| datafusion_query_builder-0.4.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl | CPython 3.9 | abi3 | Linux glibc 2.17+ ARM64 | Details for datafusion_query_builder-0.4.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
| datafusion_query_builder-0.4.0-cp39-abi3-macosx_11_0_arm64.whl | CPython 3.9 | abi3 | macOS 11.0+ ARM64 | Details for datafusion_query_builder-0.4.0-cp39-abi3-macosx_11_0_arm64.whl |
Total release size: 8.8 MB
Release files / datafusion_query_builder-0.4.0.tar.gz
| Download URL | datafusion_query_builder-0.4.0.tar.gz |
|---|---|
| Size | 67.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d4de06c4bc98be02d9d46fe2083dfa90440f599126bd06f75e1bb01b51336bb4
|
|
BLAKE2b-256 checksum How to use checksums |
862c571f41dd50c699179960fdc7887df51bb790c39cfb39b983f90651675535
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 17, 2026.
Transparency logRelease files / datafusion_query_builder-0.4.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | datafusion_query_builder-0.4.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 3.1 MB |
| Tags | CPython 3.9 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
7ddeee7e9ef3a6c2373e4bf058c695161cdcccc4b8b1755c388371f16dadd813
|
|
BLAKE2b-256 checksum How to use checksums |
8097e2b2d33731cec477ffc5e89b8c1d43fd9130d9021db8007ecbbc0dae03c5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 17, 2026.
Transparency logRelease files / datafusion_query_builder-0.4.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
| Download URL | datafusion_query_builder-0.4.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
|---|---|
| Size | 3.0 MB |
| Tags | CPython 3.9 Linux glibc 2.17+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
5db22efc03ccd478bf2fd72b72bfe124a88bf6dc3f4e8c81d055560838739edf
|
|
BLAKE2b-256 checksum How to use checksums |
b385460d0625acb448e5015da1c585f098ffaa14d4d3ad96ba7832d5ee2378e4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 17, 2026.
Transparency logRelease files / datafusion_query_builder-0.4.0-cp39-abi3-macosx_11_0_arm64.whl
| Download URL | datafusion_query_builder-0.4.0-cp39-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 2.7 MB |
| Tags | CPython 3.9 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
ca30fcac5b17454f95a86b1b6921c26a0a5cdeda88c1648be250c18279eaccf6
|
|
BLAKE2b-256 checksum How to use checksums |
6442cc68d689473495ab8cfbef0f6e38c72475935fdf82fd59413195569cbdc1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 17, 2026.
Transparency logSecurity for datafusion-query-builder 0.4.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 4 files in this release have been uploaded with provenance metadata.
Attestation for datafusion_query_builder-0.4.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 17, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.