• v1.0.0 4d6d2f1d62

    Rene Nochebuena released this 2026-05-11 19:37:43 -06:00 | 1 commits to main since this release

    v1.0.0

    code.nochebuena.dev/go/postgres

    Overview

    postgres v1.0.0 commits the database client API as stable. All v0.9.0 roadmap items are
    resolved. The module ships a pgx v5-native PostgreSQL client that integrates with the launcher
    lifecycle and health check systems, maps PostgreSQL errors to portable xerrors codes, and
    provides UnitOfWork for transactional repository patterns via context injection.

    What Changed Since v0.9.0

    New in Client interface

    BeginTx(ctx context.Context, opts pgx.TxOptions) (Tx, error) — starts a transaction with
    explicit isolation level and read-only options using pgx-native pgx.TxOptions. Begin(ctx)
    is now a convenience wrapper calling BeginTx(ctx, pgx.TxOptions{}).

    tx, err := db.BeginTx(ctx, pgx.TxOptions{
        IsoLevel:   pgx.Serializable,
        AccessMode: pgx.ReadWrite,
    })
    

    New in Component interface

    Stats() *pgxpool.Stat — exposes connection pool metrics for observability. Returns a
    zero-value *pgxpool.Stat when called before OnInit. Useful for Prometheus gauges or
    health dashboards:

    stats := db.Stats()
    // stats.TotalConns(), stats.IdleConns(), stats.AcquiredConns(), stats.MaxConns()
    

    Dependency bumps

    All micro-lib dependencies promoted to v1.0.0: logz, health, launcher, xerrors.

    Roadmap items resolved

    Item Resolution
    BeginTx(ctx, opts) for serialisable isolation Added to Client with pgx.TxOptions; Begin refactored as wrapper
    Stats() for pool observability Added Stats() *pgxpool.Stat to Component
    SELECT 1 health check option No — pgxpool.Ping already acquires a real connection and does a round-trip; SELECT 1 adds no additional signal
    Production feedback on pool defaults Validated as-is — MaxConns=5, MinConns=2, 1h/30m/1m confirmed in production

    Full API (stable)

    ExecutorExec, Query, QueryRow using pgx v5 native types (pgconn.CommandTag, pgx.Rows, pgx.Row).

    Tx — extends Executor with Commit(ctx) error, Rollback(ctx) error.

    ClientGetExecutor(ctx) Executor, Begin(ctx) (Tx, error), BeginTx(ctx, pgx.TxOptions) (Tx, error), Ping(ctx) error, HandleError(err) error.

    Componentlauncher.Component + health.Checkable + Client + Stats() *pgxpool.Stat.

    UnitOfWorkDo(ctx, fn) error; injects active pgx.Tx via context.

    ConfigHost, Port, User, Password, Name, SSLMode, Timezone, MaxConns, MinConns, MaxConnLifetime, MaxConnIdleTime, HealthCheckPeriod; env-tag support.

    New(logger logz.Logger, cfg Config) Component — constructor; pool created in OnInit.

    NewUnitOfWork(logger logz.Logger, client Client) UnitOfWork — wraps a Client for transactional Do semantics.

    HandleError(err error) error — maps pgx/PostgreSQL errors to xerrors: UniqueViolationErrAlreadyExists; ForeignKeyViolation/CheckViolationErrInvalidInput; pgx.ErrNoRowsErrNotFound; others → ErrInternal.

    Migration from v0.9.0

    BeginTx is a new method on Client. Any type that implements Client must now also
    implement BeginTx. The existing Begin behavior is unchanged.

    Stats is a new method on Component. Any type that implements Component must now also
    implement Stats.

    go get code.nochebuena.dev/go/postgres@v1.0.0
    
    Downloads
  • v0.9.0 2baafa6a0c

    Rene Nochebuena released this 2026-03-19 07:18:59 -06:00 | 2 commits to main since this release

    v0.9.0

    code.nochebuena.dev/go/postgres

    Overview

    postgres is a pgx v5-native PostgreSQL client that integrates with the launcher lifecycle
    and health check systems. It manages a pgxpool connection pool, maps PostgreSQL errors to
    portable xerrors codes, and provides a UnitOfWork implementation that injects the active
    transaction into the context so repositories participate in transactions without explicit wiring.

    This is the first stable release. The API was designed through multiple architecture reviews
    and validated end-to-end via the todo-api proof-of-concept. It is versioned at v0.9.0 rather
    than v1.0.0 because the library has not yet been exercised in production across all edge cases;
    the pre-1.0 version preserves the option for minor API refinements without a major bump.

    What's Included

    • Executor interface: Exec, Query, QueryRow using pgx v5 native types
      (pgconn.CommandTag, pgx.Rows, pgx.Row)
    • Tx interface: extends Executor with Commit(ctx) / Rollback(ctx)
    • Client interface: GetExecutor(ctx), Begin(ctx), Ping(ctx), HandleError(err)
    • Component interface: composes launcher.Component, health.Checkable, and Client
    • New(logger, cfg) Component constructor; pool initialised in OnInit, not at construction
    • Config struct with env-tag support (PG_HOST, PG_PORT, PG_USER, PG_PASSWORD,
      PG_NAME, PG_SSL_MODE, PG_MAX_CONNS, PG_MIN_CONNS, connection lifetime fields)
    • UnitOfWork interface and NewUnitOfWork(logger, client) constructor using context injection
    • HandleError(err) error package-level function mapping pgx/PostgreSQL errors to xerrors:
      • UniqueViolationErrAlreadyExists with constraint name context
      • ForeignKeyViolationErrInvalidInput with table name context
      • CheckViolationErrInvalidInput with table and column context
      • pgx.ErrNoRowsErrNotFound
      • all other errors → ErrInternal
    • health.Checkable implementation at health.LevelCritical

    Installation

    go get code.nochebuena.dev/go/postgres@v0.9.0
    

    Requires Go 1.21 or later. Depends on code.nochebuena.dev/go/health,
    code.nochebuena.dev/go/launcher, code.nochebuena.dev/go/logz,
    code.nochebuena.dev/go/xerrors, and github.com/jackc/pgx/v5.

    Design Highlights

    pgx native types throughout. Executor uses pgconn.CommandTag, pgx.Rows, and
    pgx.Row directly. There is no database/sql adapter; this is an intentional design choice
    to give repository code access to pgx-specific features (named parameters, pgtype, etc.).

    No dbutil wrapper. Executor, Tx, Client, and Component are defined locally in
    this package using pgx types. The mysql module has its own independent Executor. The two
    are intentionally incompatible.

    UnitOfWork via context injection. NewUnitOfWork.Do begins a transaction, stores it in
    the context under an unexported key, and calls the provided function. GetExecutor(ctx) returns
    the transaction when one is present, otherwise the pool. Repositories need no awareness of
    whether they are inside a transaction.

    Error mapping by pgerrcode constants. HandleError uses errors.As to unwrap
    *pgconn.PgError and switches on pgerrcode constants, not message strings.

    Lifecycle-aware health check. HealthCheck delegates to Ping, which calls
    pgxpool.Pool.Ping. Priority is health.LevelCritical.

    Known Limitations & Edge Cases

    • No query builder. Repository code writes raw SQL strings. There is no DSL or prepared
      statement cache beyond what pgxpool provides natively.
    • No migration helper. Schema migrations are out of scope; use a dedicated tool such as
      golang-migrate or goose.
    • Health check uses pgxpool.Ping, not SELECT 1. Pool.Ping acquires a connection from
      the pool and calls the pgx-level ping. It does not execute a query, so it may not detect all
      forms of server-side unavailability.
    • Transaction stored in context is not safe to use after Do returns. Goroutines launched
      inside UnitOfWork.Do that outlive the callback will hold a reference to a committed or
      rolled-back transaction.

    v0.9.0 → v1.0.0 Roadmap

    • Evaluate adding a SELECT 1 health check option alongside the pool ping.
    • Consider exposing connection pool stats (idle, total, wait count) through the health check
      or a dedicated metrics hook.
    • Assess whether a BeginTx(ctx, opts) variant is needed for serialisable isolation.
    • Gather production feedback on connection pool defaults before hardening the config.
    Downloads