Factos Sqlight
factos_sqlight stores Factos events in SQLite through
sqlight. It is intended for embedded,
single-process applications that want the same model and decision-context API as
other Factos backends.
Setup
Apply priv/migrations.sql, or copy it into your application migration history.
The schema contains one append-only factos_events table.
Configure and dispatch
let model = user.model()
let configuration = factos_sqlight.configure(model, connection: connection)
configuration
|> factos_sqlight.dispatch(
command,
decision_context: user.decision_context(command),
event_id: new_event_id,
)
Dispatch uses BEGIN IMMEDIATE, so the context read, event append, and
subscriptions share one SQLite transaction.
Transactional subscriptions
let projection =
factos.subscription(fn(connection, recorded) {
use _ <- result.try(projection.apply(connection, recorded))
Ok(connection)
})
let configuration =
factos_sqlight.Configuration(
..factos_sqlight.configure(model, connection: connection),
subscriptions: [projection],
)
A subscription failure rolls back the event append and all subscription writes.
Simulate projections
Use factos/factos_sqlight/simulate to run the same subscriptions from an
in-memory domain scenario against a real SQLite projection database:
import factos/factos_sqlight/simulate as simulate_sqlight
simulate_sqlight.new(
model,
connection:,
subscriptions: [projection],
)
|> simulate.given(existing_events)
|> simulate.dispatch(decision_context:, command:)
|> simulate.assert_errors([])
assert Ok(rows) = projection.load(connection)
Each accepted event batch runs in its own BEGIN IMMEDIATE transaction.
Subscription or transaction failure rolls back projection writes and leaves the
batch out of simulated history. The simulator does not write the SQLite event
log; event-store atomicity and locking remain dispatch integration concerns.
Durable work
There is no built-in M25 equivalent for SQLite. Persist application-owned jobs through a transactional subscription, then process them after commit with a supervised worker. External IO must not run inside a retryable dispatch.
Recovery reads
read_after returns a bounded page in global position order for rebuilds and
application-owned recovery.
Development
trellis run test factos_sqlight
See How factos_sqlight works for locking and retry details.