1package db
2
3import (
4 "context"
5 "database/sql"
6 "embed"
7 "fmt"
8 "log/slog"
9 "path/filepath"
10 "testing"
11
12 "github.com/pressly/goose/v3"
13)
14
15var pragmas = map[string]string{
16 "foreign_keys": "ON",
17 "journal_mode": "WAL",
18 "page_size": "4096",
19 "cache_size": "-8000",
20 "synchronous": "NORMAL",
21 "secure_delete": "ON",
22 "busy_timeout": "30000",
23}
24
25//go:embed migrations/*.sql
26var FS embed.FS
27
28func init() {
29 goose.SetBaseFS(FS)
30
31 if testing.Testing() {
32 goose.SetLogger(goose.NopLogger())
33 }
34}
35
36// Connect opens a SQLite database connection and runs migrations.
37func Connect(ctx context.Context, dataDir string) (*sql.DB, error) {
38 if dataDir == "" {
39 return nil, fmt.Errorf("data.dir is not set")
40 }
41 dbPath := filepath.Join(dataDir, "crush.db")
42
43 db, err := openDB(dbPath)
44 if err != nil {
45 return nil, err
46 }
47
48 if err = db.PingContext(ctx); err != nil {
49 db.Close()
50 return nil, fmt.Errorf("failed to connect to database: %w", err)
51 }
52
53 if err := goose.SetDialect("sqlite3"); err != nil {
54 slog.Error("Failed to set dialect", "error", err)
55 return nil, fmt.Errorf("failed to set dialect: %w", err)
56 }
57
58 if err := goose.Up(db, "migrations"); err != nil {
59 slog.Error("Failed to apply migrations", "error", err)
60 return nil, fmt.Errorf("failed to apply migrations: %w", err)
61 }
62
63 return db, nil
64}