# Release Notes
---
## v0.7.1
### Bug Fixes
- **Python: declare `pyarrow` as a runtime dependency** ([#2](https://github.com/bintocher/qvdrs/issues/2))
- `pip install qvdrs` now auto-installs `pyarrow` — previously users had to discover the requirement after hitting `ModuleNotFoundError: No module named 'pyarrow'` on calls like `register_duckdb()`, `read_qvd_to_arrow()`, `read_qvd_to_pandas()`, `read_qvd_to_polars()`, etc.
- **Affected functions** (now work out of the box):
- `register_duckdb`, `register_duckdb_filtered`, `register_duckdb_folder`
- `read_qvd_to_arrow`, `read_qvd_to_pandas`, `read_qvd_to_polars`
- `QvdTable.to_arrow`, `QvdTable.from_arrow`, `QvdTable.to_pandas`, `QvdTable.to_polars`
- `write_arrow`
### New Install Extras
```bash
pip install qvdrs # core + Arrow (pyarrow auto-installed)
pip install "qvdrs[pandas]" # + pandas
pip install "qvdrs[polars]" # + polars
pip install "qvdrs[duckdb]" # + duckdb
pip install "qvdrs[all]" # everything
```
### CI
- Added end-to-end Python smoke test that installs the built wheel into a clean venv and calls `register_duckdb()` against a real QVD file — this regression class is now caught before publish.
### Migration
No breaking changes. Existing code continues to work without modification.
---
## v0.7.0
### New Features
- **Node.js / TypeScript bindings** via napi-rs — native Rust performance in JavaScript. All I/O operations are async (run on libuv thread pool, never block the event loop). Sync variants available for scripts/CLI.
- `readQvd` / `readQvdSync` — read QVD files
- `saveQvd` / `saveQvdSync` — write QVD files
- `JsQvdTable` — full table API (get, filter, head, toJson, symbols, normalize)
- `JsExistsIndex` — O(1) EXISTS() lookups
- `readQvdFiltered` — streaming filtered reads
- `concatenateQvd` / `concatenatePkQvd` — file-level merge operations
- Requires **Node.js 22+**
- **npm publishing** — CI/CD workflow for automated npm releases. Platform-specific native binaries for Windows x64, Linux x64/arm64, macOS x64/arm64.
### Platforms
| `qvdrs` | Main package (auto-selects binary) |
| `qvdrs-win32-x64-msvc` | Windows x64 |
| `qvdrs-linux-x64-gnu` | Linux x64 |
| `qvdrs-linux-arm64-gnu` | Linux arm64 |
| `qvdrs-darwin-x64` | macOS Intel |
| `qvdrs-darwin-arm64` | macOS Apple Silicon |
### Migration
No breaking changes. All new features are purely additive.
---
## v0.6.2
- Fix: abi3 minimum lowered from py312 to py39 — wheels now work on **Python 3.9+** (3.10, 3.11, 3.12, 3.13, 3.14)
- v0.6.1 fixed CI to build abi3 wheels but still required Python >= 3.12; this release fixes that
## v0.6.1
- Fix: PyPI wheels now use abi3 stable ABI (single wheel per platform for all Python versions)
- Previously wheels were tagged cp313-only, causing install failures on other Python versions
## v0.6.0
### New Features
- **`write_arrow`** — write PyArrow RecordBatch or Table directly to QVD in a single call. No Parquet roundtrip needed when working with DuckDB, Arrow, or any PyArrow-compatible source. Handles `combine_chunks` internally for multi-chunk Tables.
- **`concatenate` (pure append)** — merge two QVD tables with Qlik CONCATENATE semantics. Columns are matched by name. Available as a Rust function, Python method (`QvdTable.concatenate()`), and top-level Python function (`qvd.concatenate_qvd()`).
- **`concatenate_with_pk` (PK-based upsert/dedup)** — merge with primary key deduplication. **First QVD library in any language with PK-based merge.** Supports composite keys, three conflict strategies (`replace` / `skip` / `error`), and matches Qlik `CONCATENATE + WHERE NOT EXISTS(pk)` semantics.
- **`SchemaMode`** — schema validation for concatenation: `strict` (default, error on column mismatch) or `union` (fill missing columns with NULL).
- **Python bindings** for all new functions: `write_arrow`, `concatenate`, `concatenate_pk`, `concatenate_qvd`, `concatenate_pk_qvd`.
### Testing
- 10 Rust tests + 90 Python tests passing.
### Migration
No breaking changes. All new features are purely additive.
---
## v0.5.0
- **Qlik Sense-compatible QVD output** — binary-identical to Qlik. Generated QVD files are now byte-for-byte identical to files produced by Qlik Sense, ensuring full compatibility.
---
## v0.4.4
- **Native DuckDB integration** — register QVD files as SQL-queryable DuckDB tables with `register_duckdb()`. One call to register, then query with standard SQL.
---
## v0.4.3
- **DuckDB native integration extensions** — added `register_duckdb_folder()` to bulk-register entire directories of QVD files as DuckDB tables. Supports recursive scanning, glob patterns, and file size limits.
- **Python bindings for streaming EXISTS filter** — `read_qvd_filtered()` and `register_duckdb_filtered()` now available from Python. Stream-reads only matching rows for large files.
---
## v0.4.2
- README updates with correct version numbers and `uvx` instructions.
- Crate publish fixes for crates.io.
---
## v0.4.1
- Fix README examples and update CI/CD to Node.js 24.
- Update GitHub Actions to Node.js 24 compatible versions (v5/v6).
- Remove PyQvd comparison from benchmarks.
---
## v0.4.0
- **Streaming EXISTS() filter** — 2.5x faster than Qlik Sense for filtered reads. `ExistsIndex` provides O(1) hash-based lookups matching Qlik's `EXISTS()` function.
- Column selection support in streaming reads.
---
## v0.3.0
- **Fix Qlik Sense incompatibility** — generated QVD files are now readable by Qlik Sense. Fixed critical bug where XML parser picked field-level Offset instead of table-level Offset.
---
## v0.2.0
- **DataFusion SQL engine integration** for server-side SQL queries on QVD data.
- **PyArrow / pandas / Polars conversion** — `to_arrow()`, `to_pandas()`, `to_polars()`, `from_arrow()`.
- **DuckDB integration** via Arrow bridge.
---
## v0.1.1
- Fix QVD to Parquet/Arrow index out of bounds panic.
---
## v0.1.0
- **Initial release** — QVD file reader/writer library.
- Parquet/Arrow conversion, streaming reader, CLI tool.
- CI/CD pipeline for PyPI and crates.io publishing.