Files
orm/adapter_test.go
zeekay bfd5b60d78 Add SQLite adapter bridging db.SQLiteDB to orm.DB
OpenSQLite() and AdaptDB() bridge concrete db.DB drivers to the
root orm.DB interface with key wrappers (bridgeKey/reverseKey) and
query translation (ById/IdExists/KeyExists built on Get).
9 integration tests prove end-to-end Model[T] + SQLite storage.
2026-02-23 16:19:17 -08:00

256 lines
5.0 KiB
Go

package orm
import (
"path/filepath"
"testing"
ormdb "github.com/hanzoai/orm/db"
)
type intgUser struct {
Model[intgUser]
Name string `json:"name"`
Email string `json:"email"`
Age int `json:"age"`
}
type intgHooked struct {
Model[intgHooked]
Name string `json:"name"`
BeforeHook bool `json:"beforeHook,omitempty"`
AfterHook bool `json:"afterHook,omitempty"`
}
func (h *intgHooked) BeforeCreate() error {
h.BeforeHook = true
return nil
}
func (h *intgHooked) AfterCreate() error {
h.AfterHook = true
return nil
}
func init() {
Register[intgUser]("intg-user")
Register[intgHooked]("intg-hooked")
}
func newTestSQLite(t *testing.T) DB {
t.Helper()
db, err := OpenSQLite(&ormdb.SQLiteDBConfig{
Path: filepath.Join(t.TempDir(), "test.db"),
Config: ormdb.SQLiteConfig{BusyTimeout: 5000, JournalMode: "WAL"},
})
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { db.Close() })
return db
}
func TestSQLiteAdapterCreate(t *testing.T) {
db := newTestSQLite(t)
user := New[intgUser](db)
user.Name = "Alice"
user.Email = "[email protected]"
user.Age = 30
if err := user.Create(); err != nil {
t.Fatal("Create failed:", err)
}
if user.Id() == "" {
t.Error("expected non-empty ID after create")
}
if user.CreatedAt.IsZero() {
t.Error("expected CreatedAt to be set")
}
}
func TestSQLiteAdapterGetById(t *testing.T) {
db := newTestSQLite(t)
user := New[intgUser](db)
user.Name = "Bob"
user.Email = "[email protected]"
user.Age = 25
if err := user.Create(); err != nil {
t.Fatal(err)
}
got, err := Get[intgUser](db, user.Id())
if err != nil {
t.Fatal("Get failed:", err)
}
if got.Name != "Bob" {
t.Errorf("expected Bob, got %s", got.Name)
}
if got.Email != "[email protected]" {
t.Errorf("expected [email protected], got %s", got.Email)
}
if got.Age != 25 {
t.Errorf("expected age 25, got %d", got.Age)
}
}
func TestSQLiteAdapterUpdate(t *testing.T) {
db := newTestSQLite(t)
user := New[intgUser](db)
user.Name = "Charlie"
user.Email = "[email protected]"
user.Age = 35
if err := user.Create(); err != nil {
t.Fatal(err)
}
got, err := Get[intgUser](db, user.Id())
if err != nil {
t.Fatal(err)
}
got.Name = "Charlie Updated"
got.Age = 36
if err := got.Update(); err != nil {
t.Fatal("Update failed:", err)
}
got2, err := Get[intgUser](db, user.Id())
if err != nil {
t.Fatal(err)
}
if got2.Name != "Charlie Updated" {
t.Errorf("expected 'Charlie Updated', got %s", got2.Name)
}
if got2.Age != 36 {
t.Errorf("expected age 36, got %d", got2.Age)
}
}
func TestSQLiteAdapterDelete(t *testing.T) {
db := newTestSQLite(t)
user := New[intgUser](db)
user.Name = "Dave"
user.Email = "[email protected]"
if err := user.Create(); err != nil {
t.Fatal(err)
}
if err := user.Delete(); err != nil {
t.Fatal("Delete failed:", err)
}
_, err := Get[intgUser](db, user.Id())
if err != ErrNotFound {
t.Errorf("expected ErrNotFound after delete, got %v", err)
}
}
func TestSQLiteAdapterTransaction(t *testing.T) {
db := newTestSQLite(t)
err := db.RunInTransaction(nil, func(tx DB) error {
user := New[intgUser](tx)
user.Name = "TxUser"
user.Email = "[email protected]"
return user.Create()
})
if err != nil {
t.Fatal("Transaction failed:", err)
}
}
func TestSQLiteAdapterMultipleEntities(t *testing.T) {
db := newTestSQLite(t)
names := []string{"Alice", "Bob", "Charlie", "Dave", "Eve"}
ids := make([]string, len(names))
for i, name := range names {
user := New[intgUser](db)
user.Name = name
user.Email = name + "@example.com"
user.Age = 20 + i
if err := user.Create(); err != nil {
t.Fatal(err)
}
ids[i] = user.Id()
}
for i, id := range ids {
got, err := Get[intgUser](db, id)
if err != nil {
t.Fatalf("failed to get %s: %v", names[i], err)
}
if got.Name != names[i] {
t.Errorf("expected %s, got %s", names[i], got.Name)
}
}
}
func TestSQLiteAdapterModelQuery(t *testing.T) {
db := newTestSQLite(t)
user := New[intgUser](db)
user.Name = "QueryUser"
user.Email = "[email protected]"
user.Age = 30
if err := user.Create(); err != nil {
t.Fatal(err)
}
q := TypedQuery[intgUser](db)
found, err := q.ById(user.Id())
if err != nil {
t.Fatal(err)
}
if !found {
t.Error("expected to find entity by ID")
}
}
func TestSQLiteAdapterExists(t *testing.T) {
db := newTestSQLite(t)
user := New[intgUser](db)
user.Name = "ExistsUser"
user.Email = "[email protected]"
if err := user.Create(); err != nil {
t.Fatal(err)
}
exists, err := user.Exists()
if err != nil {
t.Fatal(err)
}
if !exists {
t.Error("expected entity to exist")
}
}
func TestSQLiteAdapterHooks(t *testing.T) {
db := newTestSQLite(t)
entity := New[intgHooked](db)
entity.Name = "Hooked"
if err := entity.Create(); err != nil {
t.Fatal(err)
}
if !entity.BeforeHook {
t.Error("expected BeforeCreate hook to fire")
}
if !entity.AfterHook {
t.Error("expected AfterCreate hook to fire")
}
got, err := Get[intgHooked](db, entity.Id())
if err != nil {
t.Fatal(err)
}
if !got.BeforeHook {
t.Error("expected BeforeHook=true in stored entity")
}
}