Depot.Middleware
lib/depot_middleware.march — Depot (PostgreSQL) pool integration for Bastion.
Checks out a database connection at the start of a request and returns it to the pool after the response is sent via the "pool_checkin" after-send hook.
The pool is created once at application startup (in the supervisor) and passed to with_pool/2 in the endpoint pipeline:
-- In the app supervisor (app.march):
let pool = Pool.start(Pool.default_pool_config(conn_cfg))
-- In the endpoint pipeline:
conn
|> Depot.Middleware.with_pool(pool)
|> Session.load(secret_key_base)
|> MyApp.Router.route()
-- In a handler:
match Depot.Middleware.get_conn(conn) do
Some(db) -> Depot.Query.exec_sql(query, db)
None -> Error("no db connection")
endThe after-send hook "pool_checkin" is dispatched by BastionServer. BastionServer.dispatch_hook/2 must have a case for "pool_checkin": "pool_checkin" -> Depot.Middleware.checkin_from_conn(conn) (This is already wired in bastion_server.march.)
Functions
Return the checked-out connection to the pool.
Called automatically by BastionServer via the `"pool_checkin"` after-send
hook registered by `with_pool/2`. Safe to call even if no connection was
checked out (no-op in that case).
You should not need to call this directly — it is invoked by the server
after every response when `with_pool/2` was used.Get the checked-out database connection from the request assigns.
Returns `Some(db_conn)` if a connection was successfully checked out,
or `None` if the pool was exhausted or `with_pool/2` was not called.
match Depot.Middleware.get_conn(conn) do
Some(db) -> run_query(db)
None -> send_error(conn, 503, "database unavailable")
endGet the pool Pid stored by with_pool/2.
Returns `Some(pool)` if `with_pool/2` was called, `None` otherwise.Execute a raw SQL query wrapped in a telemetry span.
Emits `["bastion", "depot", "query", "start"]` and
`["bastion", "depot", "query", "stop"]` around the query, including
the SQL string in metadata. On error, also emits
`["bastion", "depot", "query", "exception"]`.
match Depot.Middleware.query_with_telemetry(conn, "SELECT 1", []) do
Ok(rows) -> ...
Err(msg) -> ...
endAttach a Depot connection pool to the request and check out a connection.
Stores the pool Pid under `"_db_pool"` and the checked-out connection
under `"_db_conn"`. Registers the `"pool_checkin"` after-send hook so
the connection is automatically returned to the pool after the response.
If checkout fails (pool exhausted, DB unreachable), assigns `None` for
`"_db_conn"` and does NOT register the checkin hook (nothing to return).
Handlers should check `Depot.Middleware.get_conn/1` before using the
connection.
Call early in the request pipeline, typically right after body parsing:
conn
|> Depot.Middleware.with_pool(pool)
|> Session.load(secret_key_base)
|> MyApp.Router.route()