kura_driver behaviour (kura v2.20.7)
View SourcePluggable database driver behaviour.
A kura_driver implementation is the seam between kura's portable
query layer and a specific database client library. Each impl wraps
one client (minato, pgo, esqlite, mysql_otp, ...) behind a uniform
query/transaction surface.
The pool layer (kura_pool) hands out a connection. The driver layer
runs SQL on it. Splitting them lets a single pool impl (e.g. an
in-memory test pool) be paired with multiple drivers, and lets a
driver be swapped without touching pool semantics.
Three call shapes
query/5 runs SQL on a pool. The driver picks (or already has) a
connection. Used by the common case where the caller does not own a
checkout.
query_on/4 runs SQL on a specific connection the caller already
holds. Used by the sandbox path: the test process owns a checked-out
conn and wants every query routed to it.
transaction/3 wraps a fun in a transaction. The driver chooses how
to thread connection context into queries inside the fun (process
dict, explicit arg, etc.); kura code inside the fun calls
kura_db:query/3 as usual and the driver's query/5 impl observes
the transaction context.
Today
The canonical impl is kura_driver_minato, and kura_driver_pgo is
still shipped. Both keep the in-flight transaction in the process
dictionary so that queries written inside a transaction function
code that does kura_db:transaction(Repo, fun() -> kura_repo:insert(...) end)
continues to work transparently.
Summary
Types
Driver-specific options. The PostgreSQL drivers honor decode_opts,
and the minato driver also passes timeout, which is a deadline after
which the statement is cancelled on the server. Other drivers may
ignore unknown keys or define their own.
Parameter list in the order placeholders appear in the SQL.
Driver-specific result shape. Today this is whatever the underlying
client returns (#{rows := [...], num_rows := N, ...} for both
PostgreSQL drivers). A
future kura layer may normalize this; the driver behaviour does not
prescribe a shape.
Query SQL string. Driver impls accept iodata.
Callbacks
Optional. Create the database if missing. Called by kura_migrator.
Optional. Round-trip a trivial query against Pool (e.g. SELECT 1).
Run SQL on a pool. The driver leases a connection (via PoolMod)
or threads through an active transaction context, runs the query,
and returns the result.
Run SQL on a specific connection the caller already owns. Used by the sandbox path where a test process holds a checked-out conn for its lifetime.
Wrap Fun in a database transaction over a pool. Queries inside
Fun route to the transaction's connection by whatever convention
the driver uses (both PostgreSQL drivers: the process dictionary).
Types
-type opts() :: map().
Driver-specific options. The PostgreSQL drivers honor decode_opts,
and the minato driver also passes timeout, which is a deadline after
which the statement is cancelled on the server. Other drivers may
ignore unknown keys or define their own.
-type params() :: [term()].
Parameter list in the order placeholders appear in the SQL.
-type query_result() :: dynamic().
Driver-specific result shape. Today this is whatever the underlying
client returns (#{rows := [...], num_rows := N, ...} for both
PostgreSQL drivers). A
future kura layer may normalize this; the driver behaviour does not
prescribe a shape.
-type sql() :: iodata().
Query SQL string. Driver impls accept iodata.
Callbacks
Optional. Create the database if missing. Called by kura_migrator.
-callback probe_pool(Pool :: kura_pool:name()) -> ok | {error, term()}.
Optional. Round-trip a trivial query against Pool (e.g. SELECT 1).
-callback query(PoolMod, Pool, SQL, Params, Opts) -> query_result() when PoolMod :: module(), Pool :: kura_pool:name(), SQL :: sql(), Params :: params(), Opts :: opts().
Run SQL on a pool. The driver leases a connection (via PoolMod)
or threads through an active transaction context, runs the query,
and returns the result.
-callback query_on(Conn, SQL, Params, Opts) -> query_result() when Conn :: kura_pool:conn(), SQL :: sql(), Params :: params(), Opts :: opts().
Run SQL on a specific connection the caller already owns. Used by the sandbox path where a test process holds a checked-out conn for its lifetime.
-callback transaction(PoolMod, Pool, Fun, Opts) -> term() when PoolMod :: module(), Pool :: kura_pool:name(), Fun :: fun(() -> term()), Opts :: opts().
Wrap Fun in a database transaction over a pool. Queries inside
Fun route to the transaction's connection by whatever convention
the driver uses (both PostgreSQL drivers: the process dictionary).
Opts carries driver-specific options. The pgo driver honors
pool_options => [{timeout, infinity | non_neg_integer()}] for
long-running streams; the minato driver takes no options here, because
a statement's deadline is set per query rather than per transaction.
Other drivers may ignore unknown keys.