Files
mysql/CHANGELOG.md
Rene Nochebuena 9d8762458c feat(config): expose charset, loc, and parseTime as configurable DSN parameters
- add Config.Charset (MYSQL_CHARSET, default "utf8mb4"): connection character set
  sent as SET NAMES during handshake; previously hardcoded
- add Config.Loc (MYSQL_LOC, default "UTC"): IANA timezone for time.Time ↔
  DATE/DATETIME conversion; previously hardcoded
- add Config.ParseTime (MYSQL_PARSE_TIME, default "true"): driver-level DATE/DATETIME
  → time.Time mapping; valid values "true"/"false"; previously hardcoded
- update DSN() to derive parameters from Config fields with empty-means-default
  semantics; existing Config literals produce identical DSN output (backward compatible)
- remove unused url.URL construction from DSN(); params now built directly via url.Values
- document collation DSN limitation in Config godoc, CLAUDE.md, RELEASE.md, CHANGELOG.md:
  go-sql-driver v1.8.x uses 1-byte handshake collation IDs (max 255); MariaDB 11.4+
  collations such as utf8mb4_uca1400_as_cs exceed that range — set collation at the
  database/table level in schema migrations instead
2026-03-20 14:12:24 -06:00

4.7 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.1 - 2026-03-20

Added

  • Config.Charset string (MYSQL_CHARSET, default "utf8mb4"): connection character set, sent as SET NAMES <charset> during handshake. Previously hardcoded to utf8mb4.
  • Config.Loc string (MYSQL_LOC, default "UTC"): IANA timezone name used for time.TimeDATE/DATETIME conversion. Previously hardcoded to UTC.
  • Config.ParseTime string (MYSQL_PARSE_TIME, default "true"): controls driver-level DATE/DATETIMEtime.Time mapping. Valid values "true" / "false". Previously hardcoded to true.

Changed

  • Config.DSN(): now derives charset, loc, and parseTime from the new Config fields instead of hardcoded literals. Empty fields fall back to their respective defaults, preserving identical DSN output for callers that do not set the new fields.
  • Removed unused net/url.URL construction from DSN(); the method now builds params directly with url.Values.

Notes

  • Backward compatible. Existing Config literals that do not set Charset, Loc, or ParseTime produce the same DSN as v0.9.0 (charset=utf8mb4&loc=UTC&parseTime=true).
  • Collation via DSN is not supported. go-sql-driver v1.8.x negotiates the collation using a 1-byte handshake ID (max 255). MariaDB 11.4+ collations such as utf8mb4_uca1400_as_cs carry IDs > 255 and will cause a connection error if set in the DSN. Set the desired collation in schema migrations at the database/table level.

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.