connect.go

 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}