Full project rename per m's call. Single atomic commit because the codebase rename is a coupled change — go module path, env vars, DB default, Docker artefact names, and on-disk mDock paths all flip together. - go.mod: module mgit.msbls.de/m/mcables → mgit.msbls.de/m/cablegui - cmd/mcables → cmd/cablegui (git mv) - All Go imports rewritten to the new module path - Env vars: MCABLES_ADDR/MCABLES_DB → CABLEGUI_ADDR/CABLEGUI_DB - DB default path: data/mcables.db → data/cablegui.db - Dockerfile + docker-compose.yml: image, container_name, env vars, bind-mount /home/m/stacks/mcables → /home/m/stacks/cablegui, secrets /home/m/secrets/mcables → /home/m/secrets/cablegui - Makefile: bin target + run/build commands point at cmd/cablegui - .gitignore + .dockerignore: /mcables → /cablegui - README, docs/design.md, CLAUDE.md: prose + paths + image name - web/static/index.html: <title> + brand - web/static/main.js + web/web.go: header comment - internal/exporter: Scene.Source "mcables" → "cablegui" - internal/server/export.go: error-detail secrets path - internal/db/migrations/*.sql: header comments (mCables vN → CableGUI vN) Memory group_id kept as "mcables" to preserve existing memory continuity. Documented as historical in CLAUDE.md. go build ./... clean; go test -race ./... green
48 lines
1.4 KiB
Go
48 lines
1.4 KiB
Go
// Package db owns SQLite access for CableGUI: 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() }
|