- 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
54 lines
4.7 KiB
Markdown
54 lines
4.7 KiB
Markdown
# Changelog
|
|
|
|
All notable changes to this module will be documented in this file.
|
|
|
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
and this module adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
|
## [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.Time` ↔ `DATE`/`DATETIME` conversion. Previously hardcoded to `UTC`.
|
|
- `Config.ParseTime string` (`MYSQL_PARSE_TIME`, default `"true"`): controls driver-level `DATE`/`DATETIME` → `time.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.ErrNoRows` → `ErrNotFound`; 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.
|
|
|
|
[0.9.1]: https://code.nochebuena.dev/go/mysql/releases/tag/v0.9.1
|
|
[0.9.0]: https://code.nochebuena.dev/go/mysql/releases/tag/v0.9.0
|