---
title: "HeliosDB Nano v3.13.0 Release Notes"
---

# HeliosDB Nano v3.13.0 Release Notes

**Theme:** PostgreSQL-compatible BM25 full-text search, surfaced through SQL

---

## Highlights

BM25 has been in the engine since v3.11 (`search::Bm25Index`) but unreachable from SQL. v3.13.0 lights up the full PostgreSQL FTS surface — `tsvector`, `tsquery`, `@@`, `ts_rank_cd`, `to_tsvector`, `plainto_tsquery`, `phraseto_tsquery`, plus `CREATE INDEX … USING gin` for ORM/migration compatibility.

Net effect: existing PG-FTS code paths and migration scripts compile and run. EasyRAG (`foor.network/easyrag`) was client-side reranking with `rank_bm25.BM25Okapi`; that workaround can now be deleted.

---

## What's New

### Scalar FTS Functions

```sql
-- Tokenise text into a tsvector
SELECT to_tsvector('PostgreSQL embedded database with vectors');

-- Build a query
SELECT to_tsquery('postgresql & embedded');
SELECT plainto_tsquery('PostgreSQL embedded');         -- plain English
SELECT phraseto_tsquery('embedded database');           -- phrase form

-- Rank
SELECT title, ts_rank_cd(to_tsvector(body), to_tsquery('helios')) AS rank
FROM articles
WHERE to_tsvector(body) @@ to_tsquery('helios')
ORDER BY rank DESC LIMIT 10;
```

All round-trip as `Value::Json` (array of normalised tokens) so they flow through PG wire protocol unchanged and render as JSON arrays for introspection.

### `@@` Operator

`tsvector @@ tsquery → boolean`. New `BinaryOperator::TsMatch` in the logical plan, wired in the planner from `SqlBinaryOp::AtAt` and evaluated via the shared `search::tokenizer` + in-memory match.

### `TSVECTOR` / `TSQUERY` Column Types

Accepted in `CREATE TABLE`. Stored internally as `DataType::Json`.

```sql
CREATE TABLE articles (
    id SERIAL PRIMARY KEY,
    body TEXT,
    body_tsv TSVECTOR
);
```

### `CREATE INDEX … USING gin | gist (col)`

Accepted as DDL for ORM/migration compatibility. The index itself is a no-op currently — `@@` still walks rows in the evaluator — but the syntax round-trips cleanly so Django, SQLAlchemy, and hand-written migrations load without errors.

### Hybrid Search (FTS + Vector)

Combine BM25 and vector similarity in one query:

```sql
SELECT id, text,
       0.7 * (1.0 - (embedding <=> $1::vector))
     + 0.3 * ts_rank_cd(to_tsvector(text), plainto_tsquery($2)) AS score
FROM chunks
ORDER BY score DESC
LIMIT 10;
```

---

## Fixed

- **Stale version strings** — `pg_catalog.version()`, the `server_version` parameter-status message, and the `SHOW server_version` response all now use `env!("CARGO_PKG_VERSION")` instead of hardcoded `3.7.0` / `3.10.0` / `17.0 (HeliosDB Nano 2.0)` strings that had drifted across releases.

---

## Documentation

- `docs/compatibility/fts.md` — honest scope: token match, BM25 rank, JSON-encoded tsvector ✓; stemming, phrase queries, `setweight()`, persistent GIN ✗.
- `tests/fts_tests.rs` — 8 regression cases (tsvector construction, `@@` match/miss, rank, GIN DDL, NULL propagation, version-string drift).

---

## Migration

No breaking changes. Existing `to_tsvector` / `@@` code paths from prior PG-FTS deployments work as-is. No schema migration required — `tsvector` columns can be added and populated in place.

---

## Known Limitations

- GIN/GIST indexes are accepted DDL but are no-ops; `@@` walks rows. Persistent FTS index lands in a follow-up.
- Stemming and full phrase-query semantics are out of scope for v3.13.

---

## Compatibility Matrix

| Component | Version |
|-----------|---------|
| PostgreSQL wire | 14, 15, 16 |
| MySQL wire | 5.7, 8.0 |
| MCP protocol | 1.0 |
