Module jape
A PostgreSQL client for D.
Open a Connection, run a statement with its values, and read the answer
the way that suits it: one value, all the rows, or one row at a time — as
rows, or straight into your own structs. Values are sent to the server
separately from the SQL text, as bound parameters, so they can never be
mistaken for SQL: injection is not possible.
Example
struct User { int id; string name; int age; }
auto db = Connection("host=localhost dbname=app user=app");
db .exec("insert into users(name, age) values($1, $2)", "Ada", 36);
auto adults = db .scalar!long("select count(*) from users where age >= $1", 18);
foreach (u; db .stream!User("select id, name, age from users order by id"))
writeln(u .name);
Where to start:
Connection—exec,scalarandstream, the three ways to run a statement;Query— for when the values come from different places:db;.sql(...) .bind(...) TransactionandConnection— all or nothing, and retried when the server asks;.transact CopyIn— loading many rows fast;Numeric— money and other exact decimals;PgException— everything the server said when something went wrong.
jape is a thin layer over libpq, which it reads through ImportC: no
hand-written bindings, and import jape_pq; reaches all of libpq when you
need something this module does not wrap.
See Also
the README for a guided tour, llms-full.txt for the whole API in one file.
Functions
| Name | Description |
|---|---|
isRetryable(sqlstate)
|
The two the server raises to mean "nothing happened, try again". |
Classes
| Name | Description |
|---|---|
PgException
|
What the server said, taken apart. |
Structs
| Name | Description |
|---|---|
Column
|
UDA mapping a member onto a differently named column: @Column("user_id") int id; |
Connection
|
A connection to the server, closed by its destructor. |
CopyIn
|
A bulk load in progress. |
CopyOut
|
Rows coming out of a COPY, one line at a time. |
Field
|
One cell. A copyable value that keeps its PGresult alive for as long as it exists. |
Numeric
|
An exact decimal, the way Postgres numeric is exact.
|
PreparedStatement
|
The plan is computed once and reused for the rest of the session. |
Query
|
A builder: it accumulates bindings at runtime and only hands everything to libpq on exec(). Values are always sent separately from the SQL text, as bound parameters, so they can never be mistaken for SQL. |
Result
|
Owns the PGresult via a reference count, allowing safe use with lazy ranges. |
Row
|
One row. Also a copyable view, and it too keeps its PGresult alive. |
Rows
|
A copyable view over a result's rows: a full RandomAccessRange. |
RowStream
|
A lazy InputRange. Copyable (map/filter need that), but every copy shares one cursor — advancing any of them advances all — and the draining happens exactly once, at the last reference: breaking out of a foreach early still leaves the connection clean. |
Savepoint
|
RAII, like Transaction: if you never call release(), the destructor rolls back to it. |
Transaction
|
Enums
| Name | Description |
|---|---|
Access
|
A read-only transaction is refused any write, and says so if one is attempted. |
Isolation
|
How much the transaction is allowed to see of what others are doing. |
Manifest constants
| Name | Type | Description |
|---|---|---|
defaultChunkSize
|
Rows per chunk when stream is called without an explicit size: single-row mode.
|
|
hasChunkedRows
|
True when the libpq headers this was compiled against provide PQsetChunkedRowsMode and PGRES_TUPLES_CHUNK, i.e. libpq 17 or newer. |