package orm_test import ( "database/sql" "strings" "testing" "time" _ "modernc.org/sqlite" orm "trankilou.fr/lasebuche" ) type User struct { ID string `db:"id" json:"id"` Firstname string `db:"firstname" json:"firstname,omitempty"` Lastname string `db:"lastname" json:"lastname,omitempty"` Password string `db:"password" json:"-"` Email string `db:"email" json:"email,omitempty"` PictureID *string `db:"picture" json:"picture,omitempty"` Enabled bool `db:"enabled" json:"enabled"` Theme string `db:"theme" json:"theme"` Lang string `db:"lang" json:"lang"` Content []byte `db:"content" json:"content"` DateCreated time.Time `db:"_date_created" json:"_date_created"` DateUpdated *time.Time `db:"_date_updated" json:"_date_updated"` VersionId string `db:"_version" json:"_version"` } func TestHelloName(t *testing.T) { db, err := sql.Open("sqlite", "testdb") if err != nil { t.Error(err.Error()) } defer db.Close() dialect := orm.NewSqliteDialect() tableUser, err := orm.NewTable[User](db, dialect, User{}, "user") if err != nil { t.Error(err.Error()) } tableUser.Debug() err = tableUser.Sync() if err != nil { t.Error(err.Error()) } user := &User{ Firstname: "fabien", Lastname: "masson", Email: "masson.fabien@gmail.com", } user, err = tableUser.Insert(user) if err != nil { t.Error(err.Error()) } id := user.ID user2, err := tableUser.Get(id) if err != nil { t.Error(err.Error()) } if user2.Firstname != "fabien" { t.Errorf("GetByID : expected %s, got %s", "fabien", user2.Firstname) } // Test SelectOne user3, err := tableUser.SelectOne("firstname = $1", "fabien") if err != nil { t.Errorf("SelectOne failed: %v", err) } if user3 == nil { t.Error("SelectOne returned nil") } if user3.Firstname != "fabien" { t.Errorf("SelectOne: expected firstname %s, got %s", "fabien", user3.Firstname) } // Test SelectWhere users, err := tableUser.SelectWhere("firstname = $1", "fabien") if err != nil { t.Errorf("SelectWhere failed: %v", err) } if len(users) == 0 { t.Error("SelectWhere returned no results") } // Test Update user.Firstname = "Fabien" updatedUser, err := tableUser.Update(user) if err != nil { t.Errorf("Update failed: %v", err) } if updatedUser.Firstname != "Fabien" { t.Errorf("Update: expected firstname %s, got %s", "Fabien", updatedUser.Firstname) } // Verify update with Get user4, err := tableUser.Get(id) if err != nil { t.Errorf("Get after update failed: %v", err) } if user4.Firstname != "Fabien" { t.Errorf("After update, Get: expected firstname %s, got %s", "Fabien", user4.Firstname) } // Test Delete err = tableUser.Delete(id) if err != nil { t.Errorf("Delete failed: %v", err) } // Verify delete _, err = tableUser.Get(id) if err != sql.ErrNoRows { t.Errorf("After delete, expected ErrNoRows, got: %v", err) } // Test DeleteWhere - insert another user first user5 := &User{ Firstname: "Test", Lastname: "User", Email: "test@example.com", } user5, err = tableUser.Insert(user5) if err != nil { t.Errorf("Insert for DeleteWhere test failed: %v", err) } // Delete the test user err = tableUser.DeleteWhere("firstname = $1", "Test") if err != nil { t.Errorf("DeleteWhere failed: %v", err) } // Verify delete _, err = tableUser.Get(user5.ID) if err != sql.ErrNoRows { t.Errorf("After DeleteWhere, expected ErrNoRows, got: %v", err) } } func TestCRUDOperations(t *testing.T) { db, err := sql.Open("sqlite", "testdb") if err != nil { t.Fatal(err.Error()) } defer db.Close() dialect := orm.NewSqliteDialect() tableUser, err := orm.NewTable[User](db, dialect, User{}, "user") if err != nil { t.Fatal(err.Error()) } // Clean up before test _, err = db.Exec("DELETE FROM user") if err != nil { t.Fatal(err.Error()) } // Test Insert user1 := &User{ Firstname: "John", Lastname: "Doe", Email: "john.doe@example.com", Enabled: true, Theme: "dark", Lang: "en", } insertedUser, err := tableUser.Insert(user1) if err != nil { t.Fatalf("Insert failed: %v", err) } if insertedUser.ID == "" { t.Error("Inserted user should have an ID") } if insertedUser.VersionId == "" { t.Error("Inserted user should have a VersionId") } if insertedUser.DateCreated.IsZero() { t.Error("Inserted user should have DateCreated set") } t.Logf("Inserted user with ID: %s, VersionId: %s", insertedUser.ID, insertedUser.VersionId) // Test Get fetchedUser, err := tableUser.Get(insertedUser.ID) if err != nil { t.Fatalf("Get failed: %v", err) } if fetchedUser.ID != insertedUser.ID { t.Errorf("Get: expected ID %s, got %s", insertedUser.ID, fetchedUser.ID) } if fetchedUser.Firstname != "John" { t.Errorf("Get: expected Firstname John, got %s", fetchedUser.Firstname) } // Test Update fetchedUser.Firstname = "Jane" updatedUser, err := tableUser.Update(fetchedUser) if err != nil { t.Fatalf("Update failed: %v", err) } if updatedUser.Firstname != "Jane" { t.Errorf("Update: expected Firstname Jane, got %s", updatedUser.Firstname) } if updatedUser.DateUpdated == nil { t.Error("Update should have set DateUpdated") } // Verify update verifiedUser, err := tableUser.Get(insertedUser.ID) if err != nil { t.Fatalf("Get after update failed: %v", err) } if verifiedUser.Firstname != "Jane" { t.Errorf("After update, Get: expected Firstname Jane, got %s", verifiedUser.Firstname) } // Test SelectOne selectedUser, err := tableUser.SelectOne("email = $1", "john.doe@example.com") if err != nil { t.Fatalf("SelectOne failed: %v", err) } if selectedUser == nil { t.Error("SelectOne returned nil") } if selectedUser.Email != "john.doe@example.com" { t.Errorf("SelectOne: expected email john.doe@example.com, got %s", selectedUser.Email) } // Insert another user for SelectWhere test user2 := &User{ Firstname: "Alice", Lastname: "Smith", Email: "alice.smith@example.com", } _, err = tableUser.Insert(user2) if err != nil { t.Fatalf("Insert user2 failed: %v", err) } // Test SelectWhere users, err := tableUser.SelectWhere("") if err != nil { t.Fatalf("SelectWhere failed: %v", err) } if len(users) < 2 { t.Errorf("SelectWhere: expected at least 2 users, got %d", len(users)) } // Test SelectWhere with condition filteredUsers, err := tableUser.SelectWhere("firstname = $1", "Jane") if err != nil { t.Fatalf("SelectWhere with condition failed: %v", err) } if len(filteredUsers) != 1 { t.Errorf("SelectWhere with condition: expected 1 user, got %d", len(filteredUsers)) } // Test Delete err = tableUser.Delete(insertedUser.ID) if err != nil { t.Fatalf("Delete failed: %v", err) } // Verify deletion _, err = tableUser.Get(insertedUser.ID) if err != sql.ErrNoRows { t.Errorf("After Delete, expected ErrNoRows, got: %v", err) } // Test DeleteWhere err = tableUser.DeleteWhere("firstname = $1", "Alice") if err != nil { t.Fatalf("DeleteWhere failed: %v", err) } // Verify deletion _, err = tableUser.Get(user2.ID) if err != sql.ErrNoRows { t.Errorf("After DeleteWhere, expected ErrNoRows, got: %v", err) } // Clean up _, err = db.Exec("DELETE FROM user") if err != nil { t.Logf("Cleanup failed: %v", err) } } func TestEdgeCases(t *testing.T) { db, err := sql.Open("sqlite", "testdb") if err != nil { t.Fatal(err.Error()) } defer db.Close() dialect := orm.NewSqliteDialect() tableUser, err := orm.NewTable[User](db, dialect, User{}, "user") if err != nil { t.Fatal(err.Error()) } // Clean up before test _, err = db.Exec("DELETE FROM user") if err != nil { t.Fatal(err.Error()) } // Test SelectOne with no results user, err := tableUser.SelectOne("firstname = $1", "NonExistent") if err != nil && err != sql.ErrNoRows { t.Errorf("SelectOne with no results: expected error or nil, got: %v", err) } if user != nil { t.Error("SelectOne with no results should return nil user") } // Test SelectWhere with no results users, err := tableUser.SelectWhere("firstname = $1", "NonExistent") if err != nil { t.Errorf("SelectWhere with no results: unexpected error: %v", err) } if len(users) != 0 { t.Errorf("SelectWhere with no results: expected 0 users, got %d", len(users)) } // Test Get with non-existent ID _, err = tableUser.Get("non-existent-id") if err != sql.ErrNoRows { t.Errorf("Get with non-existent ID: expected ErrNoRows, got: %v", err) } // Test Delete with non-existent ID (should not error, just affect 0 rows) err = tableUser.Delete("non-existent-id") if err != nil { t.Errorf("Delete with non-existent ID: unexpected error: %v", err) } // Test DeleteWhere with no matching rows err = tableUser.DeleteWhere("firstname = $1", "NonExistent") if err != nil { t.Errorf("DeleteWhere with no matching rows: unexpected error: %v", err) } // Test Update with non-existent ID (will fail due to WHERE clause) nonExistentUser := &User{ ID: "non-existent-id", Firstname: "Test", VersionId: "test-version", } _, err = tableUser.Update(nonExistentUser) // This should fail because the row doesn't exist if err == nil { t.Error("Update with non-existent ID should have failed") } // Clean up _, err = db.Exec("DELETE FROM user") if err != nil { t.Logf("Cleanup failed: %v", err) } } func TestVersionLocking(t *testing.T) { db, err := sql.Open("sqlite", "testdb") if err != nil { t.Fatal(err.Error()) } defer db.Close() dialect := orm.NewSqliteDialect() tableUser, err := orm.NewTable[User](db, dialect, User{}, "user") if err != nil { t.Fatal(err.Error()) } // Clean up before test _, err = db.Exec("DELETE FROM user") if err != nil { t.Fatal(err.Error()) } // Insert a user user := &User{ Firstname: "Version", Lastname: "Test", Email: "version@test.com", } insertedUser, err := tableUser.Insert(user) if err != nil { t.Fatalf("Insert failed: %v", err) } originalVersionId := insertedUser.VersionId t.Logf("Original VersionId: %s", originalVersionId) // Fetch the user to get fresh data fetchedUser, err := tableUser.Get(insertedUser.ID) if err != nil { t.Fatalf("Get failed: %v", err) } // First update should succeed with correct version fetchedUser.Firstname = "Version2" updatedUser, err := tableUser.Update(fetchedUser) if err != nil { t.Fatalf("First update failed: %v", err) } // VersionId should have changed if updatedUser.VersionId == originalVersionId { t.Error("VersionId should have changed after update") } newVersionId := updatedUser.VersionId t.Logf("New VersionId after first update: %s", newVersionId) // Second update with correct version should succeed updatedUser.Firstname = "Version3" updatedUser2, err := tableUser.Update(updatedUser) if err != nil { t.Fatalf("Second update failed: %v", err) } // VersionId should have changed again if updatedUser2.VersionId == newVersionId { t.Error("VersionId should have changed after second update") } // Now try to update with old version - should fail // Create a new user with the old version oldVersionUser := &User{ ID: insertedUser.ID, Firstname: "ShouldFail", Lastname: "Test", Email: "version@test.com", VersionId: originalVersionId, // Old version } _, err = tableUser.Update(oldVersionUser) if err == nil { t.Error("Update with old VersionId should have failed") } if !strings.Contains(err.Error(), "version mismatch") { t.Errorf("Expected version mismatch error, got: %v", err) } // Clean up _, err = db.Exec("DELETE FROM user") if err != nil { t.Logf("Cleanup failed: %v", err) } }