Documentation
¶
Overview ¶
Package postgres provides PostgreSQL access built on pgx/v5 and pgxpool. It exposes a DB type that wraps *pgxpool.Pool and implements the Querier interface. The legacy database/sql API is intentionally not exposed.
Index ¶
- func InjectTx(ctx context.Context, tx pgx.Tx) context.Context
- func IsConstraintViolation(err error) bool
- func IsUniqueViolation(err error) bool
- func PgError(err error) *pgconn.PgError
- type DB
- func (db *DB) Close()
- func (db *DB) Exec(ctx context.Context, sql string, args ...any) (pgconn.CommandTag, error)
- func (db *DB) Ping(ctx context.Context) error
- func (db *DB) Pool() *pgxpool.Pool
- func (db *DB) Querier(ctx context.Context) Querier
- func (db *DB) Query(ctx context.Context, sql string, args ...any) (pgx.Rows, error)
- func (db *DB) QueryRow(ctx context.Context, sql string, args ...any) pgx.Row
- func (db *DB) ReadyCheck() func(context.Context) error
- func (db *DB) WithTransaction(ctx context.Context, fn func(context.Context, pgx.Tx) error, ...) error
- func (db *DB) WithTransactionOptions(ctx context.Context, txOptions pgx.TxOptions, ...) error
- type Options
- type Querier
- type RetryConfig
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func InjectTx ¶
InjectTx returns a new context carrying tx as the ambient transaction. Use this in tests to inject a pre-opened transaction that will be rolled back.
func IsConstraintViolation ¶
IsConstraintViolation reports whether err is a PostgreSQL SQLSTATE 23xxx (integrity constraint violation family).
func IsUniqueViolation ¶
IsUniqueViolation reports whether err is SQLSTATE 23505 (unique_violation).
Types ¶
type DB ¶
type DB struct {
// contains filtered or unexported fields
}
DB wraps a *pgxpool.Pool and provides the devengine PostgreSQL surface.
func Open ¶
Open parses connString, applies opts and returns a connected DB. connString may be a DSN (key=value) or a postgres:// URL.
func OpenConfig ¶
OpenConfig applies opts to cfg and returns a connected DB. cfg must have been created by pgxpool.ParseConfig. The provided config is not mutated.
func (*DB) Pool ¶
Pool returns the underlying *pgxpool.Pool for callers that need raw pgx features (COPY, LISTEN/NOTIFY, batch, etc.). Prefer Querier for normal use.
func (*DB) Querier ¶
Querier returns the ambient pgx.Tx stored in ctx, or the pool itself if no transaction is active. Use this in repositories to transparently participate in an outer transaction.
func (*DB) ReadyCheck ¶
ReadyCheck returns a func suitable for health.Registry.Register.
func (*DB) WithTransaction ¶
func (db *DB) WithTransaction(ctx context.Context, fn func(context.Context, pgx.Tx) error, cfgs ...RetryConfig) error
WithTransaction executes fn inside a pgx transaction using default pgx transaction options. If ctx already carries an ambient transaction (via WithTransaction or InjectTx), fn is called within a savepoint instead of a new top-level transaction, implementing nested transaction semantics.
The provided fn receives a txCtx which MUST be passed to subsequent db.Querier(txCtx) calls. This ensures cross-repository operations participate in the same transaction.
Example:
db.WithTransaction(ctx, func(txCtx context.Context, tx pgx.Tx) error {
if err := userRepo.Create(txCtx, user); err != nil { return err }
if err := logRepo.Record(txCtx, "user_created"); err != nil { return err }
return nil
})
Transient errors whose SQLSTATE matches cfg.RetryOn cause automatic retry up to cfg.MaxAttempts times with exponential jitter backoff. Consequently fn is retryable code: it must not perform external side effects. Store an outbox message or a jobs.Job in tx and let the Outbox/Jobs worker run that side effect after the transaction commits.
Non-transient errors, context cancellation, and business errors are never retried. If fn returns nil, the transaction (or savepoint) is committed.
func (*DB) WithTransactionOptions ¶
func (db *DB) WithTransactionOptions(ctx context.Context, txOptions pgx.TxOptions, fn func(context.Context, pgx.Tx) error, cfgs ...RetryConfig) error
WithTransactionOptions executes fn using txOptions for a new top-level pgx transaction. Its retry and side-effect contract is identical to WithTransaction.
PostgreSQL transaction options are fixed when the outer transaction begins. Therefore, when ctx has an ambient transaction, zero txOptions uses a savepoint and non-zero txOptions returns an error rather than silently ignoring the requested isolation/access/deferrable modes.
type Options ¶
type Options struct {
// MaxConns is the maximum number of connections in the pool.
// Defaults to pgxpool default (4 × NumCPU).
MaxConns int32
// MinConns keeps at least this many connections alive.
MinConns int32
// MaxConnLifetime is the maximum age of a connection before recycling.
MaxConnLifetime time.Duration
// MaxConnIdleTime is how long an idle connection is kept before closing.
MaxConnIdleTime time.Duration
// HealthCheckPeriod is how often the pool pings idle connections.
HealthCheckPeriod time.Duration
}
Options configures the connection pool.
type Querier ¶
type Querier interface {
Exec(ctx context.Context, sql string, args ...any) (pgconn.CommandTag, error)
Query(ctx context.Context, sql string, args ...any) (pgx.Rows, error)
QueryRow(ctx context.Context, sql string, args ...any) pgx.Row
}
Querier abstracts the common row-level operations available on both a pool and a transaction. Repositories should depend on Querier, not on *DB or *pgxpool.Pool directly.
type RetryConfig ¶
type RetryConfig struct {
// MaxAttempts is the total number of attempts (including the first).
// Zero or negative means no retry (single attempt).
MaxAttempts int
// RetryOn is the set of SQLSTATE codes that qualify for a retry.
// If empty, defaults to {"40P01"} (deadlock_detected).
RetryOn []string
// InitialBackoff is the base wait before the first retry.
// Defaults to 20ms.
InitialBackoff time.Duration
// MaxBackoff caps the exponential backoff.
// Defaults to 500ms.
MaxBackoff time.Duration
}
RetryConfig controls how WithTransaction retries on transient SQLSTATE errors.
A callback passed to WithTransaction can run more than once. It must not perform external side effects such as sending email, publishing a webhook, or acknowledging a message broker. Persist an outbox message or a delayed job in the transaction instead, and let its handler perform the external action after commit.