db: integrate golang-migrate for schema migrations
- internal/db/migrations/: five embedded SQL files containing
the migration SQL previously held as Go string literals.
Files follow the NNN_description.up.sql naming convention
required by golang-migrate's iofs source.
- internal/db/migrate.go: rewritten to use
github.com/golang-migrate/migrate/v4 with the
database/sqlite driver (modernc.org/sqlite, pure Go) and
source/iofs for compile-time embedded SQL.
- newMigrate() opens a dedicated *sql.DB so m.Close() does
not affect the caller's shared connection.
- Migrate() includes a compatibility shim: reads the legacy
schema_version table and calls m.Force(v) before m.Up()
so existing databases are not re-migrated.
- LatestSchemaVersion promoted from var to const.
- internal/db/db.go: added path field to DB struct; Open()
translates ':memory:' to a named shared-cache URI
(file:mcias_N?mode=memory&cache=shared) so the migration
runner can open a second connection to the same in-memory
database without sharing the handle that golang-migrate
will close on teardown.
- go.mod: added golang-migrate/migrate/v4 v4.19.1 (direct).
All callers unchanged. All tests pass; golangci-lint clean.
This commit is contained in:
@@ -12,19 +12,36 @@ import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
_ "modernc.org/sqlite" // register the sqlite3 driver
|
||||
)
|
||||
|
||||
// memCounter generates unique names for in-memory shared-cache databases.
|
||||
var memCounter atomic.Int64
|
||||
|
||||
// DB wraps a *sql.DB with MCIAS-specific helpers.
|
||||
type DB struct {
|
||||
sql *sql.DB
|
||||
// path is the DSN used to open this database. For in-memory databases
|
||||
// (originally ":memory:") it is a unique shared-cache URI of the form
|
||||
// file:mcias_N?mode=memory&cache=shared so that a second connection can be
|
||||
// opened to the same in-memory database (needed by the migration runner).
|
||||
path string
|
||||
}
|
||||
|
||||
// Open opens (or creates) the SQLite database at path and configures it for
|
||||
// MCIAS use (WAL mode, foreign keys, busy timeout).
|
||||
func Open(path string) (*DB, error) {
|
||||
// Translate bare ":memory:" to a named shared-cache in-memory URI.
|
||||
// This allows the migration runner to open a second connection to the
|
||||
// same in-memory database without sharing the *sql.DB handle (which
|
||||
// would be closed by golang-migrate when the migrator is done).
|
||||
if path == ":memory:" {
|
||||
path = fmt.Sprintf("file:mcias_%d?mode=memory&cache=shared", memCounter.Add(1))
|
||||
}
|
||||
|
||||
// The modernc.org/sqlite driver is registered as "sqlite".
|
||||
sqlDB, err := sql.Open("sqlite", path)
|
||||
if err != nil {
|
||||
@@ -34,7 +51,7 @@ func Open(path string) (*DB, error) {
|
||||
// Use a single connection for writes; reads can use the pool.
|
||||
sqlDB.SetMaxOpenConns(1)
|
||||
|
||||
db := &DB{sql: sqlDB}
|
||||
db := &DB{sql: sqlDB, path: path}
|
||||
if err := db.configure(); err != nil {
|
||||
_ = sqlDB.Close()
|
||||
return nil, err
|
||||
|
||||
Reference in New Issue
Block a user