Files
mysql/CHANGELOG.md
Rene Nochebuena d9d07bcb70 feat(mysql): initial stable release v0.9.0
database/sql-backed MySQL client with launcher lifecycle, health check, unit-of-work via context injection, and structured error mapping.

What's included:
- Executor / Tx / Client / Component interfaces using database/sql native types (sql.Result, *sql.Rows, *sql.Row)
- Tx.Commit() / Tx.Rollback() without ctx, matching the honest database/sql contract
- New(logger, cfg) constructor; *sql.DB opened in OnInit
- Config struct with env-tag support for all pool tuning parameters
- UnitOfWork via context injection; GetExecutor(ctx) returns active *sql.Tx or *sql.DB
- HandleError mapping MySQLError.Number to xerrors codes (1062 → AlreadyExists, 1216/1217/1451/1452 → InvalidInput, ErrNoRows → NotFound)
- Driver imported as mysqldrv alias to avoid package name collision
- health.Checkable at LevelCritical; HealthCheck delegates to db.PingContext

Tested-via: todo-api POC integration
Reviewed-against: docs/adr/
2026-03-19 13:21:34 +00:00

3.2 KiB

Changelog

All notable changes to this module will be documented in this file.

The format is based on Keep a Changelog, and this module adheres to Semantic Versioning.

0.9.0 - 2026-03-18

Added

  • Executor interface: ExecContext, QueryContext, QueryRowContext using database/sql types (sql.Result, *sql.Rows, *sql.Row).
  • Tx interface: embeds Executor and adds Commit() error and Rollback() error (no context argument, matching database/sql semantics).
  • Client interface: GetExecutor(ctx context.Context) Executor, Begin(ctx context.Context) (Tx, error), Ping(ctx context.Context) error, HandleError(err error) error.
  • Component interface: composes launcher.Component, health.Checkable, and Client.
  • UnitOfWork interface: Do(ctx context.Context, fn func(ctx context.Context) error) error.
  • Config struct: fields Host, Port, User, Password, Name, MaxConns, MinConns, MaxConnLifetime, MaxConnIdleTime; settable via MYSQL_* environment variables with defaults (port 3306, max conns 5, idle conns 2, lifetime 1h, idle time 30m).
  • Config.DSN() string: constructs a go-sql-driver DSN in user:pass@tcp(host:port)/db?parseTime=true&loc=UTC format.
  • New(logger logz.Logger, cfg Config) Component: returns a *sql.DB-backed component; the connection is opened lazily in OnInit.
  • Lifecycle hooks: OnInit calls sql.Open, sets pool limits, and parses duration config fields; OnStart pings with a 5-second timeout; OnStop closes the *sql.DB.
  • health.Checkable implementation: HealthCheck delegates to Ping; Name() returns "mysql"; Priority() returns health.LevelCritical.
  • NewUnitOfWork(logger logz.Logger, client Client) UnitOfWork: wraps a Client to provide transactional Do semantics; rolls back and logs on error, commits on success.
  • HandleError(err error) error (package-level function): maps *mysqldrv.MySQLError error numbers to xerrors — 1062 (duplicate entry) → ErrAlreadyExists; 1216, 1217, 1451, 1452 (foreign key violations) → ErrInvalidInput; sql.ErrNoRowsErrNotFound; all other errors → ErrInternal.
  • Transaction context injection: the active *sql.Tx is stored under an unexported ctxTxKey{} context key; GetExecutor returns it when found, otherwise returns *sql.DB.
  • All *sql.DB reads guarded by sync.RWMutex for safe concurrent access.
  • go-sql-driver/mysql is imported with a blank identifier in mysql.go for driver side-effect registration, and as mysqldrv in errors.go to avoid the package name collision.

Design Notes

  • Tx.Commit() and Tx.Rollback() intentionally omit a context.Context argument, honestly reflecting the database/sql limitation rather than accepting and ignoring one.
  • The module is structurally parallel to postgres but uses database/sql types throughout; the two modules are intentionally type-incompatible.
  • MySQL error codes are matched by numeric constant via MySQLError.Number, not by string parsing, for stability across MySQL and MariaDB versions.