34 lines
3.3 KiB
Markdown
34 lines
3.3 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.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 `Path` (`SQLITE_PATH`), `MaxOpenConns` (default `1`), `MaxIdleConns` (default `1`), `Pragmas` (default `?_journal=WAL&_timeout=5000&_fk=true`); settable via `SQLITE_*` environment variables.
|
||
|
|
- `New(logger logz.Logger, cfg Config) Component`: returns a pure-Go SQLite component backed by `modernc.org/sqlite`; no CGO required.
|
||
|
|
- Lifecycle hooks: `OnInit` opens the database, sets connection limits, and enforces `PRAGMA foreign_keys = ON`; startup fails if the pragma cannot be set. `OnStart` pings with a 5-second timeout. `OnStop` closes the connection.
|
||
|
|
- `health.Checkable` implementation: `HealthCheck` delegates to `Ping`; `Name()` returns `"sqlite"`; `Priority()` returns `health.LevelCritical`.
|
||
|
|
- `NewUnitOfWork(logger logz.Logger, client Client) UnitOfWork`: wraps a `Client` to provide transactional `Do` semantics. When the client is the concrete `*sqliteComponent`, the write mutex is acquired for the duration of `Do` to serialise concurrent write transactions and prevent `SQLITE_BUSY`.
|
||
|
|
- `HandleError(err error) error` (package-level function): maps SQLite extended error codes via a duck-typed `coder` interface — code `2067` (unique constraint) and `1555` (primary key constraint) → `ErrAlreadyExists`; code `787` (foreign key constraint) → `ErrInvalidInput`; `sql.ErrNoRows` → `ErrNotFound`; all others → `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`.
|
||
|
|
- WAL journal mode, 5-second busy timeout, and foreign key enforcement enabled by default via the `Pragmas` DSN suffix.
|
||
|
|
- Support for in-memory databases via `Config{Path: ":memory:"}` for test isolation.
|
||
|
|
|
||
|
|
### Design Notes
|
||
|
|
|
||
|
|
- `modernc.org/sqlite` (pure Go, no CGO) is used instead of `mattn/go-sqlite3`, enabling cross-compilation with `CGO_ENABLED=0` and no system library dependency.
|
||
|
|
- A `sync.Mutex` (`writeMu`) on the component serialises all `UnitOfWork.Do` calls, preventing `SQLITE_BUSY` errors that arise from SQLite's single-writer constraint without requiring callers to manage locking.
|
||
|
|
- Foreign key enforcement is applied both via the `_fk=true` DSN pragma and an explicit `PRAGMA foreign_keys = ON` statement in `OnInit`, ensuring enforcement is active regardless of driver-level pragma handling.
|
||
|
|
|
||
|
|
[0.9.0]: https://com.nochebuena.dev/go/sqlite/releases/tag/v0.9.0
|