Skip to content

Add async driver for Turso behind turso feature#424

Closed
dahankzter wants to merge 3 commits intorust-db:mainfrom
dahankzter:turso-driver
Closed

Add async driver for Turso behind turso feature#424
dahankzter wants to merge 3 commits intorust-db:mainfrom
dahankzter:turso-driver

Conversation

@dahankzter
Copy link
Copy Markdown

Add async driver for Turso

This adds a turso feature to refinery-core / refinery that implements
AsyncTransaction and AsyncQuery<Vec<Migration>> for
turso::Connection, so refinery can drive
migrations against Turso databases.

Why a dedicated driver (not rusqlite reuse)

Turso is wire-compatible with SQLite on disk but ships its own parser and
executor. In particular, Turso's internal FTS tables are created with a
CREATE INDEX ... USING fts form that rusqlite's parser rejects when a
consumer later opens the same file through rusqlite. Giving Turso users a
first-class driver — that speaks Turso's own API end-to-end — avoids that
class of cross-parser surprise.

What's in the PR

  • refinery_core/src/drivers/turso.rsAsyncTransaction,
    AsyncQuery<Vec<Migration>>, blanket AsyncMigrate for
    turso::Connection, plus a thin Error newtype wrapping
    turso::Error.
  • Module gate in refinery_core/src/drivers/mod.rs and re-export in
    refinery_core/src/lib.rs.
  • turso feature + optional dep on refinery-core and refinery.
    Version spec is intentionally a range (">=0.6.0-pre.18, <0.7")
    because Turso is still in its 0.6 prerelease series and Cargo's
    SemVer rules on prereleases mean a pinned 0.6.0-pre.N would lock
    consumers out of newer pre-releases — the range lets downstream
    users pick their own Turso.
  • Integration tests in refinery/tests/turso.rs mirroring the
    rusqlite/tokio-postgres layout. 21 tests total — the full set of
    tests/rusqlite.rs scenarios that are applicable to an async-only
    driver (sync-only _iter variants and the Config/CLI-wired tests
    are the only ones skipped, to keep this PR narrow). Includes two
    regression tests for hand-rolled-runner bug classes that refinery's
    driver-delegated batch execution naturally prevents: a leading --
    comment line before a CREATE TABLE, and a ; inside a comment
    body.
  • README: Turso added to the supported-drivers list.
  • Module-level doc with a usage snippet and a note on
    LIMBO_DISABLE_FILE_LOCK=1 for multi-process scenarios — Turso
    takes an exclusive file lock on Builder::build by default.

Implementation notes

  • Transactions: driven via BEGIN IMMEDIATE / COMMIT /
    ROLLBACK strings through Connection::execute, because the
    0.6.0-pre line does not expose Connection::transaction(). On a
    failed statement inside a batch, ROLLBACK is fired best-effort
    before the original error is returned.
  • Multi-statement migrations: dispatched through
    Connection::execute_batch so Turso's own tokenizer handles
    statement boundaries, -- comment lines, and ; characters inside
    comment bodies — refinery itself does no splitting.
  • Natively async: no spawn_blocking; mirrors the tokio_postgres
    driver shape.
  • Error wrapping: turso::Error already impls
    std::error::Error + Send + Sync, so the in-crate Error type is a
    thin newtype ("turso error: {source}" display, source() chains).

Testing

cargo build --features turso
cargo test  --features turso --test turso     # 21 passed
cargo clippy --features turso --lib --test turso -- -D warnings
cargo fmt --check

All pass. cargo build with the default feature set is unaffected.

Note on cargo clippy --all-targets: main currently has pre-existing
unused import: barrel::backend::… as Sql warnings in every driver's
integration-test file whenever the matching feature is disabled. This PR
inherits that pattern (so the warning on turso.rs when the feature is
off matches the one on rusqlite.rs when rusqlite is off). Happy to
address that across drivers as a follow-up if you'd like.

Out of scope (deliberate)

  • Sync Transaction / Query impl — Turso is async-only upstream.
  • ConfigDbType / with_connection_async! / CLI wiring — consumers
    construct a turso::Connection themselves and pass it to
    run_async, same contract as the other async drivers.
  • Remote Turso Cloud / Builder::new_remote — kept the API surface
    minimal so the driver stays stable across the 0.6.0-pre series.

Turso is a pure-Rust SQLite rewrite with its own async parser/executor,
wire-compatible with SQLite on disk but not always with rusqlite at
runtime (e.g. Turso's internal FTS tables use a `CREATE INDEX ... USING
fts` form that rusqlite's parser rejects).

This driver implements `AsyncTransaction` and `AsyncQuery<Vec<Migration>>`
for `turso::Connection` and is gated behind a new `turso` feature on
both `refinery-core` and `refinery`. Transactions are driven via string-
based `BEGIN IMMEDIATE` / `COMMIT` / `ROLLBACK` since the 0.6.0-pre
series does not expose `Connection::transaction()`, and migration
bodies are dispatched through `execute_batch` so Turso's own tokenizer
handles multi-statement files and embedded-semicolon comments.

Integration tests mirror the tokio-postgres layout and include
regressions for two classic hand-rolled-runner bugs that refinery's
driver-delegated splitting prevents: a leading `--` comment line
preceding a statement, and a `;` inside a comment body.
- Mark the turso module doc example as \`ignore\` — it references
  \`refinery::embed_migrations\`, which \`refinery-core\` cannot import
  (circular dep), so it was failing the doctest run.
- Add a narrowly-scoped exception in deny.toml for \`libloading\`'s ISC
  license, which is pulled in transitively by the turso feature through
  antithesis_sdk / clang-sys / turso_core. ISC is OSI-approved and
  functionally equivalent to MIT for redistribution; the workspace-wide
  allow list is intentionally unchanged.
@jxs
Copy link
Copy Markdown
Member

jxs commented Apr 24, 2026

Hi, this is a duplicate, see #415 (comment)

@jxs jxs closed this Apr 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants