Documentation
¶
Overview ¶
Package pgxkit provides a production-ready PostgreSQL toolkit for Go applications.
pgxkit is a tool-agnostic PostgreSQL toolkit that works with any approach to PostgreSQL development - raw pgx usage, code generation tools like sqlc or Skimatik, or any other PostgreSQL development workflow.
Key Features:
- Read/Write Pool Abstraction: Safe by default with write pool, explicit read pool methods for optimization
- Extensible Hook System: Add logging, tracing, metrics, circuit breakers through hooks
- Smart Retry Logic: PostgreSQL-aware error detection with exponential backoff
- Testing Infrastructure: Golden test support for performance regression detection
- Type Helpers: Seamless pgx type conversions for clean architecture
- Health Checks: Built-in database connectivity monitoring
- Graceful Shutdown: Production-ready lifecycle management
Basic Usage:
db := pgxkit.NewDB()
err := db.Connect(ctx, "", pgxkit.WithMaxConns(25))
if err != nil {
log.Fatal(err)
}
defer db.Shutdown(ctx)
// Execute queries (uses write pool by default - safe)
_, err = db.Exec(ctx, "INSERT INTO users (name) VALUES ($1)", "John")
// Optimize reads with explicit read pool usage
rows, err := db.ReadQuery(ctx, "SELECT id, name FROM users")
Hook System:
db := pgxkit.NewDB()
err := db.Connect(ctx, "",
pgxkit.WithBeforeOperation(func(ctx context.Context, sql string, args []interface{}, operationErr error) error {
log.Printf("Executing: %s", sql)
return nil
}),
)
The package follows a "safety first" design - all default methods use the write pool for consistency, with explicit ReadQuery() methods available for read optimization.
Index ¶
- func CleanupGolden(testName string) error
- func CleanupTestData(sqlStatements ...string)
- func FromPgxBool(b pgtype.Bool) *bool
- func FromPgxBoolToBool(b pgtype.Bool) bool
- func FromPgxDate(d pgtype.Date) *time.Time
- func FromPgxFloat4(f pgtype.Float4) *float32
- func FromPgxFloat8(f pgtype.Float8) *float64
- func FromPgxInt2(i pgtype.Int2) *int16
- func FromPgxInt4(i pgtype.Int4) *int32
- func FromPgxInt4ToInt(i pgtype.Int4) *int
- func FromPgxInt8(i pgtype.Int8) *int64
- func FromPgxInt8Array(a pgtype.Array[pgtype.Int8]) []int64
- func FromPgxNumeric(n pgtype.Numeric) *float64
- func FromPgxText(t pgtype.Text) *string
- func FromPgxTextArray(a pgtype.Array[pgtype.Text]) []string
- func FromPgxTextToString(t pgtype.Text) string
- func FromPgxTime(t pgtype.Time) *time.Time
- func FromPgxTimestamp(t pgtype.Timestamp) *time.Time
- func FromPgxTimestamptz(t pgtype.Timestamptz) time.Time
- func FromPgxTimestamptzPtr(t pgtype.Timestamptz) *time.Time
- func FromPgxUUID(pgxID pgtype.UUID) uuid.UUID
- func FromPgxUUIDToPtr(pgxID pgtype.UUID) *uuid.UUID
- func GetDSN() string
- func IsRetryableError(err error) bool
- func Retry[T any](ctx context.Context, fn func(context.Context) (T, error), opts ...RetryOption) (T, error)
- func RetryOperation(ctx context.Context, operation func(context.Context) error, ...) error
- func ToPgxBool(b *bool) pgtype.Bool
- func ToPgxBoolFromBool(b bool) pgtype.Bool
- func ToPgxDate(t *time.Time) pgtype.Date
- func ToPgxFloat4(f *float32) pgtype.Float4
- func ToPgxFloat8(f *float64) pgtype.Float8
- func ToPgxInt2(i *int16) pgtype.Int2
- func ToPgxInt4(i *int32) pgtype.Int4
- func ToPgxInt4FromInt(i *int) pgtype.Int4
- func ToPgxInt8(i *int64) pgtype.Int8
- func ToPgxInt8Array(s []int64) pgtype.Array[pgtype.Int8]
- func ToPgxNumeric(f *float64) pgtype.Numeric
- func ToPgxText(s *string) pgtype.Text
- func ToPgxTextArray(s []string) pgtype.Array[pgtype.Text]
- func ToPgxTextFromString(s string) pgtype.Text
- func ToPgxTime(t *time.Time) pgtype.Time
- func ToPgxTimestamp(t *time.Time) pgtype.Timestamp
- func ToPgxTimestamptz(t *time.Time) pgtype.Timestamptz
- func ToPgxUUID(id uuid.UUID) pgtype.UUID
- func ToPgxUUIDFromPtr(id *uuid.UUID) pgtype.UUID
- type ConnectOption
- func WithAfterOperation(fn HookFunc) ConnectOption
- func WithAfterTransaction(fn HookFunc) ConnectOption
- func WithBeforeOperation(fn HookFunc) ConnectOption
- func WithBeforeTransaction(fn HookFunc) ConnectOption
- func WithMaxConnIdleTime(d time.Duration) ConnectOption
- func WithMaxConnLifetime(d time.Duration) ConnectOption
- func WithMaxConns(n int32) ConnectOption
- func WithMinConns(n int32) ConnectOption
- func WithOnAcquire(fn func(context.Context, *pgx.Conn) error) ConnectOption
- func WithOnConnect(fn func(*pgx.Conn) error) ConnectOption
- func WithOnDisconnect(fn func(*pgx.Conn)) ConnectOption
- func WithOnRelease(fn func(*pgx.Conn)) ConnectOption
- func WithOnShutdown(fn HookFunc) ConnectOption
- func WithReadMaxConns(n int32) ConnectOption
- func WithReadMinConns(n int32) ConnectOption
- func WithWriteMaxConns(n int32) ConnectOption
- func WithWriteMinConns(n int32) ConnectOption
- type DB
- func (db *DB) AssertGolden(t *testing.T, testName string)
- func (db *DB) BeginTx(ctx context.Context, txOptions pgx.TxOptions) (pgx.Tx, error)
- func (db *DB) Connect(ctx context.Context, dsn string, opts ...ConnectOption) error
- func (db *DB) ConnectReadWrite(ctx context.Context, readDSN, writeDSN string, opts ...ConnectOption) error
- func (db *DB) Exec(ctx context.Context, sql string, args ...interface{}) (pgconn.CommandTag, error)
- func (db *DB) HealthCheck(ctx context.Context) error
- func (db *DB) IsReady(ctx context.Context) bool
- func (db *DB) Query(ctx context.Context, sql string, args ...interface{}) (pgx.Rows, error)
- func (db *DB) QueryRow(ctx context.Context, sql string, args ...interface{}) pgx.Row
- func (db *DB) ReadPool() *pgxpool.Pool
- func (db *DB) ReadQuery(ctx context.Context, sql string, args ...interface{}) (pgx.Rows, error)
- func (db *DB) ReadQueryRow(ctx context.Context, sql string, args ...interface{}) pgx.Row
- func (db *DB) ReadStats() *pgxpool.Stat
- func (db *DB) Shutdown(ctx context.Context) error
- func (db *DB) Stats() *pgxpool.Stat
- func (db *DB) WritePool() *pgxpool.Pool
- type DatabaseError
- type HookFunc
- type HookType
- type NotFoundError
- type QueryPlan
- type RetryOption
- type TestDB
- type ValidationError
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CleanupGolden ¶ added in v1.1.0
CleanupGolden removes all golden test files for the specified test name. This includes both the captured query plan file and its baseline file from the testdata/golden directory.
func CleanupTestData ¶
func CleanupTestData(sqlStatements ...string)
CleanupTestData executes cleanup SQL statements on the shared test database
func FromPgxBool ¶
FromPgxBool converts a pgtype.Bool to a bool pointer. If the pgtype.Bool is invalid (NULL), returns nil.
func FromPgxBoolToBool ¶ added in v1.1.0
FromPgxBoolToBool converts a pgtype.Bool to a bool value. If the pgtype.Bool is invalid (NULL), returns false.
func FromPgxDate ¶ added in v1.1.0
FromPgxDate converts a pgtype.Date to a time.Time pointer. If the pgtype.Date is invalid (NULL), returns nil.
func FromPgxFloat4 ¶ added in v1.1.0
FromPgxFloat4 converts a pgtype.Float4 to a float32 pointer. If the pgtype.Float4 is invalid (NULL), returns nil.
func FromPgxFloat8 ¶ added in v1.1.0
FromPgxFloat8 converts a pgtype.Float8 to a float64 pointer. If the pgtype.Float8 is invalid (NULL), returns nil.
func FromPgxInt2 ¶ added in v1.1.0
FromPgxInt2 converts a pgtype.Int2 to an int16 pointer. If the pgtype.Int2 is invalid (NULL), returns nil.
func FromPgxInt4 ¶
FromPgxInt4 converts a pgtype.Int4 to an int32 pointer. If the pgtype.Int4 is invalid (NULL), returns nil.
func FromPgxInt4ToInt ¶ added in v1.1.0
FromPgxInt4ToInt converts a pgtype.Int4 to an int pointer. If the pgtype.Int4 is invalid (NULL), returns nil.
func FromPgxInt8 ¶
FromPgxInt8 converts a pgtype.Int8 to an int64 pointer. If the pgtype.Int8 is invalid (NULL), returns nil.
func FromPgxInt8Array ¶ added in v1.1.0
FromPgxInt8Array converts a pgtype.Array[pgtype.Int8] to an int64 slice. If the array is invalid (NULL), returns nil.
func FromPgxNumeric ¶ added in v1.1.0
FromPgxNumeric converts a pgtype.Numeric to a float64 pointer. If the pgtype.Numeric is invalid (NULL), returns nil.
func FromPgxText ¶
FromPgxText converts a pgtype.Text to a string pointer. If the pgtype.Text is invalid (NULL), returns nil.
func FromPgxTextArray ¶ added in v1.1.0
FromPgxTextArray converts a pgtype.Array[pgtype.Text] to a string slice. If the array is invalid (NULL), returns nil.
func FromPgxTextToString ¶
FromPgxTextToString converts a pgtype.Text to a string value. If the pgtype.Text is invalid (NULL), returns empty string.
func FromPgxTime ¶ added in v1.1.0
FromPgxTime converts a pgtype.Time to a time.Time pointer. If the pgtype.Time is invalid (NULL), returns nil. The returned time will be on the current date with the time component.
func FromPgxTimestamp ¶ added in v1.1.0
FromPgxTimestamp converts a pgtype.Timestamp to a time.Time pointer. If the pgtype.Timestamp is invalid (NULL), returns nil.
func FromPgxTimestamptz ¶
func FromPgxTimestamptz(t pgtype.Timestamptz) time.Time
FromPgxTimestamptz converts a pgtype.Timestamptz to a time.Time value. If the pgtype.Timestamptz is invalid (NULL), returns zero time.
func FromPgxTimestamptzPtr ¶
func FromPgxTimestamptzPtr(t pgtype.Timestamptz) *time.Time
FromPgxTimestamptzPtr converts a pgtype.Timestamptz to a time.Time pointer. If the pgtype.Timestamptz is invalid (NULL), returns nil.
func FromPgxUUID ¶
FromPgxUUID converts a pgtype.UUID to uuid.UUID. Returns uuid.Nil if the pgtype.UUID is invalid or cannot be parsed.
func FromPgxUUIDToPtr ¶ added in v1.1.0
FromPgxUUIDToPtr converts a pgtype.UUID to a uuid.UUID pointer. If the pgtype.UUID is invalid (NULL), returns nil.
func GetDSN ¶
func GetDSN() string
GetDSN returns a PostgreSQL connection string built from environment variables. This is useful for scripts and tools that need a connection string rather than a pgxpool.Pool.
Environment variables used:
- POSTGRES_HOST (default: "localhost")
- POSTGRES_PORT (default: 5432)
- POSTGRES_USER (default: "postgres")
- POSTGRES_PASSWORD (default: "")
- POSTGRES_DB (default: "postgres")
- POSTGRES_SSLMODE (default: "disable")
Example:
dsn := pgxkit.GetDSN()
func IsRetryableError ¶ added in v1.1.0
IsRetryableError determines if an error is worth retrying
func Retry ¶ added in v1.4.0
func Retry[T any](ctx context.Context, fn func(context.Context) (T, error), opts ...RetryOption) (T, error)
Retry executes a generic operation with configurable retry logic. It uses exponential backoff to avoid thundering herd problems.
func RetryOperation ¶ added in v1.1.0
func RetryOperation(ctx context.Context, operation func(context.Context) error, opts ...RetryOption) error
RetryOperation executes an operation with configurable retry logic. It uses exponential backoff to avoid thundering herd problems.
Example:
err := pgxkit.RetryOperation(ctx, func(ctx context.Context) error {
return doSomething(ctx)
}, pgxkit.WithMaxRetries(5), pgxkit.WithMaxDelay(5*time.Second))
func ToPgxBool ¶
ToPgxBool converts a bool pointer to pgtype.Bool. If the input is nil, returns an invalid pgtype.Bool (NULL in database).
func ToPgxBoolFromBool ¶ added in v1.1.0
ToPgxBoolFromBool converts a bool value to pgtype.Bool. Use this when you have a bool value instead of a pointer.
func ToPgxDate ¶ added in v1.1.0
ToPgxDate converts a time.Time pointer to pgtype.Date. If the input is nil, returns an invalid pgtype.Date (NULL in database).
func ToPgxFloat4 ¶ added in v1.1.0
ToPgxFloat4 converts a float32 pointer to pgtype.Float4. If the input is nil, returns an invalid pgtype.Float4 (NULL in database).
func ToPgxFloat8 ¶ added in v1.1.0
ToPgxFloat8 converts a float64 pointer to pgtype.Float8. If the input is nil, returns an invalid pgtype.Float8 (NULL in database).
func ToPgxInt2 ¶ added in v1.1.0
ToPgxInt2 converts an int16 pointer to pgtype.Int2. If the input is nil, returns an invalid pgtype.Int2 (NULL in database).
func ToPgxInt4 ¶ added in v1.1.0
ToPgxInt4 converts an int32 pointer to pgtype.Int4. If the input is nil, returns an invalid pgtype.Int4 (NULL in database).
func ToPgxInt4FromInt ¶
ToPgxInt4FromInt converts an int pointer to pgtype.Int4. If the input is nil, returns an invalid pgtype.Int4 (NULL in database).
func ToPgxInt8 ¶
ToPgxInt8 converts an int64 pointer to pgtype.Int8. If the input is nil, returns an invalid pgtype.Int8 (NULL in database).
func ToPgxInt8Array ¶ added in v1.1.0
ToPgxInt8Array converts an int64 slice to pgtype.Array[pgtype.Int8]. If the input is nil, returns an invalid array (NULL in database).
func ToPgxNumeric ¶ added in v1.1.0
ToPgxNumeric converts a float64 pointer to pgtype.Numeric. If the input is nil, returns an invalid pgtype.Numeric (NULL in database). Uses 6 decimal places as standard precision.
func ToPgxText ¶
ToPgxText converts a string pointer to pgtype.Text. If the input is nil, returns an invalid pgtype.Text (NULL in database).
func ToPgxTextArray ¶ added in v1.1.0
ToPgxTextArray converts a string slice to pgtype.Array[pgtype.Text]. If the input is nil, returns an invalid array (NULL in database).
func ToPgxTextFromString ¶ added in v1.1.0
ToPgxTextFromString converts a string value to pgtype.Text. Use this when you have a string value instead of a pointer.
func ToPgxTime ¶ added in v1.1.0
ToPgxTime converts a time.Time pointer to pgtype.Time. If the input is nil, returns an invalid pgtype.Time (NULL in database).
func ToPgxTimestamp ¶ added in v1.1.0
ToPgxTimestamp converts a time.Time pointer to pgtype.Timestamp. If the input is nil, returns an invalid pgtype.Timestamp (NULL in database).
func ToPgxTimestamptz ¶
func ToPgxTimestamptz(t *time.Time) pgtype.Timestamptz
ToPgxTimestamptz converts a time.Time pointer to pgtype.Timestamptz. If the input is nil, returns an invalid pgtype.Timestamptz (NULL in database).
Types ¶
type ConnectOption ¶ added in v1.2.0
type ConnectOption func(*connectConfig)
ConnectOption configures a database connection.
func WithAfterOperation ¶ added in v1.2.0
func WithAfterOperation(fn HookFunc) ConnectOption
func WithAfterTransaction ¶ added in v1.2.0
func WithAfterTransaction(fn HookFunc) ConnectOption
func WithBeforeOperation ¶ added in v1.2.0
func WithBeforeOperation(fn HookFunc) ConnectOption
func WithBeforeTransaction ¶ added in v1.2.0
func WithBeforeTransaction(fn HookFunc) ConnectOption
func WithMaxConnIdleTime ¶ added in v1.2.0
func WithMaxConnIdleTime(d time.Duration) ConnectOption
func WithMaxConnLifetime ¶ added in v1.2.0
func WithMaxConnLifetime(d time.Duration) ConnectOption
func WithMaxConns ¶ added in v1.2.0
func WithMaxConns(n int32) ConnectOption
func WithMinConns ¶ added in v1.2.0
func WithMinConns(n int32) ConnectOption
func WithOnAcquire ¶ added in v1.2.0
func WithOnConnect ¶ added in v1.2.0
func WithOnConnect(fn func(*pgx.Conn) error) ConnectOption
func WithOnDisconnect ¶ added in v1.2.0
func WithOnDisconnect(fn func(*pgx.Conn)) ConnectOption
func WithOnRelease ¶ added in v1.2.0
func WithOnRelease(fn func(*pgx.Conn)) ConnectOption
func WithOnShutdown ¶ added in v1.2.0
func WithOnShutdown(fn HookFunc) ConnectOption
func WithReadMaxConns ¶ added in v1.2.0
func WithReadMaxConns(n int32) ConnectOption
func WithReadMinConns ¶ added in v1.2.0
func WithReadMinConns(n int32) ConnectOption
func WithWriteMaxConns ¶ added in v1.2.0
func WithWriteMaxConns(n int32) ConnectOption
func WithWriteMinConns ¶ added in v1.2.0
func WithWriteMinConns(n int32) ConnectOption
type DB ¶ added in v1.1.0
type DB struct {
// contains filtered or unexported fields
}
DB represents a database connection with read/write pool abstraction. It provides a safe-by-default approach where all operations use the write pool unless explicitly using Read* methods for optimization.
The DB supports:
- Single pool mode (same pool for read/write)
- Read/write split mode (separate pools for optimization)
- Extensible hook system for logging, tracing, metrics
- Graceful shutdown with active operation tracking
- Built-in retry logic for transient failures
- Health checks and connection statistics
func NewDB ¶ added in v1.1.0
func NewDB() *DB
NewDB creates a new unconnected DB instance. Call Connect() with options to establish the database connection.
Example:
db := pgxkit.NewDB()
err := db.Connect(ctx, "postgres://user:pass@localhost/db",
pgxkit.WithMaxConns(25),
pgxkit.WithBeforeOperation(myLoggingHook),
)
func (*DB) AssertGolden ¶ added in v1.1.0
AssertGolden compares captured query plans against a baseline file. On first run, it creates a baseline file from the current golden output. On subsequent runs, it compares the current plans against the baseline and reports test failures for any query count, SQL, or plan changes.
func (*DB) BeginTx ¶ added in v1.1.0
BeginTx starts a transaction using the write pool. Transactions always use the write pool to ensure consistency. The transaction will execute BeforeTransaction and AfterTransaction hooks.
Example:
tx, err := db.BeginTx(ctx, pgx.TxOptions{})
if err != nil {
return err
}
defer tx.Rollback(ctx) // Safe to call even after commit
_, err = tx.Exec(ctx, "INSERT INTO users (name) VALUES ($1)", name)
if err != nil {
return err
}
return tx.Commit(ctx)
func (*DB) Connect ¶ added in v1.1.0
Connect establishes a database connection with a single pool (same pool for read/write). If dsn is empty, it uses environment variables to construct the connection string. Options are applied to configure pool settings and hooks.
This is the recommended approach for most applications as it provides safety by default while still allowing read optimization through ReadQuery methods.
Example:
db := pgxkit.NewDB()
err := db.Connect(ctx, "postgres://user:pass@localhost/db",
pgxkit.WithMaxConns(25),
pgxkit.WithOnConnect(func(conn *pgx.Conn) error {
_, err := conn.Exec(context.Background(), "SET application_name = 'myapp'")
return err
}),
)
// Or use environment variables:
err := db.Connect(ctx, "")
func (*DB) ConnectReadWrite ¶ added in v1.1.0
func (db *DB) ConnectReadWrite(ctx context.Context, readDSN, writeDSN string, opts ...ConnectOption) error
ConnectReadWrite establishes database connections with separate read and write pools. If readDSN or writeDSN is empty, it uses environment variables to construct the connection string. Options are applied to both pools.
This is useful for applications that want to optimize read performance by routing read queries to read replicas while ensuring writes go to the primary database.
Example:
db := pgxkit.NewDB()
err := db.ConnectReadWrite(ctx, "postgres://user:pass@read-replica/db", "postgres://user:pass@primary/db",
pgxkit.WithMaxConns(25),
)
// Now ReadQuery methods will use the read pool, while Query/Exec use the write pool
func (*DB) Exec ¶ added in v1.1.0
Exec executes a statement using the write pool. This method is used for INSERT, UPDATE, DELETE, and other write operations.
Example:
tag, err := db.Exec(ctx, "INSERT INTO users (name, email) VALUES ($1, $2)", name, email)
if err != nil {
return err
}
fmt.Printf("Inserted %d rows\n", tag.RowsAffected())
func (*DB) HealthCheck ¶ added in v1.1.0
HealthCheck performs a simple health check by pinging the database. This is useful for health check endpoints and monitoring systems. It returns an error if the database is not connected, shutting down, or unreachable.
Example:
if err := db.HealthCheck(ctx); err != nil {
log.Printf("Database health check failed: %v", err)
http.Error(w, "Database unavailable", http.StatusServiceUnavailable)
return
}
func (*DB) IsReady ¶ added in v1.1.0
IsReady checks if the database connection is ready to accept queries. This is a convenience method that returns true if HealthCheck() succeeds. It's useful for readiness probes and quick status checks.
Example:
if db.IsReady(ctx) {
log.Println("Database is ready to accept queries")
}
func (*DB) Query ¶ added in v1.1.0
Query executes a query using the write pool (safe by default). This ensures consistency by always using the primary database connection. Use ReadQuery for read-only queries that can benefit from read replicas.
Example:
rows, err := db.Query(ctx, "SELECT * FROM users WHERE active = $1", true)
if err != nil {
return err
}
defer rows.Close()
func (*DB) QueryRow ¶ added in v1.1.0
QueryRow executes a query that returns a single row using the write pool. This ensures consistency by always using the primary database connection. Use ReadQueryRow for read-only queries that can benefit from read replicas.
Example:
var userID int err := db.QueryRow(ctx, "SELECT id FROM users WHERE email = $1", email).Scan(&userID)
func (*DB) ReadPool ¶ added in v1.2.0
ReadPool returns the underlying read connection pool. Returns nil if no separate read pool is configured.
func (*DB) ReadQuery ¶ added in v1.1.0
ReadQuery executes a query using the read pool (explicit optimization). This method routes the query to read replicas when available, improving performance for read-heavy workloads. Only use this for queries that can tolerate read replica lag.
Example:
rows, err := db.ReadQuery(ctx, "SELECT * FROM users WHERE active = $1", true)
if err != nil {
return err
}
defer rows.Close()
func (*DB) ReadQueryRow ¶ added in v1.1.0
ReadQueryRow executes a query that returns a single row using the read pool. This method routes the query to read replicas when available, improving performance for read-heavy workloads. Only use this for queries that can tolerate read replica lag.
Example:
var count int err := db.ReadQueryRow(ctx, "SELECT COUNT(*) FROM users").Scan(&count)
func (*DB) ReadStats ¶ added in v1.1.0
ReadStats returns statistics for the read pool. This provides information about read connection usage, which is useful for monitoring read replica performance and connection pool health.
Example:
stats := db.ReadStats()
if stats != nil {
log.Printf("Read pool active connections: %d", stats.AcquiredConns())
}
func (*DB) Shutdown ¶ added in v1.1.0
Shutdown gracefully shuts down the database connections. It waits for active operations to complete, respecting the context timeout. If the context times out, shutdown proceeds anyway to prevent hanging.
The shutdown process: 1. Marks the database as shutting down (new operations will fail) 2. Waits for active operations to complete (respects context timeout) 3. Executes OnShutdown hooks 4. Closes connection pools
Example:
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() err := db.Shutdown(ctx)
func (*DB) Stats ¶ added in v1.1.0
Stats returns statistics for the write pool. This provides information about connection usage, which is useful for monitoring and debugging connection pool performance.
Example:
stats := db.Stats()
if stats != nil {
log.Printf("Active connections: %d", stats.AcquiredConns())
log.Printf("Idle connections: %d", stats.IdleConns())
}
type DatabaseError ¶
type DatabaseError struct {
Entity string
Operation string // "create", "update", "delete", "query"
Err error
}
DatabaseError represents database operation failures such as connection errors, constraint violations, or other database-specific errors.
func NewDatabaseError ¶
func NewDatabaseError(entity, operation string, err error) *DatabaseError
NewDatabaseError creates a new DatabaseError with the given entity, operation, and underlying error.
func (*DatabaseError) Error ¶
func (e *DatabaseError) Error() string
func (*DatabaseError) Unwrap ¶
func (e *DatabaseError) Unwrap() error
type HookFunc ¶ added in v1.1.0
HookFunc is the universal hook function signature for operation-level hooks. All operation-level hooks use this signature for consistency and simplicity.
Parameters:
- ctx: The context for the operation
- sql: The SQL statement being executed (empty for shutdown hooks)
- args: The arguments for the SQL statement (nil for shutdown hooks)
- operationErr: The error from the operation (nil for before hooks)
The hook should return an error if it wants to abort the operation. For after hooks, returning an error will not affect the original operation result.
type HookType ¶ added in v1.1.0
type HookType int
HookType represents the type of hook for operation-level hooks. These hooks are executed during database operations and provide extensibility for logging, tracing, metrics, circuit breakers, and other cross-cutting concerns.
const ( // BeforeOperation is called before any query/exec operation. // The operationErr parameter will always be nil. BeforeOperation HookType = iota // AfterOperation is called after any query/exec operation. // The operationErr parameter contains the result of the operation. AfterOperation // BeforeTransaction is called before starting a transaction. // The operationErr parameter will always be nil. BeforeTransaction // AfterTransaction is called after a transaction completes. // The operationErr parameter contains the result of the transaction. AfterTransaction // OnShutdown is called during graceful shutdown. // The sql and args parameters will be empty, operationErr will be nil. OnShutdown )
type NotFoundError ¶
type NotFoundError struct {
Entity string
Identifier interface{}
}
NotFoundError represents when a requested entity is not found in the database. This error should be used instead of returning pgx.ErrNoRows directly.
Example:
if err == pgx.ErrNoRows {
return nil, pgxkit.NewNotFoundError("User", userID)
}
func NewNotFoundError ¶
func NewNotFoundError(entity string, identifier interface{}) *NotFoundError
NewNotFoundError creates a new NotFoundError with the given entity and identifier.
func (*NotFoundError) Error ¶
func (e *NotFoundError) Error() string
type QueryPlan ¶ added in v1.1.0
type QueryPlan struct {
Query int `json:"query"`
SQL string `json:"sql"`
Plan []map[string]interface{} `json:"plan"`
ExecutionMS float64 `json:"execution_ms,omitempty"`
PlanningMS float64 `json:"planning_ms,omitempty"`
}
QueryPlan represents a captured query execution plan from EXPLAIN ANALYZE. It stores the SQL statement, the full JSON plan output, and timing metrics for use in golden test comparisons.
type RetryOption ¶ added in v1.3.0
type RetryOption func(*retryConfig)
RetryOption configures retry behavior for operations.
func WithBackoffMultiplier ¶ added in v1.3.0
func WithBackoffMultiplier(m float64) RetryOption
WithBackoffMultiplier sets the multiplier for exponential backoff.
func WithBaseDelay ¶ added in v1.3.0
func WithBaseDelay(d time.Duration) RetryOption
WithBaseDelay sets the initial delay between retries.
func WithMaxDelay ¶ added in v1.3.0
func WithMaxDelay(d time.Duration) RetryOption
WithMaxDelay sets the maximum delay between retries.
func WithMaxRetries ¶ added in v1.3.0
func WithMaxRetries(n int) RetryOption
WithMaxRetries sets the maximum number of retry attempts.
type TestDB ¶ added in v1.1.0
type TestDB struct {
*DB
}
TestDB is a testing utility that wraps DB with testing-specific functionality. It provides simple methods for test setup, cleanup, and golden test support. TestDB automatically manages test database connections and provides utilities for performance regression testing through golden tests.
func NewTestDB ¶ added in v1.1.0
func NewTestDB() *TestDB
NewTestDB creates a new unconnected TestDB instance. Call Connect() to establish the database connection.
Example:
func TestUserOperations(t *testing.T) {
testDB := pgxkit.NewTestDB()
err := testDB.Connect(context.Background(), "") // uses TEST_DATABASE_URL env var
if err != nil {
t.Skip("Test database not available")
}
defer testDB.Shutdown(context.Background())
// ... test code
}
func RequireDB ¶ added in v1.1.0
RequireDB ensures a test database is available or skips the test. It creates a TestDB and connects using TEST_DATABASE_URL environment variable.
func (*TestDB) Clean ¶ added in v1.1.0
Clean performs cleanup operations after a test completes. It verifies the database connection is still active and can be extended to truncate tables or reset test data. Returns nil if no pool is configured.
func (*TestDB) EnableGolden ¶ added in v1.1.0
EnableGolden returns a new DB instance configured with golden test hooks. Golden tests capture EXPLAIN ANALYZE output for each query, enabling detection of query plan regressions. The testName is used to name the golden file. Use AssertGolden after test execution to compare against baseline plans.
Example:
goldenDB := testDB.EnableGolden("user_queries")
// run queries using goldenDB
goldenDB.AssertGolden(t, "user_queries")
func (*TestDB) Setup ¶ added in v1.1.0
Setup prepares the database for testing. This method verifies the database connection and can be extended to seed data or perform other test setup tasks. Returns an error if the database is not available or not ready for testing.
Example:
err := testDB.Setup()
if err != nil {
t.Skip("Test database not available")
}
type ValidationError ¶
ValidationError represents validation failures that occur before database operations. Use this for input validation, constraint violations, or business rule failures.
func NewValidationError ¶
func NewValidationError(entity, operation, field, reason string, err error) *ValidationError
NewValidationError creates a new ValidationError with the given parameters.
func (*ValidationError) Error ¶
func (e *ValidationError) Error() string
func (*ValidationError) Unwrap ¶
func (e *ValidationError) Unwrap() error