package store import ( "database/sql" "fmt" "time" ) // Option configures Open. type Option func(*options) type options struct { autoMigrate bool changeBatchRetention time.Duration } // OpenDB opens the SQLite database at path with the store's connection // settings (foreign keys, WAL, busy timeout, immediate transactions). The // file is created on first use. Use it for anything that works on the store's // database directly, such as running migrations. func OpenDB(path string) (*sql.DB, error) { return sql.Open("sqlite3", dsn(path)) } // WithAutoMigrate makes Open apply pending migrations instead of returning // ErrNeedsMigration. Intended for tests and throwaway databases; applications // should migrate explicitly with the migrate command. func WithAutoMigrate() Option { return func(opts *options) { opts.autoMigrate = true } } // WithChangeBatchRetention makes the store delete change batches older than // retention whenever it records a new one, so a client can catch up from a // batch for that long (see ListChangedOpportunities). Without it, or with 0 // or less, batches are kept for ever. func WithChangeBatchRetention(retention time.Duration) Option { return func(opts *options) { opts.changeBatchRetention = retention } } // dsn builds the mattn/go-sqlite3 connection string. // // - _foreign_keys: SQLite ignores REFERENCES clauses unless this is on. // - _journal_mode=WAL: readers don't block the writer or each other. // - _busy_timeout: wait for a lock rather than failing immediately. // - _txlock=immediate: transactions take the write lock at BEGIN, so a // read-then-write transaction (as in SaveOpportunity) can't fail with // SQLITE_BUSY halfway through. func dsn(path string) string { return fmt.Sprintf( "file:%s?_foreign_keys=on&_journal_mode=WAL&_busy_timeout=5000&_txlock=immediate", path, ) }