48 lines
1.4 KiB
Go
48 lines
1.4 KiB
Go
// Package db owns SQLite access for mCables: migrations runner + the
|
|
// query layer (store.go). The Store wraps a *sql.DB with helpers; tests
|
|
// and the HTTP layer take a *Store, never a raw *sql.DB.
|
|
package db
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
|
|
_ "modernc.org/sqlite"
|
|
)
|
|
|
|
// Open opens (or creates) the SQLite file at path and returns a Store
|
|
// with WAL + foreign keys + busy_timeout configured.
|
|
func Open(path string) (*Store, error) {
|
|
// `_pragma` query params are honoured by modernc.org/sqlite for
|
|
// connection-time PRAGMA setup. journal_mode WAL is persistent
|
|
// across opens; the others apply per-connection.
|
|
dsn := fmt.Sprintf(
|
|
"file:%s?_pragma=journal_mode(WAL)&_pragma=foreign_keys(ON)&_pragma=busy_timeout(5000)",
|
|
path,
|
|
)
|
|
d, err := sql.Open("sqlite", dsn)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("open sqlite: %w", err)
|
|
}
|
|
if err := d.Ping(); err != nil {
|
|
_ = d.Close()
|
|
return nil, fmt.Errorf("ping sqlite: %w", err)
|
|
}
|
|
// Single writer keeps things deterministic for a local-LAN tool;
|
|
// reads scale fine in WAL.
|
|
d.SetMaxOpenConns(1)
|
|
return &Store{db: d}, nil
|
|
}
|
|
|
|
// Store is the application's handle on the SQLite database.
|
|
type Store struct {
|
|
db *sql.DB
|
|
}
|
|
|
|
// DB returns the underlying *sql.DB. Used by Migrate and (sparingly) by
|
|
// callers that need a raw query escape hatch.
|
|
func (s *Store) DB() *sql.DB { return s.db }
|
|
|
|
// Close releases the database.
|
|
func (s *Store) Close() error { return s.db.Close() }
|