connect.go

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