package storage import ( "database/sql" _ "embed" "fmt" _ "modernc.org/sqlite" ) //go:embed schema.sql var schemaSQLBytes []byte // DB wraps the sql.DB connection with KeyHunter-specific behavior. type DB struct { sql *sql.DB } // Open opens or creates a SQLite database at path, runs embedded schema migrations, // and enables WAL mode for better concurrent read performance. // Use ":memory:" for tests. func Open(path string) (*DB, error) { sqlDB, err := sql.Open("sqlite", path) if err != nil { return nil, fmt.Errorf("opening database: %w", err) } // Enable WAL mode for concurrent reads if _, err := sqlDB.Exec("PRAGMA journal_mode=WAL"); err != nil { sqlDB.Close() return nil, fmt.Errorf("enabling WAL mode: %w", err) } // Enable foreign keys if _, err := sqlDB.Exec("PRAGMA foreign_keys=ON"); err != nil { sqlDB.Close() return nil, fmt.Errorf("enabling foreign keys: %w", err) } // Run schema migrations if _, err := sqlDB.Exec(string(schemaSQLBytes)); err != nil { sqlDB.Close() return nil, fmt.Errorf("running schema migrations: %w", err) } return &DB{sql: sqlDB}, nil } // Close closes the underlying database connection. func (db *DB) Close() error { return db.sql.Close() } // SQL returns the underlying sql.DB for advanced use cases. func (db *DB) SQL() *sql.DB { return db.sql }