From f151fa7eaef31b1c2aa55b2b37b2146189f92a07 Mon Sep 17 00:00:00 2001 From: Jean Jacques Avril Date: Fri, 3 Jan 2025 15:23:33 +0000 Subject: [PATCH] made usage of first class citizen functions in go --- README.md | 6 ++- .../internal/application/repository/helper.go | 14 +++++++ .../repository/user_repository_impl.go | 40 ++++++++----------- .../application/services/user_service.go | 27 ++++++------- .../domain/repository/user_repository.go | 13 +++--- 5 files changed, 55 insertions(+), 45 deletions(-) create mode 100644 backend-go/internal/application/repository/helper.go diff --git a/README.md b/README.md index 4ab2105..eda02a1 100755 --- a/README.md +++ b/README.md @@ -138,4 +138,8 @@ Best of do's and dont's https://the-zen-of-go.netlify.app/ ### FP-Go Documentation -https://pkg.go.dev/github.com/IBM/fp-go \ No newline at end of file +https://pkg.go.dev/github.com/IBM/fp-go + +https://betterprogramming.pub/investigate-functional-programming-concepts-in-go-1dada09bc913 + +https://rlee.dev/practical-guide-to-fp-ts-part-1 \ No newline at end of file diff --git a/backend-go/internal/application/repository/helper.go b/backend-go/internal/application/repository/helper.go new file mode 100644 index 0000000..c6687c1 --- /dev/null +++ b/backend-go/internal/application/repository/helper.go @@ -0,0 +1,14 @@ +package repository + +import ( + "context" + + E "github.com/IBM/fp-go/either" +) + +// curried delegiert eine Methode mit Kontext und gibt eine Funktion zurück. +func curried[T any, R any](ctx context.Context, fn func(context.Context, T) E.Either[error, R]) func(T) E.Either[error, R] { + return func(input T) E.Either[error, R] { + return fn(ctx, input) + } +} diff --git a/backend-go/internal/application/repository/user_repository_impl.go b/backend-go/internal/application/repository/user_repository_impl.go index 9224676..86d658e 100644 --- a/backend-go/internal/application/repository/user_repository_impl.go +++ b/backend-go/internal/application/repository/user_repository_impl.go @@ -1,9 +1,8 @@ package repository import ( - "actatempus_backend/internal/domain/entities" - "actatempus_backend/internal/domain/repository" "actatempus_backend/internal/domain/data" + "actatempus_backend/internal/domain/entities" "context" E "github.com/IBM/fp-go/either" @@ -14,37 +13,32 @@ type UserRepositoryImpl struct { dataSource data.UserDataSource } -// NewUserRepository creates a new instance of UserRepositoryImpl. -func NewUserRepository(dataSource data.UserDataSource) repository.UserRepository { - return &UserRepositoryImpl{dataSource: dataSource} +// Create delegiert die Erstellung eines Benutzers an die Datenquelle. +func (r *UserRepositoryImpl) Create(ctx context.Context) func(user entities.UserCreate) E.Either[error, entities.User] { + return curried(ctx, r.dataSource.Create) } -// Create delegates the creation of a user to the data source. -func (r *UserRepositoryImpl) Create(ctx context.Context, user entities.UserCreate) E.Either[error, entities.User] { - return r.dataSource.Create(ctx, user) +// FindByID delegiert das Abrufen eines Benutzers nach ID an die Datenquelle. +func (r *UserRepositoryImpl) FindByID(ctx context.Context) func(id string) E.Either[error, entities.User] { + return curried(ctx, r.dataSource.FindByID) } -// FindByID delegates fetching a user by ID to the data source. -func (r *UserRepositoryImpl) FindByID(ctx context.Context, id string) E.Either[error, entities.User] { - return r.dataSource.FindByID(ctx, id) +// FindByEmail delegiert das Abrufen eines Benutzers nach E-Mail an die Datenquelle. +func (r *UserRepositoryImpl) FindByEmail(ctx context.Context) func(email string) E.Either[error, entities.User] { + return curried(ctx, r.dataSource.FindByEmail) } -// FindByEmail delegates fetching a user by email to the data source. -func (r *UserRepositoryImpl) FindByEmail(ctx context.Context, email string) E.Either[error, entities.User] { - return r.dataSource.FindByEmail(ctx, email) +// Update delegiert das Aktualisieren eines Benutzers an die Datenquelle. +func (r *UserRepositoryImpl) Update(ctx context.Context) func(user entities.UserUpdate) E.Either[error, entities.User] { + return curried(ctx, r.dataSource.Update) } -// Update delegates updating a user to the data source. -func (r *UserRepositoryImpl) Update(ctx context.Context, user entities.UserUpdate) E.Either[error, entities.User] { - return r.dataSource.Update(ctx, user) +// Delete delegiert das Löschen eines Benutzers an die Datenquelle. +func (r *UserRepositoryImpl) Delete(ctx context.Context) func(id string) E.Either[error, entities.User] { + return curried(ctx, r.dataSource.Delete) } -// Delete delegates deleting a user to the data source. -func (r *UserRepositoryImpl) Delete(ctx context.Context, id string) E.Either[error, entities.User] { - return r.dataSource.Delete(ctx, id) -} - -// FindAll delegates fetching all users to the data source. +// FindAll delegiert das Abrufen aller Benutzer an die Datenquelle. func (r *UserRepositoryImpl) FindAll(ctx context.Context) E.Either[error, []entities.User] { return r.dataSource.FindAll(ctx) } diff --git a/backend-go/internal/application/services/user_service.go b/backend-go/internal/application/services/user_service.go index f3b3c9f..77d64c1 100644 --- a/backend-go/internal/application/services/user_service.go +++ b/backend-go/internal/application/services/user_service.go @@ -38,9 +38,9 @@ func (s *UserService) CreateUser(c *gin.Context) { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } - userCreate := mappers.MapCreateDTOToUser(userCreateDTO) - F.Pipe2( - s.repository.Create(c.Request.Context(), userCreate), + F.Pipe3( + mappers.MapCreateDTOToUser(userCreateDTO), + s.repository.Create(c.Request.Context()), E.Map[error](mappers.MapUserToDTO), E.Fold( HandleError(c), @@ -51,9 +51,9 @@ func (s *UserService) CreateUser(c *gin.Context) { // GetUserByID handles fetching a user by their ID. func (s *UserService) GetUserByID(c *gin.Context) { - id := c.Param("id") - F.Pipe2( - s.repository.FindByID(c.Request.Context(), id), + F.Pipe3( + c.Param("id"), + s.repository.FindByID(c.Request.Context()), E.Map[error](mappers.MapUserToDTO), E.Fold( HandleError(c), @@ -84,10 +84,9 @@ func (s *UserService) UpdateUser(c *gin.Context) { return } - userUpdate := mappers.MapUpdateDTOToUser(userUpdateDTO, id) - - F.Pipe2( - s.repository.Update(c.Request.Context(), userUpdate), + F.Pipe3( + mappers.MapUpdateDTOToUser(userUpdateDTO, id), + s.repository.Update(c.Request.Context()), E.Map[error](mappers.MapUserToDTO), E.Fold( HandleError(c), @@ -98,15 +97,13 @@ func (s *UserService) UpdateUser(c *gin.Context) { // DeleteUser handles deleting a user by their ID. func (s *UserService) DeleteUser(c *gin.Context) { - id := c.Param("id") - - F.Pipe2( - s.repository.Delete(c.Request.Context(), id), + F.Pipe3( + c.Param("id"), + s.repository.Delete(c.Request.Context()), E.Map[error](mappers.MapUserToDTO), E.Fold( HandleError(c), HandleSuccess[dto.UserDTO](c, http.StatusOK), ), ) - } diff --git a/backend-go/internal/domain/repository/user_repository.go b/backend-go/internal/domain/repository/user_repository.go index 3fdb5fd..18f434b 100755 --- a/backend-go/internal/domain/repository/user_repository.go +++ b/backend-go/internal/domain/repository/user_repository.go @@ -8,11 +8,12 @@ import ( ) // UserRepository defines the operations for interacting with user data. + type UserRepository interface { - Create(ctx context.Context, user entities.UserCreate) E.Either[error,entities.User] - FindByID(ctx context.Context, id string) E.Either[error,entities.User] - FindByEmail(ctx context.Context, email string) E.Either[error,entities.User] - Update(ctx context.Context, user entities.UserUpdate) E.Either[error,entities.User] - Delete(ctx context.Context, id string) E.Either[error,entities.User] - FindAll(ctx context.Context) E.Either[error,[]entities.User] + Create(ctx context.Context) func(user entities.UserCreate) E.Either[error, entities.User] + FindByID(ctx context.Context) func(id string) E.Either[error, entities.User] + FindByEmail(ctx context.Context) func(email string) E.Either[error, entities.User] + Update(ctx context.Context) func(user entities.UserUpdate) E.Either[error, entities.User] + Delete(ctx context.Context) func(id string) E.Either[error, entities.User] + FindAll(ctx context.Context) E.Either[error, []entities.User] // Keine zusätzlichen Argumente nötig }