From 53761db1e005e01f7ced713e630b47ea2b7c5a62 Mon Sep 17 00:00:00 2001 From: Alexey Date: Thu, 18 Dec 2025 10:49:56 +0200 Subject: [PATCH] add user crud interface in impl --- internal/user/gorm_store.go | 50 ++++++++++++++++++++++ internal/user/model.go | 11 +++++ internal/user/service.go | 36 ++++++++++++++++ internal/user/store.go | 9 ++++ internal/user/user_test.go | 84 +++++++++++++++++++++++++++++++++++++ 5 files changed, 190 insertions(+) create mode 100644 internal/user/gorm_store.go create mode 100644 internal/user/model.go create mode 100644 internal/user/service.go create mode 100644 internal/user/store.go create mode 100644 internal/user/user_test.go diff --git a/internal/user/gorm_store.go b/internal/user/gorm_store.go new file mode 100644 index 0000000..c4a8792 --- /dev/null +++ b/internal/user/gorm_store.go @@ -0,0 +1,50 @@ +package user + +import ( + "fmt" + + "gorm.io/gorm" +) + +type GormUserStore struct { + db *gorm.DB +} + +func NewGormUserStore(db *gorm.DB) (*GormUserStore, error) { + if db == nil { + return nil, fmt.Errorf("db is nil") + } + return &GormUserStore{ + db: db, + }, nil +} + +func (s *GormUserStore) Create(user *User) error { + return s.db.Create(user).Error +} + +func (s *GormUserStore) GetByID(id int64) (*User, error) { + var user User + err := s.db.First(&user, id).Error + if err != nil { + return nil, err + } + return &user, nil +} + +func (s *GormUserStore) GetByUsername(username string) (*User, error) { + var user User + err := s.db.Where("username = ?", username).First(&user).Error + if err != nil { + return nil, err + } + return &user, nil +} + +func (s *GormUserStore) Update(user *User) error { + return s.db.Save(user).Error +} + +func (s *GormUserStore) Delete(id int64) error { + return s.db.Delete(&User{}, id).Error +} diff --git a/internal/user/model.go b/internal/user/model.go new file mode 100644 index 0000000..f6fca17 --- /dev/null +++ b/internal/user/model.go @@ -0,0 +1,11 @@ +package user + +import "gorm.io/gorm" + +type User struct { + ID int64 `gorm:"primaryKey"` + Username string `gorm:"uniqueIndex;not null"` + Email string `gorm:"uniqueIndex;not null"` + Password string `gorm:"not null"` + DeletedAt gorm.DeletedAt `gorm:"index"` +} diff --git a/internal/user/service.go b/internal/user/service.go new file mode 100644 index 0000000..068f21c --- /dev/null +++ b/internal/user/service.go @@ -0,0 +1,36 @@ +package user + +import "fmt" + +type Service struct { + store UserCRUD +} + +func NewService(store UserCRUD) (UserCRUD, error) { + if store == nil { + return nil, fmt.Errorf("store is nil") + } + return &Service{ + store: store, + }, nil +} + +func (s *Service) Create(user *User) error { + return s.store.Create(user) +} + +func (s *Service) GetByID(id int64) (*User, error) { + return s.store.GetByID(id) +} + +func (s *Service) GetByUsername(username string) (*User, error) { + return s.store.GetByUsername(username) +} + +func (s *Service) Update(user *User) error { + return s.store.Update(user) +} + +func (s *Service) Delete(id int64) error { + return s.store.Delete(id) +} diff --git a/internal/user/store.go b/internal/user/store.go new file mode 100644 index 0000000..b2f8b3b --- /dev/null +++ b/internal/user/store.go @@ -0,0 +1,9 @@ +package user + +type UserCRUD interface { + Create(user *User) error + GetByID(id int64) (*User, error) + GetByUsername(username string) (*User, error) + Update(user *User) error + Delete(id int64) error +} diff --git a/internal/user/user_test.go b/internal/user/user_test.go new file mode 100644 index 0000000..629583c --- /dev/null +++ b/internal/user/user_test.go @@ -0,0 +1,84 @@ +package user + +import ( + "os" + "path/filepath" + "testing" + + "gorm.io/driver/sqlite" + "gorm.io/gorm" +) + +func setupTestDB(t *testing.T) *gorm.DB { + t.Helper() + + dbPath := filepath.Join("testdata", "users.db") + + _ = os.Remove(dbPath) + + db, err := gorm.Open(sqlite.Open(dbPath), &gorm.Config{}) + if err != nil { + t.Fatalf("failed to open db: %v", err) + } + + if err := db.AutoMigrate(&User{}); err != nil { + t.Fatalf("failed to migrate: %v", err) + } + + return db +} + +func TestUsersCRUD(t *testing.T) { + db := setupTestDB(t) + + store, err := NewGormUserStore(db) + if err != nil { + t.Fatalf("failed to create store: %v", err) + } + + service, err := NewService(store) + if err != nil { + t.Fatalf("failed to create service: %v", err) + } + + user := &User{ + Username: "testuser", + Email: "test@example.com", + Password: "password123", + } + + if err := service.Create(user); err != nil { + t.Fatalf("failed to create user: %v", err) + } + retrieved, err := service.GetByID(user.ID) + if err != nil { + t.Fatalf("failed to get user by ID: %v", err) + } + if retrieved.Username != user.Username { + t.Fatalf("expected username %s, got %s", user.Username, retrieved.Username) + } + + retrievedByUsername, err := service.GetByUsername(user.Username) + if err != nil { + t.Fatalf("failed to get user by username: %v", err) + } + if retrievedByUsername.Email != user.Email { + t.Fatalf("expected email %s, got %s", user.Email, retrievedByUsername.Email) + } + + user.Email = "newemail@example.com" + if err := service.Update(user); err != nil { + t.Fatalf("failed to update user: %v", err) + } + retrieved, err = service.GetByID(user.ID) + if err != nil { + t.Fatalf("failed to get user by ID: %v", err) + } + if retrieved.Email != user.Email { + t.Fatalf("expected email %s, got %s", user.Email, retrieved.Email) + } + err = service.Delete(user.ID) + if err != nil { + t.Fatalf("failed to delete user: %v", err) + } +} \ No newline at end of file