Prototype of an Ecto adapter for libSQL servers (Turso, Bunny Database,
sqld), over the Hrana protocol on HTTP, in pure Elixir.
libSQL speaks SQLite's dialect, so the SQL generation, the migrations, the
loaders/dumpers and the constraint errors are ecto_sqlite3's: only the driver
(EctoHrana.Connection) is new.
defmodule MyApp.Repo do
use Ecto.Repo, otp_app: :my_app, adapter: Ecto.Adapters.Hrana
end
config :my_app, MyApp.Repo,
uri: "libsql://my-db.turso.io",
auth_token: System.fetch_env!("LIBSQL_AUTH_TOKEN")Motivations
- Pure Elixir, no native code.
ecto_libsqlwraps libSQL's Rust library in a NIF: it needs a precompiled binary for the target (or a Rust toolchain), and a crash in native code takes the whole VM down. Against a remote server, the native library is not needed: Hrana is HTTP and JSON, whichReqandJasonspeak. This adapter builds and runs wherever the BEAM does, and a failing connection is an ordinary process crash, restarted byDBConnection. - Reuse rather than rewrite. libSQL speaks SQLite's dialect, and
ecto_sqlite3already generates it, runs the migrations, loads and dumps the types and maps the constraint errors. Only the transport is new, so the behaviour is the one SQLite users already know,ash_sqliteincluded. - Hosted libSQL, from Elixir. Turso and Bunny Database expose libSQL over Hrana: this lets an Ecto (or Ash) application use them like any other database, with transactions and savepoints.
Limitations
- A prototype: it passes its tests against
sqldand a full Ash application test suite, but has not been used against a remote server in production. - Each statement is an HTTP round trip to the server: against a remote server, the network latency dominates. Keep the application close to the database and avoid N+1 queries.
- Streams are emulated:
Repo.stream/2fetches all the rows at once. - No embedded replicas (a local copy synchronised with the server), which need libSQL's native library.
- The SQL generation comes from
ecto_sqlite3's internal modules, so theecto_sqlite3versions this library works with are pinned.
As with ecto_sqlite3, query_many/4 is not supported: run the statements
one by one.
Development
The tests and bench/compare.exs need a libSQL server:
docker run -p 127.0.0.1:8080:8080 ghcr.io/tursodatabase/libsql-server:latestLicense
MIT, see LICENSE.