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