72 lines
1.7 KiB
Go
72 lines
1.7 KiB
Go
package db
|
|
|
|
import (
|
|
"database/sql"
|
|
"embed"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
_ "modernc.org/sqlite"
|
|
)
|
|
|
|
//go:embed migrations/*.sql
|
|
var migrations embed.FS
|
|
|
|
type Store struct {
|
|
*Queries
|
|
db *sql.DB
|
|
}
|
|
|
|
func Open() (*Store, error) {
|
|
home, err := os.UserHomeDir()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("home dir: %w", err)
|
|
}
|
|
dir := filepath.Join(home, ".config", "ai-agent")
|
|
if err := os.MkdirAll(dir, 0o755); err != nil {
|
|
return nil, fmt.Errorf("create config dir: %w", err)
|
|
}
|
|
return OpenPath(filepath.Join(dir, "ai-agent.db"))
|
|
}
|
|
|
|
func OpenPath(path string) (*Store, error) {
|
|
conn, err := sql.Open("sqlite", path+"?_journal_mode=WAL&_busy_timeout=5000&_foreign_keys=ON")
|
|
if err != nil {
|
|
return nil, fmt.Errorf("open db: %w", err)
|
|
}
|
|
if err := runMigrations(conn); err != nil {
|
|
conn.Close()
|
|
return nil, fmt.Errorf("migrations: %w", err)
|
|
}
|
|
return &Store{Queries: New(conn), db: conn}, nil
|
|
}
|
|
|
|
func (s *Store) Close() error {
|
|
return s.db.Close()
|
|
}
|
|
|
|
func (s *Store) DB() *sql.DB {
|
|
return s.db
|
|
}
|
|
|
|
func runMigrations(conn *sql.DB) error {
|
|
entries, err := migrations.ReadDir("migrations")
|
|
if err != nil {
|
|
return fmt.Errorf("read migrations dir: %w", err)
|
|
}
|
|
for _, entry := range entries {
|
|
if entry.IsDir() {
|
|
continue
|
|
}
|
|
data, err := migrations.ReadFile("migrations/" + entry.Name())
|
|
if err != nil {
|
|
return fmt.Errorf("read migration %s: %w", entry.Name(), err)
|
|
}
|
|
if _, err := conn.Exec(string(data)); err != nil {
|
|
return fmt.Errorf("exec migration %s: %w", entry.Name(), err)
|
|
}
|
|
}
|
|
return nil
|
|
}
|