8d98faccd9
Añade sistema de proposals al registry: modelos (ProposalKind, ProposalStatus), CRUD completo (Insert/Get/Update/Delete/List/Search con FTS), validación, migración 002_proposals.sql y subcomando CLI fn proposal (add/list/show/update). Motor de migraciones con embed.FS reemplaza schema estático. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
54 lines
1.1 KiB
Go
54 lines
1.1 KiB
Go
package registry
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
_ "github.com/mattn/go-sqlite3"
|
|
)
|
|
|
|
// DB wraps a SQLite connection for the registry.
|
|
type DB struct {
|
|
conn *sql.DB
|
|
path string
|
|
}
|
|
|
|
// Open opens or creates the registry database at the given path.
|
|
func Open(path string) (*DB, error) {
|
|
dir := filepath.Dir(path)
|
|
if err := os.MkdirAll(dir, 0o755); err != nil {
|
|
return nil, fmt.Errorf("creating db directory: %w", err)
|
|
}
|
|
|
|
conn, err := sql.Open("sqlite3", path+"?_foreign_keys=on")
|
|
if err != nil {
|
|
return nil, fmt.Errorf("opening database: %w", err)
|
|
}
|
|
|
|
// WAL mode: enables concurrent reads while writing.
|
|
if _, err := conn.Exec("PRAGMA journal_mode=WAL"); err != nil {
|
|
conn.Close()
|
|
return nil, fmt.Errorf("setting WAL mode: %w", err)
|
|
}
|
|
|
|
if err := migrate(conn); err != nil {
|
|
conn.Close()
|
|
return nil, fmt.Errorf("running migrations: %w", err)
|
|
}
|
|
|
|
return &DB{conn: conn, path: path}, nil
|
|
}
|
|
|
|
// Close closes the database connection.
|
|
func (db *DB) Close() error {
|
|
return db.conn.Close()
|
|
}
|
|
|
|
// Drop removes the database file. Used by `fn index` to regenerate.
|
|
func (db *DB) Drop() error {
|
|
db.Close()
|
|
return os.Remove(db.path)
|
|
}
|