// Package store provides durable, pure-Go SQLite implementations of executus's // battery store seams (audit, budget, persona, skill). It is a SEPARATE nested // module so the SQLite driver (modernc.org/sqlite — pure Go, no cgo) never // enters the executus core go.sum: a static-binary host (gadfly) that imports // only the core stays static, while a host that wants turnkey persistence // imports this module and gets every *Store seam backed by one SQLite file. // // db, _ := store.Open("file:executus.db?_pragma=busy_timeout(5000)") // defer db.Close() // budgetStore := db.Budget() // satisfies budget.BudgetStorage package store import ( "database/sql" "fmt" _ "modernc.org/sqlite" // pure-Go driver, registered as "sqlite" ) // DB is a handle to one SQLite database backing the executus store seams. Each // accessor (Budget(), …) returns a seam implementation sharing this connection. // Safe for concurrent use (SQLite serializes writes; busy_timeout handles // contention). Construct with Open; close with Close. type DB struct { sql *sql.DB } // Open opens (creating if absent) a SQLite database at dsn and returns a DB. A // dsn of ":memory:" yields an ephemeral in-memory database. The caller owns the // returned DB and must Close it. func Open(dsn string) (*DB, error) { sqldb, err := sql.Open("sqlite", dsn) if err != nil { return nil, fmt.Errorf("store: open %q: %w", dsn, err) } // A contended writer should WAIT for the lock, not fail immediately — set a // busy_timeout so concurrent stores don't see spurious SQLITE_BUSY. (The // doc example advertised this; it's now actually applied for every DSN.) if _, err := sqldb.Exec("PRAGMA busy_timeout=5000"); err != nil { sqldb.Close() return nil, fmt.Errorf("store: set busy_timeout %q: %w", dsn, err) } if err := sqldb.Ping(); err != nil { sqldb.Close() return nil, fmt.Errorf("store: ping %q: %w", dsn, err) } return &DB{sql: sqldb}, nil } // Close closes the underlying database. func (d *DB) Close() error { return d.sql.Close() } // SQL exposes the underlying *sql.DB for hosts that need direct access. func (d *DB) SQL() *sql.DB { return d.sql }