• v0.9.0 d9d07bcb70

    Release 0.9.0 Stable

    Rene Nochebuena released this 2026-03-19 07:22:21 -06:00 | 1 commits to main since this release

    v0.9.0

    code.nochebuena.dev/go/mysql

    Overview

    mysql is a database/sql-backed MySQL client that integrates with the launcher lifecycle
    and health check systems. It manages a *sql.DB connection pool, maps MySQL driver 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: ExecContext, QueryContext, QueryRowContext using database/sql
      native types (sql.Result, *sql.Rows, *sql.Row)
    • Tx interface: extends Executor with Commit() / Rollback() — no context arguments,
      matching the honest database/sql contract
    • 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 opened in OnInit, not at construction
    • Config struct with env-tag support (MYSQL_HOST, MYSQL_PORT, MYSQL_USER,
      MYSQL_PASSWORD, MYSQL_NAME, MYSQL_MAX_CONNS, MYSQL_MIN_CONNS, connection lifetime fields)
    • UnitOfWork interface and NewUnitOfWork(logger, client) constructor using context injection
    • HandleError(err) error package-level function mapping MySQL errors to xerrors:
      • Error 1062 (ER_DUP_ENTRY) → ErrAlreadyExists
      • Errors 1216, 1217, 1451, 1452 (foreign key violations) → ErrInvalidInput
      • sql.ErrNoRowsErrNotFound
      • all other errors → ErrInternal
    • Driver imported as mysqldrv alias in errors.go to avoid name collision with this package
    • health.Checkable implementation at health.LevelCritical

    Installation

    go get code.nochebuena.dev/go/mysql@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/go-sql-driver/mysql.

    Design Highlights

    database/sql native types throughout. Executor uses sql.Result, *sql.Rows, and
    *sql.Row. Method names follow database/sql convention (ExecContext, QueryContext,
    QueryRowContext). This is intentionally distinct from the postgres module, which uses pgx
    types.

    Honest Tx contract. database/sql does not support per-call context on Commit or
    Rollback. The Tx interface reflects this honestly — Commit() and Rollback() take no
    context — rather than accepting a context argument and silently ignoring it.

    Driver alias prevents name collision. The go-sql-driver/mysql package name would
    collide with this package's name mysql. In errors.go it is imported as mysqldrv; in
    mysql.go it is imported with _ for side-effect driver registration only.

    UnitOfWork via context injection. Same pattern as the postgres module: the active
    *sql.Tx is stored under an unexported ctxTxKey{} in the context. GetExecutor(ctx) returns
    the transaction if present, otherwise *sql.DB.

    Error mapping by error number. HandleError type-asserts to *mysqldrv.MySQLError and
    switches on .Number — not message strings — to map driver errors to xerrors codes.

    Known Limitations & Edge Cases

    • No context on Tx.Commit() / Tx.Rollback(). database/sql does not support it. A
      commit or rollback cannot be cancelled by a deadline or context cancellation.
    • No query builder. Repository code writes raw SQL strings.
    • No migration helper. Schema migrations are out of scope.
    • parseTime=true and loc=UTC are hardcoded in the DSN. Applications that need a
      different timezone or raw time bytes must construct their own DSN.

    v0.9.0 → v1.0.0 Roadmap

    • Evaluate whether DSN parameters (parseTime, loc) should be exposed in Config.
    • Consider adding a BeginTx(ctx, opts) variant for explicit transaction isolation levels.
    • Gather production feedback on connection pool defaults before hardening the config.
    • Assess whether *sql.DB stats (OpenConnections, WaitCount) should be surfaced for observability.
    Downloads