modules/postgres
Package postgres connects apistock apps to PostgreSQL: a pgx connection pool with OpenTelemetry tracing, transactions, error classification for repositories, a readiness check and goose migrations (ADR-0005, ADR-0032).
Repositories hold a DBTX, so the same store runs on the pool or inside a transaction started with InTx. Transactions are passed explicitly, never stored in a context (ADR-0030).
This package is the pgx adapter, so pgx types appear in its API and its errors wrap pgx errors. Repositories translate them into domain errors with IsNoRows, UniqueViolation and the other helpers before returning.
Stability: pre-1.0 (ADR-0015).
Constants#
const DefaultConnectTimeout#
const DefaultConnectTimeout = 5 * time.SecondDefaultConnectTimeout bounds each connection attempt and the initial ping.
Functions#
func CheckViolation#
func CheckViolation(err error) (constraint string, ok bool)CheckViolation reports whether err is a check constraint violation and returns the constraint's name.
func ForeignKeyViolation#
func ForeignKeyViolation(err error) (constraint string, ok bool)ForeignKeyViolation reports whether err is a foreign key violation and returns the constraint's name.
func HealthCheck#
func HealthCheck(pool *pgxpool.Pool) health.CheckHealthCheck returns a readiness check that pings the database.
func InTx#
func InTx(ctx context.Context, db Beginner, fn func(tx pgx.Tx) error) errorInTx runs fn in a read-write transaction with the server's default isolation level. See InTxWithOptions.
func InTxWithOptions#
func InTxWithOptions(ctx context.Context, db Beginner, opts pgx.TxOptions, fn func(tx pgx.Tx) error) errorInTxWithOptions runs fn in a transaction started with opts. It commits when fn returns nil. Otherwise it rolls back and returns fn's error unchanged, so callers can match domain errors with errors.Is. If fn panics, the transaction is rolled back and the panic continues.
Build tx-bound repositories inside fn (for example NewUserStore(tx)); never keep tx after fn returns. With pgx.Serializable, retry when IsRetryable reports true.
func IsNoRows#
func IsNoRows(err error) boolIsNoRows reports whether err means a query returned no rows, as from QueryRow(...).Scan. Repositories return their not-found domain error.
func IsRetryable#
func IsRetryable(err error) boolIsRetryable reports whether err is a serialization failure or deadlock, after which the whole transaction can be retried.
func Migrate#
func Migrate(ctx context.Context, pool *pgxpool.Pool, fsys fs.FS) ([]int64, error)Migrate applies every pending goose migration in the root of fsys (files such as 00001_create_users.sql) and returns the versions it applied, in order. It returns nil when fsys has no migrations or none are pending.
A PostgreSQL advisory lock serialises concurrent callers, so several instances can run Migrate at once. Apps run migrations from a separate command, never implicitly at startup (ADR-0017).
func NotNullViolation#
func NotNullViolation(err error) (column string, ok bool)NotNullViolation reports whether err is a not-null violation and returns the column's name.
func Open#
func Open(ctx context.Context, url config.Secret, opts ...Option) (*pgxpool.Pool, error)Open creates a connection pool for url and pings the database, so a wrong URL or unreachable server fails at startup. Errors never include the URL, which may contain a password.
Every query becomes an OpenTelemetry client span carrying the SQL text but never its arguments. Close the pool on shutdown:
cleanup.Add("postgres", func(context.Context) error { pool.Close(); return nil })
func UniqueViolation#
func UniqueViolation(err error) (constraint string, ok bool)UniqueViolation reports whether err is a unique constraint violation and returns the constraint's name, so repositories can map it to a domain error such as ErrDuplicateEmail.
Types#
type Beginner#
type Beginner interface {
BeginTx(ctx context.Context, opts pgx.TxOptions) (pgx.Tx, error)
}Beginner starts transactions. *pgxpool.Pool and *pgx.Conn implement it.
type DBTX#
type DBTX 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
}DBTX runs queries. *pgxpool.Pool, *pgxpool.Conn, *pgx.Conn and pgx.Tx implement it, so repositories work with or without a transaction.
type MigrationState#
type MigrationState struct {
// Current is the highest applied version, 0 when none are applied.
Current int64
// Latest is the highest version in the migration files.
Latest int64
// Pending counts migration files not yet applied.
Pending int
}MigrationState describes the schema version against a set of migrations.
func Migrations#
func Migrations(ctx context.Context, pool *pgxpool.Pool, fsys fs.FS) (MigrationState, error)Migrations reports the database's migration state for fsys, for readiness reports and doctor commands. It changes nothing.
type Option#
type Option interface {
// contains filtered or unexported methods
}An Option configures Open.
func WithApplicationName#
func WithApplicationName(name string) OptionWithApplicationName sets application_name, shown in pg_stat_activity.
func WithConnectTimeout#
func WithConnectTimeout(d time.Duration) OptionWithConnectTimeout bounds each connection attempt and the ping in Open. Default: DefaultConnectTimeout.
func WithMaxConnIdleTime#
func WithMaxConnIdleTime(d time.Duration) OptionWithMaxConnIdleTime closes connections idle longer than d. Default: 30 minutes.
func WithMaxConnLifetime#
func WithMaxConnLifetime(d time.Duration) OptionWithMaxConnLifetime closes connections older than d, so load moves to new database hosts after failover. Default: one hour.
func WithMaxConns#
func WithMaxConns(n int32) OptionWithMaxConns sets the maximum pool size. Default: pgx's default, the greater of 4 and the number of CPUs.
func WithMinConns#
func WithMinConns(n int32) OptionWithMinConns sets how many connections the pool keeps open when idle. Default: 0.
func WithTracerProvider#
func WithTracerProvider(tp trace.TracerProvider) OptionWithTracerProvider sets the provider for query spans. Default: the global OpenTelemetry provider.