kura_driver_minato (kura_postgres v1.0.2)

View Source

kura_driver implementation over minato.

Where a query goes

Outside a transaction it goes to the pool: minato:query/4 borrows a connection, runs the statement and gives it back, all inside the call. Nothing is held and nothing is threaded through kura.

Inside a transaction it goes to the connection the transaction is running on, which kura_pool_minato holds and this module finds in the process dictionary. The reason is that a query written inside transaction/4's function is handed nothing, so the connection has to be found rather than passed.

Results and errors

minato answers #{command := atom(), num_rows := integer(), rows := [row()]}, which is the shape kura already reads, and a failing statement answers {error, {pgsql_error, Fields}} with code and constraint as binaries - which is what kura_repo_worker turns into a changeset error. Nothing in kura had to change for either.

numeric

numeric decodes to a float here, which is not minato's default: minato hands back the exact decimal text, because that is what the type is for. kura has always given callers a float for it, through pg_types, and a driver swap is the wrong moment to change what avg/1 returns for everybody.

A repo that wants the exact form says numeric_format => binary in its driver options, and should, for anything that is money.

Timeouts

timeout in the driver options is a deadline on the statement rather than on the read. minato cancels a statement that outlives it on the server and reads the cancellation through, so a slow query comes back as SQLSTATE 57014 and the connection goes back to the pool rather than being closed.

Summary

Functions

Create the database named in Config if it is not there.

Round trip a trivial statement against Pool.

Run a statement on a pool, or on the transaction this process is inside.

Run a statement on a connection the caller checked out.

Run Fun inside a transaction.

Functions

ensure_database(Config)

-spec ensure_database(map()) -> ok | {error, term()}.

Create the database named in Config if it is not there.

probe_pool(Pool)

-spec probe_pool(kura_pool:name()) -> ok | {error, term()}.

Round trip a trivial statement against Pool.

query(PoolMod, Pool, SQL, Params, Opts)

-spec query(module(), kura_pool:name(), iodata(), [term()], map()) -> dynamic().

Run a statement on a pool, or on the transaction this process is inside.

query_on(Holder, SQL, Params, Opts)

-spec query_on(kura_pool:conn(), iodata(), [term()], map()) -> dynamic().

Run a statement on a connection the caller checked out.

transaction(PoolMod, Pool, Fun, Opts)

-spec transaction(module(), kura_pool:name(), fun(() -> term()), map()) -> term().

Run Fun inside a transaction.

BEGIN first, COMMIT on a normal return, ROLLBACK on an exception, which is then re-raised. Queries inside Fun find the connection through the process dictionary.

Raises error(transaction_rolled_back) when the server answers the COMMIT with ROLLBACK, which it does when the transaction had already failed. Nothing was written, and returning the function's value there would report success for work the server threw away.