From b4cf84d6721a918876bfe513c18846bcd6b5d10f Mon Sep 17 00:00:00 2001 From: wiraphat <132466647+wiraphatys@users.noreply.github.com> Date: Thu, 27 Jun 2024 12:19:44 +0700 Subject: [PATCH 01/16] add: [group-svc] find one rpc --- cmd/main.go | 6 +++ internal/group/group.repository.go | 28 ++++++++++++ internal/group/group.service.go | 69 +++++++++++++++++++++++++++--- 3 files changed, 96 insertions(+), 7 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index c252be5..e083d33 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -13,9 +13,11 @@ import ( "github.com/isd-sgcu/rpkm67-backend/config" "github.com/isd-sgcu/rpkm67-backend/database" "github.com/isd-sgcu/rpkm67-backend/internal/cache" + "github.com/isd-sgcu/rpkm67-backend/internal/group" "github.com/isd-sgcu/rpkm67-backend/internal/pin" "github.com/isd-sgcu/rpkm67-backend/internal/stamp" "github.com/isd-sgcu/rpkm67-backend/logger" + groupProto "github.com/isd-sgcu/rpkm67-go-proto/rpkm67/backend/group/v1" pinProto "github.com/isd-sgcu/rpkm67-go-proto/rpkm67/backend/pin/v1" stampProto "github.com/isd-sgcu/rpkm67-go-proto/rpkm67/backend/stamp/v1" "go.uber.org/zap" @@ -50,6 +52,9 @@ func main() { stampRepo := stamp.NewRepository(db) stampSvc := stamp.NewService(stampRepo, logger.Named("stampSvc")) + groupRepo := group.NewRepository(db) + groupSvc := group.NewService(groupRepo, cacheRepo, logger.Named("groupSvc")) + // selectionRepo := selection.NewRepository(db) listener, err := net.Listen("tcp", fmt.Sprintf(":%v", conf.App.Port)) @@ -61,6 +66,7 @@ func main() { grpc_health_v1.RegisterHealthServer(grpcServer, health.NewServer()) pinProto.RegisterPinServiceServer(grpcServer, pinSvc) stampProto.RegisterStampServiceServer(grpcServer, stampSvc) + groupProto.RegisterGroupServiceServer(grpcServer, groupSvc) reflection.Register(grpcServer) go func() { diff --git a/internal/group/group.repository.go b/internal/group/group.repository.go index de9c54a..4f9f01d 100644 --- a/internal/group/group.repository.go +++ b/internal/group/group.repository.go @@ -1,10 +1,17 @@ package group import ( + "context" + "fmt" + "time" + + "github.com/google/uuid" + "github.com/isd-sgcu/rpkm67-model/model" "gorm.io/gorm" ) type Repository interface { + FindOne(userId string) (*model.Group, error) } type repositoryImpl struct { @@ -16,3 +23,24 @@ func NewRepository(db *gorm.DB) Repository { Db: db, } } + +func (r *repositoryImpl) FindOne(userId string) (*model.Group, error) { + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) + defer cancel() + + userUUID, err := uuid.Parse(userId) + if err != nil { + return nil, fmt.Errorf("invalid UUID format: %v", err) + } + + var group model.Group + if err := r.Db.WithContext(ctx). + Preload("Members"). + Joins("JOIN users ON users.group_id = groups.id"). + Where("users.id = ?", userUUID). + First(&group).Error; err != nil { + return nil, err + } + + return &group, nil +} diff --git a/internal/group/group.service.go b/internal/group/group.service.go index 8f03ce2..5e91278 100644 --- a/internal/group/group.service.go +++ b/internal/group/group.service.go @@ -2,7 +2,9 @@ package group import ( "context" + "fmt" + "github.com/isd-sgcu/rpkm67-backend/internal/cache" proto "github.com/isd-sgcu/rpkm67-go-proto/rpkm67/backend/group/v1" "go.uber.org/zap" ) @@ -13,17 +15,70 @@ type Service interface { type serviceImpl struct { proto.UnimplementedGroupServiceServer - repo Repository - log *zap.Logger + repo Repository + cache cache.Repository + log *zap.Logger } -func NewService(repo Repository, log *zap.Logger) Service { +func NewService(repo Repository, cache cache.Repository, log *zap.Logger) Service { return &serviceImpl{ - repo: repo, - log: log, + repo: repo, + cache: cache, + log: log, } } -func (s *serviceImpl) FindOne(_ context.Context, in *proto.FindOneGroupRequest) (res *proto.FindOneGroupResponse, err error) { - return nil, nil +func (s *serviceImpl) FindOne(ctx context.Context, in *proto.FindOneGroupRequest) (*proto.FindOneGroupResponse, error) { + cacheKey := fmt.Sprintf("group:%s", in.UserId) + var cachedGroup proto.Group + + // try to retreive from cache + err := s.cache.GetValue(cacheKey, &cachedGroup) + if err == nil { + s.log.Info("Group found in cache", zap.String("user_id", in.UserId)) + return &proto.FindOneGroupResponse{Group: &cachedGroup}, nil + } + + // if not found cache, find group in database + group, err := s.repo.FindOne(in.UserId) + if err != nil { + s.log.Error("Failed to find group", zap.String("user_id", in.UserId), zap.Error(err)) + return nil, err + } + + userInfo := make([]*proto.UserInfo, 0, len(group.Members)) + for _, m := range group.Members { + user := proto.UserInfo{ + Id: m.ID.String(), + Firstname: m.Firstname, + Lastname: m.Lastname, + ImageUrl: m.PhotoUrl, + } + userInfo = append(userInfo, &user) + } + + groupRPC := proto.Group{ + Id: group.ID.String(), + LeaderID: group.LeaderID, + Token: group.Token, + Members: userInfo, + Baans: nil, + } + + // set cache + if err := s.cache.SetValue(cacheKey, &groupRPC, 3600); err != nil { // cache นาน 1 ชั่วโมง + s.log.Warn("Failed to set group in cache", zap.String("user_id", in.UserId), zap.Error(err)) + } + + res := proto.FindOneGroupResponse{ + Group: &groupRPC, + } + + s.log.Info("FindOne group service completed", + zap.String("group_id", group.ID.String()), + zap.String("user_id", in.UserId), + zap.Int("member_count", len(userInfo)), + zap.Bool("from_cache", false)) + + return &res, nil } From ce2505c5a569582c89a28fd7a0831b090ba06a03 Mon Sep 17 00:00:00 2001 From: wiraphat <132466647+wiraphatys@users.noreply.github.com> Date: Thu, 27 Jun 2024 13:16:35 +0700 Subject: [PATCH 02/16] refactor: move parse uuid into service layer --- internal/group/group.repository.go | 12 +++--------- internal/group/group.service.go | 8 +++++++- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/internal/group/group.repository.go b/internal/group/group.repository.go index 4f9f01d..2ddf043 100644 --- a/internal/group/group.repository.go +++ b/internal/group/group.repository.go @@ -2,7 +2,6 @@ package group import ( "context" - "fmt" "time" "github.com/google/uuid" @@ -11,7 +10,7 @@ import ( ) type Repository interface { - FindOne(userId string) (*model.Group, error) + FindOne(userId uuid.UUID) (*model.Group, error) } type repositoryImpl struct { @@ -24,20 +23,15 @@ func NewRepository(db *gorm.DB) Repository { } } -func (r *repositoryImpl) FindOne(userId string) (*model.Group, error) { +func (r *repositoryImpl) FindOne(userId uuid.UUID) (*model.Group, error) { ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() - userUUID, err := uuid.Parse(userId) - if err != nil { - return nil, fmt.Errorf("invalid UUID format: %v", err) - } - var group model.Group if err := r.Db.WithContext(ctx). Preload("Members"). Joins("JOIN users ON users.group_id = groups.id"). - Where("users.id = ?", userUUID). + Where("users.id = ?", userId). First(&group).Error; err != nil { return nil, err } diff --git a/internal/group/group.service.go b/internal/group/group.service.go index 5e91278..d960376 100644 --- a/internal/group/group.service.go +++ b/internal/group/group.service.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "github.com/google/uuid" "github.com/isd-sgcu/rpkm67-backend/internal/cache" proto "github.com/isd-sgcu/rpkm67-go-proto/rpkm67/backend/group/v1" "go.uber.org/zap" @@ -39,8 +40,13 @@ func (s *serviceImpl) FindOne(ctx context.Context, in *proto.FindOneGroupRequest return &proto.FindOneGroupResponse{Group: &cachedGroup}, nil } + userUUID, err := uuid.Parse(in.UserId) + if err != nil { + return nil, fmt.Errorf("invalid UUID format: %v", err) + } + // if not found cache, find group in database - group, err := s.repo.FindOne(in.UserId) + group, err := s.repo.FindOne(userUUID) if err != nil { s.log.Error("Failed to find group", zap.String("user_id", in.UserId), zap.Error(err)) return nil, err From bc25d3a197182d5942b1648c5621fddc06926809 Mon Sep 17 00:00:00 2001 From: flagrantii Date: Thu, 27 Jun 2024 16:15:28 +0700 Subject: [PATCH 03/16] Feat : Implement selection service --- go.mod | 2 +- go.sum | 2 + internal/group/group.service.go | 10 +- internal/selection/selection.repository.go | 8 +- internal/selection/selection.service.go | 158 ++++++++++++++++++ .../selection/test/selection.service_test.go | 1 + 6 files changed, 171 insertions(+), 10 deletions(-) create mode 100644 internal/selection/selection.service.go create mode 100644 internal/selection/test/selection.service_test.go diff --git a/go.mod b/go.mod index 4e0b246..a0817da 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.22.4 require ( github.com/golang-jwt/jwt/v4 v4.5.0 github.com/golang/mock v1.6.0 - github.com/isd-sgcu/rpkm67-go-proto v0.1.5 + github.com/isd-sgcu/rpkm67-go-proto v0.1.6 github.com/isd-sgcu/rpkm67-model v0.0.1 github.com/joho/godotenv v1.5.1 github.com/redis/go-redis/v9 v9.5.3 diff --git a/go.sum b/go.sum index ded8080..f91d6f3 100644 --- a/go.sum +++ b/go.sum @@ -19,6 +19,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/isd-sgcu/rpkm67-go-proto v0.1.5 h1:WShrm8DeVqIY1ZelgM88vW8LMnLxF6dTt650A0YkC8U= github.com/isd-sgcu/rpkm67-go-proto v0.1.5/go.mod h1:Z5SYz5kEe4W+MdqPouF0zEOiaqvg+s9I1S5d0q6e+Jw= +github.com/isd-sgcu/rpkm67-go-proto v0.1.6 h1:6mubghe7HuGJYv+hgpIxJBBrmVk5UdjHjdvzykLLhQ0= +github.com/isd-sgcu/rpkm67-go-proto v0.1.6/go.mod h1:Z5SYz5kEe4W+MdqPouF0zEOiaqvg+s9I1S5d0q6e+Jw= github.com/isd-sgcu/rpkm67-model v0.0.1 h1:LFn7jaawkZP1golE9B32a2KL/U/w20UFjQo2Cd/3Fhc= github.com/isd-sgcu/rpkm67-model v0.0.1/go.mod h1:dxgLSkrFpbQOXsrzqgepZoEOyZUIG2LBGtm5gsuBbVc= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= diff --git a/internal/group/group.service.go b/internal/group/group.service.go index 5e91278..3908d76 100644 --- a/internal/group/group.service.go +++ b/internal/group/group.service.go @@ -58,11 +58,11 @@ func (s *serviceImpl) FindOne(ctx context.Context, in *proto.FindOneGroupRequest } groupRPC := proto.Group{ - Id: group.ID.String(), - LeaderID: group.LeaderID, - Token: group.Token, - Members: userInfo, - Baans: nil, + Id: group.ID.String(), + LeaderID: group.LeaderID, + Token: group.Token, + Members: userInfo, + IsConfirmed: group.IsConfirmed, } // set cache diff --git a/internal/selection/selection.repository.go b/internal/selection/selection.repository.go index 82a58ee..d0584af 100644 --- a/internal/selection/selection.repository.go +++ b/internal/selection/selection.repository.go @@ -27,11 +27,11 @@ func (r *repositoryImpl) Create(user *model.Selection) error { } func (r *repositoryImpl) FindByGroupId(groupId string, selections *[]model.Selection) error { - return r.Db.Find(selections, "groupId = ?", groupId).Error + return r.Db.Find(selections, "group_id = ?", groupId).Error } -func (r *repositoryImpl) Delete(id string) error { - return r.Db.Delete(&model.Selection{}, "id = ?", id).Error +func (r *repositoryImpl) Delete(groupId string) error { + return r.Db.Delete(&model.Selection{}, "group_id = ?", groupId).Error } func (r *repositoryImpl) CountGroupByBaanId() (map[string]int, error) { @@ -39,7 +39,7 @@ func (r *repositoryImpl) CountGroupByBaanId() (map[string]int, error) { BaanId string Count int } - if err := r.Db.Model(&model.Selection{}).Select("baan_id, count(*) as count").Group("baan_id").Scan(&result).Error; err != nil { + if err := r.Db.Model(&model.Selection{}).Select("baan, count(*) as count").Group("baan").Scan(&result).Error; err != nil { return nil, err } diff --git a/internal/selection/selection.service.go b/internal/selection/selection.service.go new file mode 100644 index 0000000..14c693f --- /dev/null +++ b/internal/selection/selection.service.go @@ -0,0 +1,158 @@ +package selection + +import ( + "context" + "fmt" + + "github.com/google/uuid" + "github.com/isd-sgcu/rpkm67-backend/internal/cache" + proto "github.com/isd-sgcu/rpkm67-go-proto/rpkm67/backend/selection/v1" + "github.com/isd-sgcu/rpkm67-model/model" + "go.uber.org/zap" +) + +type Service interface { + proto.SelectionServiceServer +} + +type serviceImpl struct { + proto.UnimplementedSelectionServiceServer + repo Repository + cache cache.Repository + log *zap.Logger +} + +func NewService(repo Repository, cache cache.Repository, log *zap.Logger) Service { + return &serviceImpl{ + repo: repo, + cache: cache, + log: log, + } +} + +func (s *serviceImpl) Create(ctx context.Context, in *proto.CreateSelectionRequest) (*proto.CreateSelectionResponse, error) { + GroupUuid, err := uuid.Parse(in.GroupId) + if err != nil { + s.log.Error("Failed to parse group id", zap.Error(err)) + return nil, err + } + + selection := model.Selection{ + GroupID: &GroupUuid, + Baan: in.BaanId, + Order: int(in.Order), + } + + err = s.repo.Create(&selection) + if err != nil { + s.log.Error("Failed to create selection", zap.Error(err)) + return nil, err + } + + cacheKey := fmt.Sprintf("group:%s", in.GroupId) + err = s.cache.SetValue(cacheKey, selection, 3600) + if err != nil { + s.log.Error("Failed to cache selection", zap.Error(err)) + } + + res := proto.CreateSelectionResponse{ + Selection: &proto.Selection{ + Id: "", + GroupId: in.GroupId, + BaanId: in.BaanId, + Order: in.Order, + }, + } + + s.log.Info("Selection created", + zap.String("group_id", in.GroupId), + zap.String("baan_id", in.BaanId)) + + return &res, nil +} + +func (s *serviceImpl) FindByGroupId(ctx context.Context, in *proto.FindByGroupIdSelectionRequest) (*proto.FindByGroupIdSelectionResponse, error) { + cacheKey := fmt.Sprintf("group:%s", in.GroupId) + var cachedSelection []*proto.Selection + + err := s.cache.GetValue(cacheKey, &cachedSelection) + if err == nil { + s.log.Info("Group found in cache", zap.String("user_id", in.GroupId)) + return &proto.FindByGroupIdSelectionResponse{Selections: cachedSelection}, nil + } + + selection := &[]model.Selection{} + + err = s.repo.FindByGroupId(in.GroupId, selection) + if err != nil { + s.log.Error("Failed to find selection", zap.String("group_id", in.GroupId), zap.Error(err)) + return nil, err + } + + selectionRPC := []*proto.Selection{} + for _, m := range *selection { + ss := &proto.Selection{ + Id: "", + GroupId: m.GroupID.String(), + BaanId: m.Baan, + Order: int32(m.Order), + } + selectionRPC = append(selectionRPC, ss) + } + + res := proto.FindByGroupIdSelectionResponse{ + Selections: selectionRPC, + } + + s.log.Info("Selection found", + zap.String("group_id", in.GroupId), + zap.Any("selections", selectionRPC)) + + return &res, nil +} + +func (s *serviceImpl) Delete(ctx context.Context, in *proto.DeleteSelectionRequest) (*proto.DeleteSelectionResponse, error) { + err := s.repo.Delete(in.GroupId) + if err != nil { + s.log.Error("Failed to delete selection", zap.Error(err)) + return nil, err + } + cacheKey := fmt.Sprintf("group:%s", in.GroupId) + + err = s.cache.DeleteValue(cacheKey) + if err != nil { + s.log.Error("Failed to delete selection from cache", zap.Error(err)) + return nil, err + } + + s.log.Info("Selection deleted", + zap.String("group_id", in.GroupId)) + + return &proto.DeleteSelectionResponse{Success: true}, nil +} + +func (s *serviceImpl) CountGroupByBaanId(ctx context.Context, in *proto.CountByBaanIdSelectionRequest) (*proto.CountByBaanIdSelectionResponse, error) { + count, err := s.repo.CountGroupByBaanId() + if err != nil { + s.log.Error("Failed to count group by baan id", zap.Error(err)) + return nil, err + } + + countRPC := []*proto.BaanCount{} + for k, v := range count { + bc := &proto.BaanCount{ + BaanId: k, + Count: int32(v), + } + countRPC = append(countRPC, bc) + } + + res := proto.CountByBaanIdSelectionResponse{ + BaanCounts: countRPC, + } + + s.log.Info("Count group by baan id", + zap.Any("count", count)) + + return &res, nil +} diff --git a/internal/selection/test/selection.service_test.go b/internal/selection/test/selection.service_test.go new file mode 100644 index 0000000..56e5404 --- /dev/null +++ b/internal/selection/test/selection.service_test.go @@ -0,0 +1 @@ +package test From 7ec12dde0a24a995012c8499f113c3c664042ddd Mon Sep 17 00:00:00 2001 From: wiraphat <132466647+wiraphatys@users.noreply.github.com> Date: Thu, 27 Jun 2024 17:18:42 +0700 Subject: [PATCH 04/16] update: go.mod and go.sum --- go.mod | 3 +-- go.sum | 4 ---- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/go.mod b/go.mod index a0817da..a598e95 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,8 @@ module github.com/isd-sgcu/rpkm67-backend go 1.22.4 require ( - github.com/golang-jwt/jwt/v4 v4.5.0 github.com/golang/mock v1.6.0 + github.com/google/uuid v1.6.0 github.com/isd-sgcu/rpkm67-go-proto v0.1.6 github.com/isd-sgcu/rpkm67-model v0.0.1 github.com/joho/godotenv v1.5.1 @@ -20,7 +20,6 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect - github.com/google/uuid v1.6.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackc/pgx/v5 v5.5.5 // indirect diff --git a/go.sum b/go.sum index f91d6f3..b827df9 100644 --- a/go.sum +++ b/go.sum @@ -9,16 +9,12 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= -github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= -github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/isd-sgcu/rpkm67-go-proto v0.1.5 h1:WShrm8DeVqIY1ZelgM88vW8LMnLxF6dTt650A0YkC8U= -github.com/isd-sgcu/rpkm67-go-proto v0.1.5/go.mod h1:Z5SYz5kEe4W+MdqPouF0zEOiaqvg+s9I1S5d0q6e+Jw= github.com/isd-sgcu/rpkm67-go-proto v0.1.6 h1:6mubghe7HuGJYv+hgpIxJBBrmVk5UdjHjdvzykLLhQ0= github.com/isd-sgcu/rpkm67-go-proto v0.1.6/go.mod h1:Z5SYz5kEe4W+MdqPouF0zEOiaqvg+s9I1S5d0q6e+Jw= github.com/isd-sgcu/rpkm67-model v0.0.1 h1:LFn7jaawkZP1golE9B32a2KL/U/w20UFjQo2Cd/3Fhc= From 56a4579b2f5b46c9af1b2f69d10b3abd701df4bb Mon Sep 17 00:00:00 2001 From: flagrantii Date: Thu, 27 Jun 2024 21:46:36 +0700 Subject: [PATCH 05/16] Feat : Add condition check in Create Selection --- internal/selection/selection.service.go | 49 +++++++++++++++++++------ 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/internal/selection/selection.service.go b/internal/selection/selection.service.go index 14c693f..15a5128 100644 --- a/internal/selection/selection.service.go +++ b/internal/selection/selection.service.go @@ -37,6 +37,30 @@ func (s *serviceImpl) Create(ctx context.Context, in *proto.CreateSelectionReque return nil, err } + selections := &[]model.Selection{} + err = s.repo.FindByGroupId(in.GroupId, selections) + if err != nil { + s.log.Error("Failed to find selection", zap.Error(err)) + return nil, err + } + + //Check can not create selection with same order + for _, selection := range *selections { + if selection.Order == int(in.Order) { + s.log.Error("Failed to create selection", zap.Error(err)) + return nil, fmt.Errorf("Can not create selection with same order") + } + } + + //Check can not create selection with same baan + for _, selection := range *selections { + if selection.Baan == in.BaanId { + s.log.Error("Failed to create selection", zap.Error(err)) + return nil, fmt.Errorf("Can not create selection with same baan") + } + } + + //Create selection selection := model.Selection{ GroupID: &GroupUuid, Baan: in.BaanId, @@ -49,11 +73,13 @@ func (s *serviceImpl) Create(ctx context.Context, in *proto.CreateSelectionReque return nil, err } - cacheKey := fmt.Sprintf("group:%s", in.GroupId) - err = s.cache.SetValue(cacheKey, selection, 3600) - if err != nil { - s.log.Error("Failed to cache selection", zap.Error(err)) - } + defer func() { + cacheKey := fmt.Sprintf("group:%s", in.GroupId) + err = s.cache.SetValue(cacheKey, selection, 3600) + if err != nil { + s.log.Error("Failed to cache selection", zap.Error(err)) + } + }() res := proto.CreateSelectionResponse{ Selection: &proto.Selection{ @@ -117,13 +143,14 @@ func (s *serviceImpl) Delete(ctx context.Context, in *proto.DeleteSelectionReque s.log.Error("Failed to delete selection", zap.Error(err)) return nil, err } - cacheKey := fmt.Sprintf("group:%s", in.GroupId) - err = s.cache.DeleteValue(cacheKey) - if err != nil { - s.log.Error("Failed to delete selection from cache", zap.Error(err)) - return nil, err - } + defer func() { + cacheKey := fmt.Sprintf("group:%s", in.GroupId) + err = s.cache.DeleteValue(cacheKey) + if err != nil { + s.log.Error("Failed to delete selection from cache", zap.Error(err)) + } + }() s.log.Info("Selection deleted", zap.String("group_id", in.GroupId)) From de87d565afe4658df0185d088bcfc04b3e7360af Mon Sep 17 00:00:00 2001 From: wiraphat <132466647+wiraphatys@users.noreply.github.com> Date: Sun, 30 Jun 2024 20:09:33 +0700 Subject: [PATCH 06/16] init: selection service to grpc server --- cmd/main.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cmd/main.go b/cmd/main.go index e083d33..bc55f75 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -15,10 +15,12 @@ import ( "github.com/isd-sgcu/rpkm67-backend/internal/cache" "github.com/isd-sgcu/rpkm67-backend/internal/group" "github.com/isd-sgcu/rpkm67-backend/internal/pin" + "github.com/isd-sgcu/rpkm67-backend/internal/selection" "github.com/isd-sgcu/rpkm67-backend/internal/stamp" "github.com/isd-sgcu/rpkm67-backend/logger" groupProto "github.com/isd-sgcu/rpkm67-go-proto/rpkm67/backend/group/v1" pinProto "github.com/isd-sgcu/rpkm67-go-proto/rpkm67/backend/pin/v1" + selectionProto "github.com/isd-sgcu/rpkm67-go-proto/rpkm67/backend/selection/v1" stampProto "github.com/isd-sgcu/rpkm67-go-proto/rpkm67/backend/stamp/v1" "go.uber.org/zap" "google.golang.org/grpc" @@ -55,7 +57,8 @@ func main() { groupRepo := group.NewRepository(db) groupSvc := group.NewService(groupRepo, cacheRepo, logger.Named("groupSvc")) - // selectionRepo := selection.NewRepository(db) + selectionRepo := selection.NewRepository(db) + selectionSvc := selection.NewService(selectionRepo, cacheRepo, logger.Named("selectionSvc")) listener, err := net.Listen("tcp", fmt.Sprintf(":%v", conf.App.Port)) if err != nil { @@ -67,6 +70,7 @@ func main() { pinProto.RegisterPinServiceServer(grpcServer, pinSvc) stampProto.RegisterStampServiceServer(grpcServer, stampSvc) groupProto.RegisterGroupServiceServer(grpcServer, groupSvc) + selectionProto.RegisterSelectionServiceServer(grpcServer, selectionSvc) reflection.Register(grpcServer) go func() { From 0ddbafdcb1bd93656e0c156148ed016224d30c43 Mon Sep 17 00:00:00 2001 From: flagrantii Date: Tue, 2 Jul 2024 15:54:41 +0700 Subject: [PATCH 07/16] Feat: Add selection repository and service for counting selections by baan ID --- Makefile | 2 + go.mod | 4 +- go.sum | 4 + internal/selection/selection.repository.go | 10 +- internal/selection/selection.service.go | 4 +- mocks/selection/selection.repository.go | 92 ++++++++++++++++++ mocks/selection/selection.service.go | 108 +++++++++++++++++++++ 7 files changed, 215 insertions(+), 9 deletions(-) create mode 100644 mocks/selection/selection.repository.go create mode 100644 mocks/selection/selection.service.go diff --git a/Makefile b/Makefile index 4be5439..87546cc 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,8 @@ mock-gen: mockgen -source ./internal/pin/pin.service.go -destination ./mocks/pin/pin.service.go mockgen -source ./internal/stamp/stamp.repository.go -destination ./mocks/stamp/stamp.repository.go mockgen -source ./internal/stamp/stamp.service.go -destination ./mocks/stamp/stamp.service.go + mockgen -source ./internal/selection/selection.repository.go -destination ./mocks/selection/selection.repository.go + mockgen -source ./internal/selection/selection.service.go -destination ./mocks/selection/selection.service.go test: go vet ./... diff --git a/go.mod b/go.mod index a598e95..276cf11 100644 --- a/go.mod +++ b/go.mod @@ -5,8 +5,8 @@ go 1.22.4 require ( github.com/golang/mock v1.6.0 github.com/google/uuid v1.6.0 - github.com/isd-sgcu/rpkm67-go-proto v0.1.6 - github.com/isd-sgcu/rpkm67-model v0.0.1 + github.com/isd-sgcu/rpkm67-go-proto v0.2.3 + github.com/isd-sgcu/rpkm67-model v0.0.6 github.com/joho/godotenv v1.5.1 github.com/redis/go-redis/v9 v9.5.3 github.com/stretchr/testify v1.9.0 diff --git a/go.sum b/go.sum index b827df9..0891156 100644 --- a/go.sum +++ b/go.sum @@ -17,8 +17,12 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/isd-sgcu/rpkm67-go-proto v0.1.6 h1:6mubghe7HuGJYv+hgpIxJBBrmVk5UdjHjdvzykLLhQ0= github.com/isd-sgcu/rpkm67-go-proto v0.1.6/go.mod h1:Z5SYz5kEe4W+MdqPouF0zEOiaqvg+s9I1S5d0q6e+Jw= +github.com/isd-sgcu/rpkm67-go-proto v0.2.3 h1:u4ROlwsTmzcXgW3ED2UobPvF1OF+jykHH9AEH8F3XcU= +github.com/isd-sgcu/rpkm67-go-proto v0.2.3/go.mod h1:Z5SYz5kEe4W+MdqPouF0zEOiaqvg+s9I1S5d0q6e+Jw= github.com/isd-sgcu/rpkm67-model v0.0.1 h1:LFn7jaawkZP1golE9B32a2KL/U/w20UFjQo2Cd/3Fhc= github.com/isd-sgcu/rpkm67-model v0.0.1/go.mod h1:dxgLSkrFpbQOXsrzqgepZoEOyZUIG2LBGtm5gsuBbVc= +github.com/isd-sgcu/rpkm67-model v0.0.6 h1:pYlqOmeXGQIfHdOhyAta4kXkqnoLc4X3KWcAjPrAuds= +github.com/isd-sgcu/rpkm67-model v0.0.6/go.mod h1:dxgLSkrFpbQOXsrzqgepZoEOyZUIG2LBGtm5gsuBbVc= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= diff --git a/internal/selection/selection.repository.go b/internal/selection/selection.repository.go index d0584af..f020dd4 100644 --- a/internal/selection/selection.repository.go +++ b/internal/selection/selection.repository.go @@ -9,7 +9,7 @@ type Repository interface { Create(user *model.Selection) error FindByGroupId(groupId string, selections *[]model.Selection) error Delete(id string) error - CountGroupByBaanId() (map[string]int, error) + CountByBaanId() (map[string]int, error) } type repositoryImpl struct { @@ -34,10 +34,10 @@ func (r *repositoryImpl) Delete(groupId string) error { return r.Db.Delete(&model.Selection{}, "group_id = ?", groupId).Error } -func (r *repositoryImpl) CountGroupByBaanId() (map[string]int, error) { +func (r *repositoryImpl) CountByBaanId() (map[string]int, error) { var result []struct { - BaanId string - Count int + Baan string + Count int } if err := r.Db.Model(&model.Selection{}).Select("baan, count(*) as count").Group("baan").Scan(&result).Error; err != nil { return nil, err @@ -45,7 +45,7 @@ func (r *repositoryImpl) CountGroupByBaanId() (map[string]int, error) { count := make(map[string]int) for _, v := range result { - count[v.BaanId] = v.Count + count[v.Baan] = v.Count } return count, nil diff --git a/internal/selection/selection.service.go b/internal/selection/selection.service.go index 15a5128..e67565f 100644 --- a/internal/selection/selection.service.go +++ b/internal/selection/selection.service.go @@ -158,8 +158,8 @@ func (s *serviceImpl) Delete(ctx context.Context, in *proto.DeleteSelectionReque return &proto.DeleteSelectionResponse{Success: true}, nil } -func (s *serviceImpl) CountGroupByBaanId(ctx context.Context, in *proto.CountByBaanIdSelectionRequest) (*proto.CountByBaanIdSelectionResponse, error) { - count, err := s.repo.CountGroupByBaanId() +func (s *serviceImpl) CountByBaanId(ctx context.Context, in *proto.CountByBaanIdSelectionRequest) (*proto.CountByBaanIdSelectionResponse, error) { + count, err := s.repo.CountByBaanId() if err != nil { s.log.Error("Failed to count group by baan id", zap.Error(err)) return nil, err diff --git a/mocks/selection/selection.repository.go b/mocks/selection/selection.repository.go new file mode 100644 index 0000000..ce4de67 --- /dev/null +++ b/mocks/selection/selection.repository.go @@ -0,0 +1,92 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: ./internal/selection/selection.repository.go + +// Package mock_selection is a generated GoMock package. +package mock_selection + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + model "github.com/isd-sgcu/rpkm67-model/model" +) + +// MockRepository is a mock of Repository interface. +type MockRepository struct { + ctrl *gomock.Controller + recorder *MockRepositoryMockRecorder +} + +// MockRepositoryMockRecorder is the mock recorder for MockRepository. +type MockRepositoryMockRecorder struct { + mock *MockRepository +} + +// NewMockRepository creates a new mock instance. +func NewMockRepository(ctrl *gomock.Controller) *MockRepository { + mock := &MockRepository{ctrl: ctrl} + mock.recorder = &MockRepositoryMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockRepository) EXPECT() *MockRepositoryMockRecorder { + return m.recorder +} + +// CountGroupByBaanId mocks base method. +func (m *MockRepository) CountGroupByBaanId() (map[string]int, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CountGroupByBaanId") + ret0, _ := ret[0].(map[string]int) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CountGroupByBaanId indicates an expected call of CountGroupByBaanId. +func (mr *MockRepositoryMockRecorder) CountGroupByBaanId() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CountGroupByBaanId", reflect.TypeOf((*MockRepository)(nil).CountGroupByBaanId)) +} + +// Create mocks base method. +func (m *MockRepository) Create(user *model.Selection) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Create", user) + ret0, _ := ret[0].(error) + return ret0 +} + +// Create indicates an expected call of Create. +func (mr *MockRepositoryMockRecorder) Create(user interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockRepository)(nil).Create), user) +} + +// Delete mocks base method. +func (m *MockRepository) Delete(id string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", id) + ret0, _ := ret[0].(error) + return ret0 +} + +// Delete indicates an expected call of Delete. +func (mr *MockRepositoryMockRecorder) Delete(id interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockRepository)(nil).Delete), id) +} + +// FindByGroupId mocks base method. +func (m *MockRepository) FindByGroupId(groupId string, selections *[]model.Selection) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FindByGroupId", groupId, selections) + ret0, _ := ret[0].(error) + return ret0 +} + +// FindByGroupId indicates an expected call of FindByGroupId. +func (mr *MockRepositoryMockRecorder) FindByGroupId(groupId, selections interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindByGroupId", reflect.TypeOf((*MockRepository)(nil).FindByGroupId), groupId, selections) +} diff --git a/mocks/selection/selection.service.go b/mocks/selection/selection.service.go new file mode 100644 index 0000000..05419a9 --- /dev/null +++ b/mocks/selection/selection.service.go @@ -0,0 +1,108 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: ./internal/selection/selection.service.go + +// Package mock_selection is a generated GoMock package. +package mock_selection + +import ( + context "context" + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + v1 "github.com/isd-sgcu/rpkm67-go-proto/rpkm67/backend/selection/v1" +) + +// MockService is a mock of Service interface. +type MockService struct { + ctrl *gomock.Controller + recorder *MockServiceMockRecorder +} + +// MockServiceMockRecorder is the mock recorder for MockService. +type MockServiceMockRecorder struct { + mock *MockService +} + +// NewMockService creates a new mock instance. +func NewMockService(ctrl *gomock.Controller) *MockService { + mock := &MockService{ctrl: ctrl} + mock.recorder = &MockServiceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockService) EXPECT() *MockServiceMockRecorder { + return m.recorder +} + +// CountByBaanId mocks base method. +func (m *MockService) CountByBaanId(arg0 context.Context, arg1 *v1.CountByBaanIdSelectionRequest) (*v1.CountByBaanIdSelectionResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CountByBaanId", arg0, arg1) + ret0, _ := ret[0].(*v1.CountByBaanIdSelectionResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CountByBaanId indicates an expected call of CountByBaanId. +func (mr *MockServiceMockRecorder) CountByBaanId(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CountByBaanId", reflect.TypeOf((*MockService)(nil).CountByBaanId), arg0, arg1) +} + +// Create mocks base method. +func (m *MockService) Create(arg0 context.Context, arg1 *v1.CreateSelectionRequest) (*v1.CreateSelectionResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Create", arg0, arg1) + ret0, _ := ret[0].(*v1.CreateSelectionResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Create indicates an expected call of Create. +func (mr *MockServiceMockRecorder) Create(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockService)(nil).Create), arg0, arg1) +} + +// Delete mocks base method. +func (m *MockService) Delete(arg0 context.Context, arg1 *v1.DeleteSelectionRequest) (*v1.DeleteSelectionResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", arg0, arg1) + ret0, _ := ret[0].(*v1.DeleteSelectionResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Delete indicates an expected call of Delete. +func (mr *MockServiceMockRecorder) Delete(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockService)(nil).Delete), arg0, arg1) +} + +// FindByGroupId mocks base method. +func (m *MockService) FindByGroupId(arg0 context.Context, arg1 *v1.FindByGroupIdSelectionRequest) (*v1.FindByGroupIdSelectionResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FindByGroupId", arg0, arg1) + ret0, _ := ret[0].(*v1.FindByGroupIdSelectionResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FindByGroupId indicates an expected call of FindByGroupId. +func (mr *MockServiceMockRecorder) FindByGroupId(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindByGroupId", reflect.TypeOf((*MockService)(nil).FindByGroupId), arg0, arg1) +} + +// mustEmbedUnimplementedSelectionServiceServer mocks base method. +func (m *MockService) mustEmbedUnimplementedSelectionServiceServer() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "mustEmbedUnimplementedSelectionServiceServer") +} + +// mustEmbedUnimplementedSelectionServiceServer indicates an expected call of mustEmbedUnimplementedSelectionServiceServer. +func (mr *MockServiceMockRecorder) mustEmbedUnimplementedSelectionServiceServer() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "mustEmbedUnimplementedSelectionServiceServer", reflect.TypeOf((*MockService)(nil).mustEmbedUnimplementedSelectionServiceServer)) +} From ac41f0283de02cdc599c65297540b367e656fdbc Mon Sep 17 00:00:00 2001 From: flagrantii Date: Wed, 3 Jul 2024 16:19:56 +0700 Subject: [PATCH 08/16] Feat : add update Selection --- go.mod | 2 +- go.sum | 10 ++- internal/selection/selection.repository.go | 62 +++++++++++++++++- internal/selection/selection.service.go | 74 ++++++++++++++++++++++ mocks/selection/selection.repository.go | 12 ++-- 5 files changed, 146 insertions(+), 14 deletions(-) diff --git a/go.mod b/go.mod index 276cf11..99dcdc3 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.22.4 require ( github.com/golang/mock v1.6.0 github.com/google/uuid v1.6.0 - github.com/isd-sgcu/rpkm67-go-proto v0.2.3 + github.com/isd-sgcu/rpkm67-go-proto v0.2.7 github.com/isd-sgcu/rpkm67-model v0.0.6 github.com/joho/godotenv v1.5.1 github.com/redis/go-redis/v9 v9.5.3 diff --git a/go.sum b/go.sum index 0891156..1ea8705 100644 --- a/go.sum +++ b/go.sum @@ -15,12 +15,10 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/isd-sgcu/rpkm67-go-proto v0.1.6 h1:6mubghe7HuGJYv+hgpIxJBBrmVk5UdjHjdvzykLLhQ0= -github.com/isd-sgcu/rpkm67-go-proto v0.1.6/go.mod h1:Z5SYz5kEe4W+MdqPouF0zEOiaqvg+s9I1S5d0q6e+Jw= -github.com/isd-sgcu/rpkm67-go-proto v0.2.3 h1:u4ROlwsTmzcXgW3ED2UobPvF1OF+jykHH9AEH8F3XcU= -github.com/isd-sgcu/rpkm67-go-proto v0.2.3/go.mod h1:Z5SYz5kEe4W+MdqPouF0zEOiaqvg+s9I1S5d0q6e+Jw= -github.com/isd-sgcu/rpkm67-model v0.0.1 h1:LFn7jaawkZP1golE9B32a2KL/U/w20UFjQo2Cd/3Fhc= -github.com/isd-sgcu/rpkm67-model v0.0.1/go.mod h1:dxgLSkrFpbQOXsrzqgepZoEOyZUIG2LBGtm5gsuBbVc= +github.com/isd-sgcu/rpkm67-go-proto v0.2.6 h1:ZzCqW09c7QyRwIzrQA2Kp4+0IYxB6A3iVtzp9Jn+QSI= +github.com/isd-sgcu/rpkm67-go-proto v0.2.6/go.mod h1:Z5SYz5kEe4W+MdqPouF0zEOiaqvg+s9I1S5d0q6e+Jw= +github.com/isd-sgcu/rpkm67-go-proto v0.2.7 h1:Sfq5r2+IN2Q4+MJCysWeEjcQ4MtcylBAdChOOVCLUN0= +github.com/isd-sgcu/rpkm67-go-proto v0.2.7/go.mod h1:Z5SYz5kEe4W+MdqPouF0zEOiaqvg+s9I1S5d0q6e+Jw= github.com/isd-sgcu/rpkm67-model v0.0.6 h1:pYlqOmeXGQIfHdOhyAta4kXkqnoLc4X3KWcAjPrAuds= github.com/isd-sgcu/rpkm67-model v0.0.6/go.mod h1:dxgLSkrFpbQOXsrzqgepZoEOyZUIG2LBGtm5gsuBbVc= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= diff --git a/internal/selection/selection.repository.go b/internal/selection/selection.repository.go index f020dd4..b6b5aa6 100644 --- a/internal/selection/selection.repository.go +++ b/internal/selection/selection.repository.go @@ -8,8 +8,11 @@ import ( type Repository interface { Create(user *model.Selection) error FindByGroupId(groupId string, selections *[]model.Selection) error - Delete(id string) error + Delete(groupId string) error CountByBaanId() (map[string]int, error) + UpdateNewBaanExistOrder(updateSelection *model.Selection, selections *[]model.Selection) error + UpdateExistBaanExistOrder(updateSelection *model.Selection, selections *[]model.Selection) error + UpdateExistBaanNewOrder(updateSelection *model.Selection, selections *[]model.Selection) error } type repositoryImpl struct { @@ -50,3 +53,60 @@ func (r *repositoryImpl) CountByBaanId() (map[string]int, error) { return count, nil } + +func (r *repositoryImpl) UpdateNewBaanExistOrder(updateSelection *model.Selection, selections *[]model.Selection) error { + return r.Db.Transaction(func(tx *gorm.DB) error { + var existingSelection model.Selection + if err := tx.Where(`group_id = ? AND "order" = ?`, updateSelection.GroupID, updateSelection.Order).First(&existingSelection).Error; err != nil { + return err + } + + if err := tx.Where(`"order" = ?`, updateSelection.Order).Model(&existingSelection).Update("baan", updateSelection.Baan).Error; err != nil { + return err + } + + return nil + }) +} + +func (r *repositoryImpl) UpdateExistBaanExistOrder(updateSelection *model.Selection, selections *[]model.Selection) error { + return r.Db.Transaction(func(tx *gorm.DB) error { + var existingBaanSelection model.Selection + if err := tx.Where("group_id = ? AND baan = ?", updateSelection.GroupID, updateSelection.Baan).First(&existingBaanSelection).Error; err != nil { + return err + } + + var existingOrderSelection model.Selection + if err := tx.Where(`group_id = ? AND "order" = ?`, updateSelection.GroupID, updateSelection.Order).First(&existingOrderSelection).Error; err != nil { + return err + } + + if existingBaanSelection.Order == updateSelection.Order { + return nil + } + + if err := tx.Where(`"order" = ?`, existingBaanSelection.Order).Model(&existingBaanSelection).Update("baan", existingOrderSelection.Baan).Error; err != nil { + return err + } + if err := tx.Where(`"order" = ?`, existingOrderSelection.Order).Model(&existingOrderSelection).Update("baan", existingBaanSelection.Baan).Error; err != nil { + return err + } + + return nil + }) +} + +func (r *repositoryImpl) UpdateExistBaanNewOrder(updateSelection *model.Selection, selections *[]model.Selection) error { + return r.Db.Transaction(func(tx *gorm.DB) error { + var existingSelection model.Selection + if err := tx.Where("group_id = ? AND baan = ?", updateSelection.GroupID, updateSelection.Baan).First(&existingSelection).Error; err != nil { + return err + } + + if err := tx.Where("baan = ?", updateSelection.Baan).Model(&existingSelection).Update("order", updateSelection.Order).Error; err != nil { + return err + } + + return nil + }) +} diff --git a/internal/selection/selection.service.go b/internal/selection/selection.service.go index e67565f..6d2fe91 100644 --- a/internal/selection/selection.service.go +++ b/internal/selection/selection.service.go @@ -60,6 +60,12 @@ func (s *serviceImpl) Create(ctx context.Context, in *proto.CreateSelectionReque } } + //Order must be in range 1-5 + if in.Order < 1 || in.Order > 5 { + s.log.Error("Failed to create selection", zap.Error(err)) + return nil, fmt.Errorf("Order must be in range 1-5") + } + //Create selection selection := model.Selection{ GroupID: &GroupUuid, @@ -183,3 +189,71 @@ func (s *serviceImpl) CountByBaanId(ctx context.Context, in *proto.CountByBaanId return &res, nil } + +func (s *serviceImpl) Update(ctx context.Context, in *proto.UpdateSelectionRequest) (*proto.UpdateSelectionResponse, error) { + oldSelections := &[]model.Selection{} + + err := s.repo.FindByGroupId(in.Selection.GroupId, oldSelections) + if err != nil { + s.log.Error("Failed to find selection", zap.String("group_id", in.Selection.GroupId), zap.Error(err)) + return nil, err + } + + groupUUID, err := uuid.Parse(in.Selection.GroupId) + if err != nil { + s.log.Error("Failed to parse group id", zap.Error(err)) + return nil, err + } + + //Order must be in range 1-5 + if in.Selection.Order < 1 || in.Selection.Order > 5 { + s.log.Error("Failed to create selection", zap.Error(err)) + return nil, fmt.Errorf("Order must be in range 1-5") + } + + newSelection := model.Selection{ + GroupID: &groupUUID, + Baan: in.Selection.BaanId, + Order: int(in.Selection.Order), + } + + // Check if the new Baan exists in oldSelections + baanExists := false + orderExists := false + for _, oldSel := range *oldSelections { + if oldSel.Baan == newSelection.Baan { + baanExists = true + } + if oldSel.Order == newSelection.Order { + orderExists = true + } + } + + var updateErr error + + if !baanExists && orderExists { + updateErr = s.repo.UpdateNewBaanExistOrder(&newSelection, oldSelections) + } else if baanExists && orderExists { + updateErr = s.repo.UpdateExistBaanExistOrder(&newSelection, oldSelections) + } else if baanExists && !orderExists { + updateErr = s.repo.UpdateExistBaanNewOrder(&newSelection, oldSelections) + } else { + s.log.Error("Invalid update scenario", zap.String("group_id", in.Selection.GroupId), zap.String("baan_id", in.Selection.BaanId)) + return nil, err + } + + if updateErr != nil { + s.log.Error("Failed to update selection", zap.String("group_id", in.Selection.GroupId), zap.Error(updateErr)) + return nil, updateErr + } + + res := proto.UpdateSelectionResponse{ + Success: true, + } + + s.log.Info("Selection updated", + zap.String("group_id", in.Selection.GroupId), + zap.String("baan_id", in.Selection.BaanId)) + + return &res, nil +} diff --git a/mocks/selection/selection.repository.go b/mocks/selection/selection.repository.go index ce4de67..1fd7268 100644 --- a/mocks/selection/selection.repository.go +++ b/mocks/selection/selection.repository.go @@ -34,19 +34,19 @@ func (m *MockRepository) EXPECT() *MockRepositoryMockRecorder { return m.recorder } -// CountGroupByBaanId mocks base method. -func (m *MockRepository) CountGroupByBaanId() (map[string]int, error) { +// CountByBaanId mocks base method. +func (m *MockRepository) CountByBaanId() (map[string]int, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CountGroupByBaanId") + ret := m.ctrl.Call(m, "CountByBaanId") ret0, _ := ret[0].(map[string]int) ret1, _ := ret[1].(error) return ret0, ret1 } -// CountGroupByBaanId indicates an expected call of CountGroupByBaanId. -func (mr *MockRepositoryMockRecorder) CountGroupByBaanId() *gomock.Call { +// CountByBaanId indicates an expected call of CountByBaanId. +func (mr *MockRepositoryMockRecorder) CountByBaanId() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CountGroupByBaanId", reflect.TypeOf((*MockRepository)(nil).CountGroupByBaanId)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CountByBaanId", reflect.TypeOf((*MockRepository)(nil).CountByBaanId)) } // Create mocks base method. From b97a34088bb7302ddef9457a260f71b30e8f05b5 Mon Sep 17 00:00:00 2001 From: flagrantii Date: Wed, 3 Jul 2024 18:18:38 +0700 Subject: [PATCH 09/16] Fix : swapUpdate --- internal/selection/selection.repository.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/selection/selection.repository.go b/internal/selection/selection.repository.go index b6b5aa6..518cff7 100644 --- a/internal/selection/selection.repository.go +++ b/internal/selection/selection.repository.go @@ -88,7 +88,7 @@ func (r *repositoryImpl) UpdateExistBaanExistOrder(updateSelection *model.Select if err := tx.Where(`"order" = ?`, existingBaanSelection.Order).Model(&existingBaanSelection).Update("baan", existingOrderSelection.Baan).Error; err != nil { return err } - if err := tx.Where(`"order" = ?`, existingOrderSelection.Order).Model(&existingOrderSelection).Update("baan", existingBaanSelection.Baan).Error; err != nil { + if err := tx.Where(`"order" = ?`, existingOrderSelection.Order).Model(&existingOrderSelection).Update("baan", updateSelection.Baan).Error; err != nil { return err } From aaee62e7e15b8a0c23987391ee094ae113921088 Mon Sep 17 00:00:00 2001 From: flagrantii Date: Wed, 3 Jul 2024 20:55:38 +0700 Subject: [PATCH 10/16] Feat: update delete seletion --- go.mod | 10 +++++----- go.sum | 10 ++++++++++ internal/selection/selection.repository.go | 6 +++--- internal/selection/selection.service.go | 2 +- 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 99dcdc3..393e3c9 100644 --- a/go.mod +++ b/go.mod @@ -5,19 +5,19 @@ go 1.22.4 require ( github.com/golang/mock v1.6.0 github.com/google/uuid v1.6.0 - github.com/isd-sgcu/rpkm67-go-proto v0.2.7 + github.com/isd-sgcu/rpkm67-go-proto v0.2.8 github.com/isd-sgcu/rpkm67-model v0.0.6 github.com/joho/godotenv v1.5.1 github.com/redis/go-redis/v9 v9.5.3 github.com/stretchr/testify v1.9.0 go.uber.org/zap v1.27.0 - google.golang.org/grpc v1.64.0 + google.golang.org/grpc v1.65.0 gorm.io/driver/postgres v1.5.9 gorm.io/gorm v1.25.10 ) require ( - github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/jackc/pgpassfile v1.0.0 // indirect @@ -30,11 +30,11 @@ require ( github.com/rogpeppe/go-internal v1.12.0 // indirect go.uber.org/multierr v1.10.0 // indirect golang.org/x/crypto v0.24.0 // indirect - golang.org/x/net v0.22.0 // indirect + golang.org/x/net v0.25.0 // indirect golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.21.0 // indirect golang.org/x/text v0.16.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect google.golang.org/protobuf v1.34.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 1ea8705..d2d8e30 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -19,6 +21,8 @@ github.com/isd-sgcu/rpkm67-go-proto v0.2.6 h1:ZzCqW09c7QyRwIzrQA2Kp4+0IYxB6A3iVt github.com/isd-sgcu/rpkm67-go-proto v0.2.6/go.mod h1:Z5SYz5kEe4W+MdqPouF0zEOiaqvg+s9I1S5d0q6e+Jw= github.com/isd-sgcu/rpkm67-go-proto v0.2.7 h1:Sfq5r2+IN2Q4+MJCysWeEjcQ4MtcylBAdChOOVCLUN0= github.com/isd-sgcu/rpkm67-go-proto v0.2.7/go.mod h1:Z5SYz5kEe4W+MdqPouF0zEOiaqvg+s9I1S5d0q6e+Jw= +github.com/isd-sgcu/rpkm67-go-proto v0.2.8 h1:YDkxRcu204XD70E+xJSYt/4XmwXuM13nVNiEWflc73c= +github.com/isd-sgcu/rpkm67-go-proto v0.2.8/go.mod h1:w+UCeQnJ3wBuJ7Tyf8LiBiPZVb1KlecjMNCB7kBeL7M= github.com/isd-sgcu/rpkm67-model v0.0.6 h1:pYlqOmeXGQIfHdOhyAta4kXkqnoLc4X3KWcAjPrAuds= github.com/isd-sgcu/rpkm67-model v0.0.6/go.mod h1:dxgLSkrFpbQOXsrzqgepZoEOyZUIG2LBGtm5gsuBbVc= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= @@ -67,6 +71,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= @@ -91,8 +97,12 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc= google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 h1:Zy9XzmMEflZ/MAaA7vNcoebnRAld7FsPW1EeBB7V0m8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= +google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= +google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/internal/selection/selection.repository.go b/internal/selection/selection.repository.go index 518cff7..e8c3b63 100644 --- a/internal/selection/selection.repository.go +++ b/internal/selection/selection.repository.go @@ -8,7 +8,7 @@ import ( type Repository interface { Create(user *model.Selection) error FindByGroupId(groupId string, selections *[]model.Selection) error - Delete(groupId string) error + Delete(groupId string, baanId string) error CountByBaanId() (map[string]int, error) UpdateNewBaanExistOrder(updateSelection *model.Selection, selections *[]model.Selection) error UpdateExistBaanExistOrder(updateSelection *model.Selection, selections *[]model.Selection) error @@ -33,8 +33,8 @@ func (r *repositoryImpl) FindByGroupId(groupId string, selections *[]model.Selec return r.Db.Find(selections, "group_id = ?", groupId).Error } -func (r *repositoryImpl) Delete(groupId string) error { - return r.Db.Delete(&model.Selection{}, "group_id = ?", groupId).Error +func (r *repositoryImpl) Delete(groupId string, baanId string) error { + return r.Db.Delete(&model.Selection{}, "group_id = ? AND baan = ?", groupId, baanId).Error } func (r *repositoryImpl) CountByBaanId() (map[string]int, error) { diff --git a/internal/selection/selection.service.go b/internal/selection/selection.service.go index 6d2fe91..92cb7f8 100644 --- a/internal/selection/selection.service.go +++ b/internal/selection/selection.service.go @@ -144,7 +144,7 @@ func (s *serviceImpl) FindByGroupId(ctx context.Context, in *proto.FindByGroupId } func (s *serviceImpl) Delete(ctx context.Context, in *proto.DeleteSelectionRequest) (*proto.DeleteSelectionResponse, error) { - err := s.repo.Delete(in.GroupId) + err := s.repo.Delete(in.GroupId, in.BaanId) if err != nil { s.log.Error("Failed to delete selection", zap.Error(err)) return nil, err From f4f77dcb2486a6be6ef5f24f37835076330529d6 Mon Sep 17 00:00:00 2001 From: flagrantii Date: Wed, 3 Jul 2024 21:09:26 +0700 Subject: [PATCH 11/16] Feat : add group in main --- cmd/main.go | 7 ++++++- go.mod | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/cmd/main.go b/cmd/main.go index db8aafa..1d99558 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -13,6 +13,8 @@ import ( "github.com/isd-sgcu/rpkm67-backend/config" "github.com/isd-sgcu/rpkm67-backend/constant" "github.com/isd-sgcu/rpkm67-backend/database" + "github.com/isd-sgcu/rpkm67-backend/internal/cache" + "github.com/isd-sgcu/rpkm67-backend/internal/group" "github.com/isd-sgcu/rpkm67-backend/internal/pin" "github.com/isd-sgcu/rpkm67-backend/internal/selection" "github.com/isd-sgcu/rpkm67-backend/internal/stamp" @@ -46,7 +48,7 @@ func main() { panic(fmt.Sprintf("Failed to connect to redis: %v", err)) } - // cacheRepo := cache.NewRepository(redis) + cacheRepo := cache.NewRepository(redis) pinRepo := pin.NewRepository(redis) pinUtils := pin.NewUtils() @@ -55,6 +57,9 @@ func main() { stampRepo := stamp.NewRepository(db) stampSvc := stamp.NewService(stampRepo, constant.ActivityIdToIdx, logger.Named("stampSvc")) + groupRepo := group.NewRepository(db) + groupSvc := group.NewService(groupRepo, cacheRepo, logger.Named("groupSvc")) + selectionRepo := selection.NewRepository(db) selectionSvc := selection.NewService(selectionRepo, cacheRepo, logger.Named("selectionSvc")) diff --git a/go.mod b/go.mod index 393e3c9..cb668e0 100644 --- a/go.mod +++ b/go.mod @@ -30,6 +30,7 @@ require ( github.com/rogpeppe/go-internal v1.12.0 // indirect go.uber.org/multierr v1.10.0 // indirect golang.org/x/crypto v0.24.0 // indirect + golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 golang.org/x/net v0.25.0 // indirect golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.21.0 // indirect From 93c20bc24088f57860bd5b58070dc27680319796 Mon Sep 17 00:00:00 2001 From: flagrantii Date: Wed, 3 Jul 2024 21:37:30 +0700 Subject: [PATCH 12/16] Feat : remove selection cache, add CountBaan cache --- internal/selection/selection.service.go | 42 ++++++++++--------------- 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/internal/selection/selection.service.go b/internal/selection/selection.service.go index 92cb7f8..730f4b2 100644 --- a/internal/selection/selection.service.go +++ b/internal/selection/selection.service.go @@ -79,14 +79,6 @@ func (s *serviceImpl) Create(ctx context.Context, in *proto.CreateSelectionReque return nil, err } - defer func() { - cacheKey := fmt.Sprintf("group:%s", in.GroupId) - err = s.cache.SetValue(cacheKey, selection, 3600) - if err != nil { - s.log.Error("Failed to cache selection", zap.Error(err)) - } - }() - res := proto.CreateSelectionResponse{ Selection: &proto.Selection{ Id: "", @@ -104,18 +96,9 @@ func (s *serviceImpl) Create(ctx context.Context, in *proto.CreateSelectionReque } func (s *serviceImpl) FindByGroupId(ctx context.Context, in *proto.FindByGroupIdSelectionRequest) (*proto.FindByGroupIdSelectionResponse, error) { - cacheKey := fmt.Sprintf("group:%s", in.GroupId) - var cachedSelection []*proto.Selection - - err := s.cache.GetValue(cacheKey, &cachedSelection) - if err == nil { - s.log.Info("Group found in cache", zap.String("user_id", in.GroupId)) - return &proto.FindByGroupIdSelectionResponse{Selections: cachedSelection}, nil - } - selection := &[]model.Selection{} - err = s.repo.FindByGroupId(in.GroupId, selection) + err := s.repo.FindByGroupId(in.GroupId, selection) if err != nil { s.log.Error("Failed to find selection", zap.String("group_id", in.GroupId), zap.Error(err)) return nil, err @@ -150,14 +133,6 @@ func (s *serviceImpl) Delete(ctx context.Context, in *proto.DeleteSelectionReque return nil, err } - defer func() { - cacheKey := fmt.Sprintf("group:%s", in.GroupId) - err = s.cache.DeleteValue(cacheKey) - if err != nil { - s.log.Error("Failed to delete selection from cache", zap.Error(err)) - } - }() - s.log.Info("Selection deleted", zap.String("group_id", in.GroupId)) @@ -165,6 +140,17 @@ func (s *serviceImpl) Delete(ctx context.Context, in *proto.DeleteSelectionReque } func (s *serviceImpl) CountByBaanId(ctx context.Context, in *proto.CountByBaanIdSelectionRequest) (*proto.CountByBaanIdSelectionResponse, error) { + cachedKey := "countByBaanId" + var cachedCount *proto.CountByBaanIdSelectionResponse + + err := s.cache.GetValue(cachedKey, &cachedCount) + if err == nil { + s.log.Info("Count group by baan id found in cache") + return &proto.CountByBaanIdSelectionResponse{ + BaanCounts: cachedCount.BaanCounts, + }, nil + } + count, err := s.repo.CountByBaanId() if err != nil { s.log.Error("Failed to count group by baan id", zap.Error(err)) @@ -184,6 +170,10 @@ func (s *serviceImpl) CountByBaanId(ctx context.Context, in *proto.CountByBaanId BaanCounts: countRPC, } + if err := s.cache.SetValue(cachedKey, &res, 3600); err != nil { + s.log.Warn("Failed to set count group by baan id in cache", zap.Error(err)) + } + s.log.Info("Count group by baan id", zap.Any("count", count)) From f81a6c64e55953ad202711df498f15752ee0745d Mon Sep 17 00:00:00 2001 From: flagrantii Date: Wed, 3 Jul 2024 21:44:54 +0700 Subject: [PATCH 13/16] Refector : selection logging error --- internal/selection/selection.service.go | 62 +++++++++++++------------ 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/internal/selection/selection.service.go b/internal/selection/selection.service.go index 730f4b2..11d267f 100644 --- a/internal/selection/selection.service.go +++ b/internal/selection/selection.service.go @@ -9,6 +9,8 @@ import ( proto "github.com/isd-sgcu/rpkm67-go-proto/rpkm67/backend/selection/v1" "github.com/isd-sgcu/rpkm67-model/model" "go.uber.org/zap" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) type Service interface { @@ -33,37 +35,37 @@ func NewService(repo Repository, cache cache.Repository, log *zap.Logger) Servic func (s *serviceImpl) Create(ctx context.Context, in *proto.CreateSelectionRequest) (*proto.CreateSelectionResponse, error) { GroupUuid, err := uuid.Parse(in.GroupId) if err != nil { - s.log.Error("Failed to parse group id", zap.Error(err)) - return nil, err + s.log.Named("Create").Error(fmt.Sprintf("Parse group id: %s", in.GroupId), zap.Error(err)) + return nil, status.Error(codes.Internal, err.Error()) } selections := &[]model.Selection{} err = s.repo.FindByGroupId(in.GroupId, selections) if err != nil { - s.log.Error("Failed to find selection", zap.Error(err)) - return nil, err + s.log.Named("Create").Error(fmt.Sprintf("FindByGroupId: group_id=%s", in.GroupId), zap.Error(err)) + return nil, status.Error(codes.Internal, err.Error()) } //Check can not create selection with same order for _, selection := range *selections { if selection.Order == int(in.Order) { - s.log.Error("Failed to create selection", zap.Error(err)) - return nil, fmt.Errorf("Can not create selection with same order") + s.log.Named("Create").Error(fmt.Sprintf("Failed to create selection: order=%d", in.Order), zap.Error(err)) + return nil, status.Error(codes.Internal, "Can not create selection with same order") } } //Check can not create selection with same baan for _, selection := range *selections { if selection.Baan == in.BaanId { - s.log.Error("Failed to create selection", zap.Error(err)) - return nil, fmt.Errorf("Can not create selection with same baan") + s.log.Named("Create").Error(fmt.Sprintf("Failed to create selection: baan_id=%s", in.BaanId), zap.Error(err)) + return nil, status.Error(codes.Internal, "Can not create selection with same baan") } } //Order must be in range 1-5 if in.Order < 1 || in.Order > 5 { - s.log.Error("Failed to create selection", zap.Error(err)) - return nil, fmt.Errorf("Order must be in range 1-5") + s.log.Named("Create").Error(fmt.Sprintf("Failed to create selection: order=%d", in.Order), zap.Error(err)) + return nil, status.Error(codes.Internal, "Order must be in range 1-5") } //Create selection @@ -75,8 +77,8 @@ func (s *serviceImpl) Create(ctx context.Context, in *proto.CreateSelectionReque err = s.repo.Create(&selection) if err != nil { - s.log.Error("Failed to create selection", zap.Error(err)) - return nil, err + s.log.Named("Create").Error(fmt.Sprintf("Create: group_id=%s, baan_id=%s", in.GroupId, in.BaanId), zap.Error(err)) + return nil, status.Error(codes.Internal, err.Error()) } res := proto.CreateSelectionResponse{ @@ -100,8 +102,8 @@ func (s *serviceImpl) FindByGroupId(ctx context.Context, in *proto.FindByGroupId err := s.repo.FindByGroupId(in.GroupId, selection) if err != nil { - s.log.Error("Failed to find selection", zap.String("group_id", in.GroupId), zap.Error(err)) - return nil, err + s.log.Named("FindByGroupId").Error(fmt.Sprintf("FindByGroupId: group_id=%s", in.GroupId), zap.Error(err)) + return nil, status.Error(codes.Internal, err.Error()) } selectionRPC := []*proto.Selection{} @@ -129,8 +131,8 @@ func (s *serviceImpl) FindByGroupId(ctx context.Context, in *proto.FindByGroupId func (s *serviceImpl) Delete(ctx context.Context, in *proto.DeleteSelectionRequest) (*proto.DeleteSelectionResponse, error) { err := s.repo.Delete(in.GroupId, in.BaanId) if err != nil { - s.log.Error("Failed to delete selection", zap.Error(err)) - return nil, err + s.log.Named("Delete").Error(fmt.Sprintf("Delete: group_id=%s, baan_id=%s", in.GroupId, in.BaanId), zap.Error(err)) + return nil, status.Error(codes.Internal, err.Error()) } s.log.Info("Selection deleted", @@ -145,7 +147,7 @@ func (s *serviceImpl) CountByBaanId(ctx context.Context, in *proto.CountByBaanId err := s.cache.GetValue(cachedKey, &cachedCount) if err == nil { - s.log.Info("Count group by baan id found in cache") + s.log.Named("CountByBaanId").Info("Count group by baan id found in cache") return &proto.CountByBaanIdSelectionResponse{ BaanCounts: cachedCount.BaanCounts, }, nil @@ -153,8 +155,8 @@ func (s *serviceImpl) CountByBaanId(ctx context.Context, in *proto.CountByBaanId count, err := s.repo.CountByBaanId() if err != nil { - s.log.Error("Failed to count group by baan id", zap.Error(err)) - return nil, err + s.log.Named("CountByBaanId").Error("CountByBaanId", zap.Error(err)) + return nil, status.Error(codes.Internal, err.Error()) } countRPC := []*proto.BaanCount{} @@ -171,7 +173,7 @@ func (s *serviceImpl) CountByBaanId(ctx context.Context, in *proto.CountByBaanId } if err := s.cache.SetValue(cachedKey, &res, 3600); err != nil { - s.log.Warn("Failed to set count group by baan id in cache", zap.Error(err)) + s.log.Named("CountByBaanId").Warn("Failed to set count group by baan id in cache", zap.Error(err)) } s.log.Info("Count group by baan id", @@ -185,20 +187,20 @@ func (s *serviceImpl) Update(ctx context.Context, in *proto.UpdateSelectionReque err := s.repo.FindByGroupId(in.Selection.GroupId, oldSelections) if err != nil { - s.log.Error("Failed to find selection", zap.String("group_id", in.Selection.GroupId), zap.Error(err)) - return nil, err + s.log.Named("Update").Error(fmt.Sprintf("FindByGroupId: group_id=%s", in.Selection.GroupId), zap.Error(err)) + return nil, status.Error(codes.Internal, err.Error()) } groupUUID, err := uuid.Parse(in.Selection.GroupId) if err != nil { - s.log.Error("Failed to parse group id", zap.Error(err)) - return nil, err + s.log.Named("Update").Error(fmt.Sprintf("Parse group id: %s", in.Selection.GroupId), zap.Error(err)) + return nil, status.Error(codes.Internal, err.Error()) } //Order must be in range 1-5 if in.Selection.Order < 1 || in.Selection.Order > 5 { - s.log.Error("Failed to create selection", zap.Error(err)) - return nil, fmt.Errorf("Order must be in range 1-5") + s.log.Named("Update").Error(fmt.Sprintf("Failed to update selection: order=%d", in.Selection.Order), zap.Error(err)) + return nil, status.Error(codes.Internal, "Order must be in range 1-5") } newSelection := model.Selection{ @@ -228,13 +230,13 @@ func (s *serviceImpl) Update(ctx context.Context, in *proto.UpdateSelectionReque } else if baanExists && !orderExists { updateErr = s.repo.UpdateExistBaanNewOrder(&newSelection, oldSelections) } else { - s.log.Error("Invalid update scenario", zap.String("group_id", in.Selection.GroupId), zap.String("baan_id", in.Selection.BaanId)) - return nil, err + s.log.Named("Update").Error(fmt.Sprintf("Invalid update scenario: group_id=%s, baan_id=%s", in.Selection.GroupId, in.Selection.BaanId)) + return nil, status.Error(codes.Internal, "Invalid update scenario") } if updateErr != nil { - s.log.Error("Failed to update selection", zap.String("group_id", in.Selection.GroupId), zap.Error(updateErr)) - return nil, updateErr + s.log.Named("Update").Error(fmt.Sprintf("Update: group_id=%s, baan_id=%s", in.Selection.GroupId, in.Selection.BaanId), zap.Error(updateErr)) + return nil, status.Error(codes.Internal, updateErr.Error()) } res := proto.UpdateSelectionResponse{ From 1c08f38705f8890bc5375e2478b1a91893176df0 Mon Sep 17 00:00:00 2001 From: flagrantii Date: Wed, 3 Jul 2024 22:01:34 +0700 Subject: [PATCH 14/16] Refactor: Update dependencies --- go.sum | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/go.sum b/go.sum index 4efa70c..6962b41 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,6 @@ github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -17,10 +15,6 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/isd-sgcu/rpkm67-go-proto v0.2.6 h1:ZzCqW09c7QyRwIzrQA2Kp4+0IYxB6A3iVtzp9Jn+QSI= -github.com/isd-sgcu/rpkm67-go-proto v0.2.6/go.mod h1:Z5SYz5kEe4W+MdqPouF0zEOiaqvg+s9I1S5d0q6e+Jw= -github.com/isd-sgcu/rpkm67-go-proto v0.2.7 h1:Sfq5r2+IN2Q4+MJCysWeEjcQ4MtcylBAdChOOVCLUN0= -github.com/isd-sgcu/rpkm67-go-proto v0.2.7/go.mod h1:Z5SYz5kEe4W+MdqPouF0zEOiaqvg+s9I1S5d0q6e+Jw= github.com/isd-sgcu/rpkm67-go-proto v0.2.8 h1:YDkxRcu204XD70E+xJSYt/4XmwXuM13nVNiEWflc73c= github.com/isd-sgcu/rpkm67-go-proto v0.2.8/go.mod h1:w+UCeQnJ3wBuJ7Tyf8LiBiPZVb1KlecjMNCB7kBeL7M= github.com/isd-sgcu/rpkm67-model v0.0.6 h1:pYlqOmeXGQIfHdOhyAta4kXkqnoLc4X3KWcAjPrAuds= @@ -71,8 +65,6 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= -golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -97,12 +89,8 @@ golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 h1:Zy9XzmMEflZ/MAaA7vNcoebnRAld7FsPW1EeBB7V0m8= google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= -google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= -google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= From a0389d50e5127fb70d32dfe8733e496234bb82e9 Mon Sep 17 00:00:00 2001 From: Idhibhat Pankam Date: Wed, 3 Jul 2024 22:46:57 +0700 Subject: [PATCH 15/16] fix: rename to groupUUID --- internal/selection/selection.service.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/selection/selection.service.go b/internal/selection/selection.service.go index 11d267f..bb3bbc9 100644 --- a/internal/selection/selection.service.go +++ b/internal/selection/selection.service.go @@ -33,7 +33,7 @@ func NewService(repo Repository, cache cache.Repository, log *zap.Logger) Servic } func (s *serviceImpl) Create(ctx context.Context, in *proto.CreateSelectionRequest) (*proto.CreateSelectionResponse, error) { - GroupUuid, err := uuid.Parse(in.GroupId) + groupUUID, err := uuid.Parse(in.GroupId) if err != nil { s.log.Named("Create").Error(fmt.Sprintf("Parse group id: %s", in.GroupId), zap.Error(err)) return nil, status.Error(codes.Internal, err.Error()) @@ -70,7 +70,7 @@ func (s *serviceImpl) Create(ctx context.Context, in *proto.CreateSelectionReque //Create selection selection := model.Selection{ - GroupID: &GroupUuid, + GroupID: &groupUUID, Baan: in.BaanId, Order: int(in.Order), } From 42f02f7dcaadab57958951eebe6b20237d96bff3 Mon Sep 17 00:00:00 2001 From: flagrantii Date: Wed, 3 Jul 2024 23:02:50 +0700 Subject: [PATCH 16/16] Feat : update selection repository methods to remove unnecessary parameter --- internal/selection/selection.repository.go | 20 ++++++++++---------- internal/selection/selection.service.go | 6 +++--- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/internal/selection/selection.repository.go b/internal/selection/selection.repository.go index e8c3b63..adc5631 100644 --- a/internal/selection/selection.repository.go +++ b/internal/selection/selection.repository.go @@ -10,9 +10,9 @@ type Repository interface { FindByGroupId(groupId string, selections *[]model.Selection) error Delete(groupId string, baanId string) error CountByBaanId() (map[string]int, error) - UpdateNewBaanExistOrder(updateSelection *model.Selection, selections *[]model.Selection) error - UpdateExistBaanExistOrder(updateSelection *model.Selection, selections *[]model.Selection) error - UpdateExistBaanNewOrder(updateSelection *model.Selection, selections *[]model.Selection) error + UpdateNewBaanExistOrder(updateSelection *model.Selection) error + UpdateExistBaanExistOrder(updateSelection *model.Selection) error + UpdateExistBaanNewOrder(updateSelection *model.Selection) error } type repositoryImpl struct { @@ -54,14 +54,14 @@ func (r *repositoryImpl) CountByBaanId() (map[string]int, error) { return count, nil } -func (r *repositoryImpl) UpdateNewBaanExistOrder(updateSelection *model.Selection, selections *[]model.Selection) error { +func (r *repositoryImpl) UpdateNewBaanExistOrder(updateSelection *model.Selection) error { return r.Db.Transaction(func(tx *gorm.DB) error { var existingSelection model.Selection if err := tx.Where(`group_id = ? AND "order" = ?`, updateSelection.GroupID, updateSelection.Order).First(&existingSelection).Error; err != nil { return err } - if err := tx.Where(`"order" = ?`, updateSelection.Order).Model(&existingSelection).Update("baan", updateSelection.Baan).Error; err != nil { + if err := tx.Where(`"order" = ? AND group_id = ?`, updateSelection.Order, updateSelection.GroupID).Model(&existingSelection).Update("baan", updateSelection.Baan).Error; err != nil { return err } @@ -69,7 +69,7 @@ func (r *repositoryImpl) UpdateNewBaanExistOrder(updateSelection *model.Selectio }) } -func (r *repositoryImpl) UpdateExistBaanExistOrder(updateSelection *model.Selection, selections *[]model.Selection) error { +func (r *repositoryImpl) UpdateExistBaanExistOrder(updateSelection *model.Selection) error { return r.Db.Transaction(func(tx *gorm.DB) error { var existingBaanSelection model.Selection if err := tx.Where("group_id = ? AND baan = ?", updateSelection.GroupID, updateSelection.Baan).First(&existingBaanSelection).Error; err != nil { @@ -85,10 +85,10 @@ func (r *repositoryImpl) UpdateExistBaanExistOrder(updateSelection *model.Select return nil } - if err := tx.Where(`"order" = ?`, existingBaanSelection.Order).Model(&existingBaanSelection).Update("baan", existingOrderSelection.Baan).Error; err != nil { + if err := tx.Where(`"order" = ? AND group_id = ?`, existingBaanSelection.Order, updateSelection.GroupID).Model(&existingBaanSelection).Update("baan", existingOrderSelection.Baan).Error; err != nil { return err } - if err := tx.Where(`"order" = ?`, existingOrderSelection.Order).Model(&existingOrderSelection).Update("baan", updateSelection.Baan).Error; err != nil { + if err := tx.Where(`"order" = ? AND group_id = ?`, existingOrderSelection.Order, updateSelection.GroupID).Model(&existingOrderSelection).Update("baan", updateSelection.Baan).Error; err != nil { return err } @@ -96,14 +96,14 @@ func (r *repositoryImpl) UpdateExistBaanExistOrder(updateSelection *model.Select }) } -func (r *repositoryImpl) UpdateExistBaanNewOrder(updateSelection *model.Selection, selections *[]model.Selection) error { +func (r *repositoryImpl) UpdateExistBaanNewOrder(updateSelection *model.Selection) error { return r.Db.Transaction(func(tx *gorm.DB) error { var existingSelection model.Selection if err := tx.Where("group_id = ? AND baan = ?", updateSelection.GroupID, updateSelection.Baan).First(&existingSelection).Error; err != nil { return err } - if err := tx.Where("baan = ?", updateSelection.Baan).Model(&existingSelection).Update("order", updateSelection.Order).Error; err != nil { + if err := tx.Where("baan = ? AND group_id = ?", updateSelection.Baan, updateSelection.GroupID).Model(&existingSelection).Update("order", updateSelection.Order).Error; err != nil { return err } diff --git a/internal/selection/selection.service.go b/internal/selection/selection.service.go index 11d267f..9b2099a 100644 --- a/internal/selection/selection.service.go +++ b/internal/selection/selection.service.go @@ -224,11 +224,11 @@ func (s *serviceImpl) Update(ctx context.Context, in *proto.UpdateSelectionReque var updateErr error if !baanExists && orderExists { - updateErr = s.repo.UpdateNewBaanExistOrder(&newSelection, oldSelections) + updateErr = s.repo.UpdateNewBaanExistOrder(&newSelection) } else if baanExists && orderExists { - updateErr = s.repo.UpdateExistBaanExistOrder(&newSelection, oldSelections) + updateErr = s.repo.UpdateExistBaanExistOrder(&newSelection) } else if baanExists && !orderExists { - updateErr = s.repo.UpdateExistBaanNewOrder(&newSelection, oldSelections) + updateErr = s.repo.UpdateExistBaanNewOrder(&newSelection) } else { s.log.Named("Update").Error(fmt.Sprintf("Invalid update scenario: group_id=%s, baan_id=%s", in.Selection.GroupId, in.Selection.BaanId)) return nil, status.Error(codes.Internal, "Invalid update scenario")