Pure-Go CGO-free SQLite client with launcher lifecycle, write-mutex serialisation, 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 - Tx.Commit() / Tx.Rollback() without ctx, matching the honest database/sql contract - New(logger, cfg) constructor; database opened in OnInit - Config struct with env-tag support; default Pragmas: WAL + 5s busy timeout + FK enforcement - PRAGMA foreign_keys = ON enforced explicitly in OnInit - writeMu sync.Mutex acquired by UnitOfWork.Do to serialise writes and prevent SQLITE_BUSY - UnitOfWork via context injection; GetExecutor(ctx) returns active Tx or *sql.DB - HandleError mapping SQLite extended error codes to xerrors codes (unique/primary-key → AlreadyExists, foreign-key → InvalidInput, ErrNoRows → NotFound) - health.Checkable at LevelCritical; pure-Go modernc.org/sqlite driver (CGO_ENABLED=0 compatible) Tested-via: todo-api POC integration Reviewed-against: docs/adr/
3.3 KiB
3.3 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
Executorinterface:ExecContext,QueryContext,QueryRowContextusingdatabase/sqltypes (sql.Result,*sql.Rows,*sql.Row).Txinterface: embedsExecutorand addsCommit() errorandRollback() error(no context argument, matchingdatabase/sqlsemantics).Clientinterface:GetExecutor(ctx context.Context) Executor,Begin(ctx context.Context) (Tx, error),Ping(ctx context.Context) error,HandleError(err error) error.Componentinterface: composeslauncher.Component,health.Checkable, andClient.UnitOfWorkinterface:Do(ctx context.Context, fn func(ctx context.Context) error) error.Configstruct: fieldsPath(SQLITE_PATH),MaxOpenConns(default1),MaxIdleConns(default1),Pragmas(default?_journal=WAL&_timeout=5000&_fk=true); settable viaSQLITE_*environment variables.New(logger logz.Logger, cfg Config) Component: returns a pure-Go SQLite component backed bymodernc.org/sqlite; no CGO required.- Lifecycle hooks:
OnInitopens the database, sets connection limits, and enforcesPRAGMA foreign_keys = ON; startup fails if the pragma cannot be set.OnStartpings with a 5-second timeout.OnStopcloses the connection. health.Checkableimplementation:HealthCheckdelegates toPing;Name()returns"sqlite";Priority()returnshealth.LevelCritical.NewUnitOfWork(logger logz.Logger, client Client) UnitOfWork: wraps aClientto provide transactionalDosemantics. When the client is the concrete*sqliteComponent, the write mutex is acquired for the duration ofDoto serialise concurrent write transactions and preventSQLITE_BUSY.HandleError(err error) error(package-level function): maps SQLite extended error codes via a duck-typedcoderinterface — code2067(unique constraint) and1555(primary key constraint) →ErrAlreadyExists; code787(foreign key constraint) →ErrInvalidInput;sql.ErrNoRows→ErrNotFound; all others →ErrInternal.- Transaction context injection: the active
*sql.Txis stored under an unexportedctxTxKey{}context key;GetExecutorreturns it when found, otherwise returns*sql.DB. - WAL journal mode, 5-second busy timeout, and foreign key enforcement enabled by default via the
PragmasDSN 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 ofmattn/go-sqlite3, enabling cross-compilation withCGO_ENABLED=0and no system library dependency.- A
sync.Mutex(writeMu) on the component serialises allUnitOfWork.Docalls, preventingSQLITE_BUSYerrors that arise from SQLite's single-writer constraint without requiring callers to manage locking. - Foreign key enforcement is applied both via the
_fk=trueDSN pragma and an explicitPRAGMA foreign_keys = ONstatement inOnInit, ensuring enforcement is active regardless of driver-level pragma handling.