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