> Not every hall needs pillars that reach the sky. Sometimes what matters fits in a single room, carried wherever the warrior goes.
`code.nochebuena.dev/einherjar/db-sqlite` is the SQLite database component of the Einherjar framework. It uses the pure-Go `modernc.org/sqlite` driver (no CGO, cross-compilation works without a C toolchain), wraps `database/sql` behind a lifecycle-aware `Component`, and serializes writes through a mutex to prevent `SQLITE_BUSY` under concurrent goroutines. WAL mode is enabled by default.
// GetExecutor returns the pool when called outside a UnitOfWork.
rows,err:=db.GetExecutor(ctx).QueryContext(ctx,"SELECT id, name FROM users WHERE active = ?",true)
deferrows.Close()
varnamestring
err:=db.GetExecutor(ctx).QueryRowContext(ctx,"SELECT name FROM users WHERE id = ?",id).Scan(&name)
```
### Manual transaction
```go
tx,err:=db.Begin(ctx)
iferr!=nil{
returnerr
}
defertx.Rollback()
_,err=tx.ExecContext(ctx,"UPDATE accounts SET balance = balance - ? WHERE id = ?",amount,fromID)
iferr!=nil{
returnerr
}
returntx.Commit()
```
Note: `Commit` and `Rollback` do not accept a context — this is a `database/sql` limitation.
### Unit of work (recommended)
`UnitOfWork` wraps the transaction in context so every call to `GetExecutor` inside `uow.Do` automatically returns the active transaction. The internal write mutex prevents concurrent `SQLITE_BUSY` errors; only one goroutine can write at a time.
```go
uow:=dbsqlite.NewUnitOfWork(logger,db)
err:=uow.Do(ctx,func(ctxcontext.Context)error{
_,err:=db.GetExecutor(ctx).ExecContext(ctx,"INSERT INTO orders (...) VALUES (...)",...)
returnerr
})
```
If the function returns an error, the transaction is rolled back. If it returns nil, the transaction is committed.
### Error handling
```go
iferr:=db.HandleError(someErr);err!=nil{
// SQLite error codes mapped to xerrors:
// UNIQUE constraint failed → ErrAlreadyExists
// FOREIGN KEY constraint → ErrPreconditionFailed
// NOT NULL constraint → ErrInvalidInput
// context.Canceled → ErrCancelled
// context.DeadlineExceeded → ErrDeadlineExceeded
}
```
`HandleError` is also available as a package-level function: `dbsqlite.HandleError(err)`.
---
## Environment variables
| Variable | Required | Default | Description |
|---|---|---|---|
| `EINHERJAR_SQLITE_PATH` | Yes | — | Path to the SQLite database file |
| `EINHERJAR_SQLITE_MAX_OPEN_CONNS` | No | `1` | Maximum open connections (keep at 1 for writes) |
| `EINHERJAR_SQLITE_MAX_IDLE_CONNS` | No | `1` | Maximum idle connections |