A Hrana client — the mirror of Filo.Plug.
Where the server decodes client requests and encodes results, a client encodes
requests and decodes results, so it reuses the same protocol codec the server is
built on: Filo.Value for cell values and Filo.StmtResult for the shape of a
result. There is no second implementation of the wire format to drift from the
server's.
Model
One Filo.Client is one Hrana stream over one owned transport connection. The
first request opens the stream; each response carries a baton that threads into
the next request, so a transaction is a burst of execute/3s on the held
connection — the same per-statement round-trip model libSQL SDKs use over
POST /v2/pipeline. The client is an immutable struct you thread through your own
process; hold one per concurrent stream (on the BEAM, that is one cheap process
each).
{:ok, c} = Filo.Client.connect("http://localhost:8080", authority: "acme.example")
{:ok, _res, c} = Filo.Client.execute(c, "CREATE TABLE t (a INTEGER, b TEXT)")
{:ok, _res, c} = Filo.Client.execute(c, "INSERT INTO t VALUES (?, ?)", [1, "x"])
{:ok, res, c} = Filo.Client.execute(c, "SELECT a, b FROM t WHERE a = ?", [1])
res.rows #=> [[1, "x"]]
:ok = Filo.Client.close(c)Transport
The HTTP round-trip is a Filo.Client.Transport behaviour so Filo keeps its
no-concrete-transport posture: the default Filo.Client.Transport.Mint needs the
optional :mint dependency, and a host that would rather drive Finch/Req/:gun
passes its own :transport.
Scope
This is the Hrana 2/3 HTTP JSON pipeline (execute, close, baton threading) —
enough to drive a shard end to end. Protobuf, the WebSocket binding, cursors, and
batches are natural follow-ups that reuse the same codec.
Summary
Functions
Closes the stream (a best-effort close request that lets the server release the
connection) and the underlying transport.
Opens a Hrana stream to url (e.g. "http://host:8080").
Runs one SQL statement on the stream, binding args positionally.
Sends a raw list of Hrana stream-request maps as one pipeline and returns the raw
results list (and the advanced client). The low-level primitive execute/3 is
built on; use it to send request types this module has no sugar for yet
(batch, describe, get_autocommit).
Drops the transport connection and opens a fresh one, resetting the baton.
Types
Functions
@spec close(t()) :: :ok
Closes the stream (a best-effort close request that lets the server release the
connection) and the underlying transport.
Opens a Hrana stream to url (e.g. "http://host:8080").
Options
:transport— aFilo.Client.Transportmodule. DefaultFilo.Client.Transport.Mint(requires the optional:mintdep).:authority— theHostheader value. Set this to route by subdomain through a load balancer ("acme.fathom.example"), exactly as a libSQL SDK does. Default: the URL's host.:auth_token— a bearer token sent asAuthorization: Bearer <token>(libSQL'sauthTokenover HTTP). Default: none.:version—"v2"or"v3"(the pipeline path). Default"v2".:headers— extra request headers. Default[].:timeout— per-request timeout in ms. Default15_000.:transport_opts— extra options passed to the transport'sconnect/2.
@spec execute(t(), String.t(), [Filo.Value.native()]) :: {:ok, Filo.StmtResult.t(), t()} | {:error, Filo.Error.t() | {:transport, term()}, t()}
Runs one SQL statement on the stream, binding args positionally.
Returns the decoded Filo.StmtResult and the advanced client (its baton threaded
for the next call). A SQL-level failure is {:error, %Filo.Error{}, client} with
the stream still open (its baton advanced), matching the server. A transport
failure is {:error, {:transport, reason}, client}; recover with reconnect/1.
Values are encoded via Filo.Value, so integers, floats, text, nil, and
{:blob, binary} all bind correctly.
@spec pipeline(t(), [map()]) :: {:ok, [map()], t()} | {:error, Filo.Error.t() | {:transport, term()}, t()}
Sends a raw list of Hrana stream-request maps as one pipeline and returns the raw
results list (and the advanced client). The low-level primitive execute/3 is
built on; use it to send request types this module has no sugar for yet
(batch, describe, get_autocommit).
Drops the transport connection and opens a fresh one, resetting the baton.
The server rolls back any uncommitted transaction on the abandoned stream. Use it
to recover from a transport error (a stale keepalive the server closed, or a 502
while a load balancer moves the shard) without losing the client.