2026-05-29 15:50:20 +00:00
# einherjar/db-postgres
2026-08-08 10:48:40 -06:00
[](https://code.nochebuena.dev/einherjar/db-postgres)
2026-05-29 15:50:20 +00:00
[](LICENSE)
[](https://go.dev)
[]()
> The runes carved in stone do not fade when the runemaster dies. They outlast the hand that carved them.
`code.nochebuena.dev/einherjar/db-postgres` is the PostgreSQL database component of the Einherjar framework. It wraps `pgxpool` behind a lifecycle-aware `Component` , exposes a uniform `Executor` interface for queries and transactions, and provides a `UnitOfWork` that injects the active transaction into context — so repositories never need to know whether they are inside a transaction or not.
---
## Usage
### Setup
```go
import dbpg "code.nochebuena.dev/einherjar/db-postgres"
db := dbpg . New ( logger , dbpg . DefaultConfig ())
2026-08-07 22:21:06 -06:00
lc . Append ( db ) // OnInit opens pool; OnStop closes it
// db is observability.Checkable (PING health check, LevelCritical):
srv . Get ( "/health" , health . NewHandler ( logger , db ). ServeHTTP )
2026-05-29 15:50:20 +00:00
```
### Querying
```go
// GetExecutor returns the pool when called outside a UnitOfWork.
rows , err := db . GetExecutor ( ctx ). Query ( ctx , "SELECT id, name FROM users WHERE active = $1" , true )
defer rows . Close ()
var name string
err := db . GetExecutor ( ctx ). QueryRow ( ctx , "SELECT name FROM users WHERE id = $1" , id ). Scan ( & name )
```
### Manual transaction
```go
tx , err := db . Begin ( ctx )
if err != nil {
return err
}
defer tx . Rollback ( ctx )
_ , err = tx . Exec ( ctx , "UPDATE accounts SET balance = balance - $1 WHERE id = $2" , amount , fromID )
if err != nil {
return err
}
return tx . Commit ( ctx )
```
`BeginTx` is available when you need explicit isolation level control:
```go
tx , err := db . BeginTx ( ctx , pgx . TxOptions { IsoLevel : pgx . Serializable })
```
### Unit of work (recommended)
`UnitOfWork` wraps the transaction in context so every call to `GetExecutor` inside `uow.Do` automatically returns the active transaction. Repositories require no changes.
```go
uow := dbpg . NewUnitOfWork ( logger , db )
err := uow . Do ( ctx , func ( ctx context . Context ) error {
_ , err := db . GetExecutor ( ctx ). Exec ( ctx , "INSERT INTO orders (...) VALUES (...)" , ... )
return err
})
```
If the function returns an error, the transaction is rolled back. If it returns nil, the transaction is committed.
### Error handling
```go
if err := db . HandleError ( someErr ); err != nil {
// pgconn error codes mapped to xerrors:
// 23505 unique_violation → ErrAlreadyExists
// 23503 foreign_key_violation → ErrPreconditionFailed
// 23502 not_null_violation → ErrInvalidInput
// context.Canceled → ErrCancelled
// context.DeadlineExceeded → ErrDeadlineExceeded
}
```
`HandleError` is also available as a package-level function: `dbpg.HandleError(err)` .
---
## Environment variables
| Variable | Required | Default | Description |
|---|---|---|---|
| `EINHERJAR_PG_HOST` | Yes | — | PostgreSQL host |
| `EINHERJAR_PG_PORT` | No | `5432` | Listen port |
| `EINHERJAR_PG_USER` | Yes | — | Database user |
| `EINHERJAR_PG_PASSWORD` | Yes | — | Database password |
| `EINHERJAR_PG_NAME` | Yes | — | Database name |
| `EINHERJAR_PG_SSL_MODE` | No | `disable` | `disable` , `require` , `verify-full` |
| `EINHERJAR_PG_TIMEZONE` | No | `UTC` | Session timezone |
| `EINHERJAR_PG_MAX_CONNS` | No | `5` | Maximum connections in pool |
| `EINHERJAR_PG_MIN_CONNS` | No | `2` | Minimum idle connections |
| `EINHERJAR_PG_MAX_CONN_LIFETIME` | No | `1h` | Maximum connection lifetime |
| `EINHERJAR_PG_MAX_CONN_IDLE_TIME` | No | `30m` | Maximum idle time before connection is closed |
| `EINHERJAR_PG_HEALTH_CHECK_PERIOD` | No | `1m` | pgxpool background health check interval |
---
## Dependency graph
```
contracts (zero dependencies)
↑
core
↑
db-postgres (contracts, core, pgx/v5, pgerrcode)
↑
your app
```
---
## Verification
```bash
cd db-postgres/
go build ./...
go vet ./...
go test ./...
gofmt -l .
```
---
> *The hall is built before the warriors arrive.*
> *That is the only guarantee worth making.*