feat(db): add SQLite schema, Store CRUD, ULID generation
Foundation layer: entities table with card support, entity_tags join table, WAL mode, busy_timeout, full CRUD operations including promote/demote lifecycle and soft/hard delete. 33 tests passing.
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func testStore(t *testing.T) *Store {
|
||||
t.Helper()
|
||||
path := filepath.Join(t.TempDir(), "test.db")
|
||||
s, err := Open(path)
|
||||
if err != nil {
|
||||
t.Fatalf("Open: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { s.Close() })
|
||||
return s
|
||||
}
|
||||
|
||||
func TestOpen_CreatesFile(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "test.db")
|
||||
s, err := Open(path)
|
||||
if err != nil {
|
||||
t.Fatalf("Open: %v", err)
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||
t.Fatal("database file not created")
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpen_WALMode(t *testing.T) {
|
||||
s := testStore(t)
|
||||
var mode string
|
||||
if err := s.db.QueryRow("PRAGMA journal_mode").Scan(&mode); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if mode != "wal" {
|
||||
t.Errorf("expected wal, got %s", mode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpen_ForeignKeys(t *testing.T) {
|
||||
s := testStore(t)
|
||||
var fk int
|
||||
if err := s.db.QueryRow("PRAGMA foreign_keys").Scan(&fk); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if fk != 1 {
|
||||
t.Errorf("expected foreign_keys=1, got %d", fk)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpen_MigrateIdempotent(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "test.db")
|
||||
s1, err := Open(path)
|
||||
if err != nil {
|
||||
t.Fatalf("first Open: %v", err)
|
||||
}
|
||||
s1.Close()
|
||||
|
||||
s2, err := Open(path)
|
||||
if err != nil {
|
||||
t.Fatalf("second Open: %v", err)
|
||||
}
|
||||
s2.Close()
|
||||
}
|
||||
|
||||
func TestDefaultPath_EnvOverride(t *testing.T) {
|
||||
want := "/tmp/custom-nib.db"
|
||||
t.Setenv("NIB_DB", want)
|
||||
got, err := DefaultPath()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got != want {
|
||||
t.Errorf("expected %s, got %s", want, got)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user