db.go
⎇
Raw
1// Package db opens the SQLite database and holds the query layer.
2package db
3
4import (
5 "context"
6 "database/sql"
7 _ "embed"
8 "fmt"
9
10 _ "modernc.org/sqlite"
11)
12
13//go:embed schema.sql
14var Schema string
15
16// DB wraps *sql.DB. Other packages may run raw SQL through it.
17type DB struct {
18 *sql.DB
19}
20
21// Open opens (or creates) the database, applies schema.sql and migrations.
22func Open(path string) (*DB, error) {
23 sqlDB, err := sql.Open("sqlite", path+"?_pragma=journal_mode(WAL)&_pragma=busy_timeout(5000)&_pragma=foreign_keys(1)")
24 if err != nil {
25 return nil, err
26 }
27 // SQLite allows one writer. A single connection avoids SQLITE_BUSY
28 // between goroutines; busy_timeout covers external writers.
29 sqlDB.SetMaxOpenConns(1)
30 d := &DB{sqlDB}
31 if _, err := d.ExecContext(context.Background(), Schema); err != nil {
32 return nil, fmt.Errorf("apply schema: %w", err)
33 }
34 if err := d.migrate(context.Background()); err != nil {
35 return nil, fmt.Errorf("migrate: %w", err)
36 }
37 return d, nil
38}
39