Skip to content

Commit

Permalink
findByUserIdNoCache
Browse files Browse the repository at this point in the history
  • Loading branch information
bookpanda committed Jul 8, 2024
1 parent 03700f8 commit 94af786
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 65 deletions.
16 changes: 0 additions & 16 deletions internal/group/group.repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ type Repository interface {
FindByToken(token string, group *model.Group) error
UpdateConfirm(id string, group *model.Group) error
CreateTX(tx *gorm.DB, group *model.Group) error
MoveUserToNewGroupTX(tx *gorm.DB, userId string, groupId *uuid.UUID) error
DeleteGroupTX(tx *gorm.DB, groupId *uuid.UUID) error
}

Expand Down Expand Up @@ -74,21 +73,6 @@ func (r *repositoryImpl) CreateTX(tx *gorm.DB, group *model.Group) error {
return tx.Create(&group).Error
}

func (r *repositoryImpl) MoveUserToNewGroupTX(tx *gorm.DB, userId string, groupId *uuid.UUID) error {
updateMap := map[string]interface{}{
"group_id": groupId,
}
result := tx.Model(&model.User{}).Where("id = ?", userId).Updates(updateMap)
if result.Error != nil {
return result.Error
}
if result.RowsAffected == 0 {
return errors.New("no user found with the given ID")
}

return nil
}

func (r *repositoryImpl) DeleteGroupTX(tx *gorm.DB, groupId *uuid.UUID) error {
result := tx.Delete(&model.Group{}, "id = ?", groupId)
if result.Error != nil {
Expand Down
107 changes: 59 additions & 48 deletions internal/group/group.service.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,24 @@ func (s *serviceImpl) findByUserId(userId string) (*model.Group, error) {
return cachedGroup, nil
}

group, err := s.findByUserIdNoCache(userId)
if err != nil {
s.log.Named("findByUserId").Error("findByUserIdNoCache group: ", zap.Error(err))
return nil, err
}

if err := s.cache.SetValue(cacheKey, group, s.conf.CacheTTL); err != nil {
s.log.Named("findByUserId").Error("SetValue: ", zap.Error(err))
return nil, status.Error(codes.Internal, "failed to cache group")
}

return group, nil
}

func (s *serviceImpl) findByUserIdNoCache(userId string) (*model.Group, error) {
user := &model.User{}
if err := s.userRepo.FindOne(userId, user); err != nil {
s.log.Named("findByUserId").Error("FindOne user: ", zap.Error(err))
s.log.Named("findByUserIdNoCache").Error("FindOne user: ", zap.Error(err))
return nil, status.Error(codes.Internal, "failed to find user")
}

Expand All @@ -72,40 +87,30 @@ func (s *serviceImpl) findByUserId(userId string) (*model.Group, error) {
}

if err := s.repo.CreateTX(tx, createGroup); err != nil {
s.log.Named("findByUserId").Error("CreateTX: ", zap.Error(err))
s.log.Named("findByUserIdNoCache").Error("CreateTX: ", zap.Error(err))
return fmt.Errorf("failed to create new group: %w", err)
}

if err := s.repo.MoveUserToNewGroupTX(tx, userId, &createGroup.ID); err != nil {
s.log.Named("findByUserId").Error("MoveUserToNewGroupTX: ", zap.Error(err))
return fmt.Errorf("failed to delete member from group: %w", err)
}

if err := s.userRepo.AssignGroupTX(tx, user.ID.String(), &createGroup.ID); err != nil {
s.log.Named("findByUserId").Error("AssignGroupTX: ", zap.Error(err))
s.log.Named("findByUserIdNoCache").Error("AssignGroupTX: ", zap.Error(err))
return fmt.Errorf("failed to assign user to group: %w", err)
}

return nil
})

if err != nil {
s.log.Named("findByUserId").Error("WithTransaction: ", zap.Error(err))
s.log.Named("findByUserIdNoCache").Error("WithTransaction: ", zap.Error(err))
return nil, status.Error(codes.Internal, fmt.Sprintf("transaction failed: %s", err.Error()))
}
}

group := &model.Group{}
if err := s.repo.FindOne(user.GroupID.String(), group); err != nil {
s.log.Named("findByUserId").Error("FindByUserId: ", zap.Error(err))
s.log.Named("findByUserIdNoCache").Error("FindOne: ", zap.Error(err))
return nil, status.Error(codes.Internal, "failed to find group")
}

if err := s.cache.SetValue(cacheKey, group, s.conf.CacheTTL); err != nil {
s.log.Named("findByUserId").Error("SetValue: ", zap.Error(err))
return nil, status.Error(codes.Internal, "failed to cache group")
}

return group, nil
}

Expand Down Expand Up @@ -174,7 +179,7 @@ func (s *serviceImpl) UpdateConfirm(_ context.Context, in *proto.UpdateConfirmGr
return nil, status.Error(codes.Internal, "failed to update group")
}

if err := s.updateGroupCacheByUserId(group); err != nil {
if err := s.updateGroupCache(group); err != nil {
s.log.Named("UpdateConfirm").Error("updateGroupCacheByUserId: ", zap.Error(err))
return nil, status.Error(codes.Internal, "failed to update group cache")
}
Expand Down Expand Up @@ -217,9 +222,9 @@ func (s *serviceImpl) DeleteMember(_ context.Context, in *proto.DeleteMemberGrou
return fmt.Errorf("failed to create new group: %w", err)
}

if err := s.repo.MoveUserToNewGroupTX(tx, in.UserId, &createGroup.ID); err != nil {
s.log.Named("DeleteMember").Error("MoveUserToNewGroupTX: ", zap.Error(err))
return fmt.Errorf("failed to delete member from group: %w", err)
if err := s.userRepo.AssignGroupTX(tx, in.UserId, &createGroup.ID); err != nil {
s.log.Named("DeleteMember").Error("AssignGroupTX: ", zap.Error(err))
return fmt.Errorf("failed to assign user to new group: %w", err)
}

return nil
Expand All @@ -230,22 +235,22 @@ func (s *serviceImpl) DeleteMember(_ context.Context, in *proto.DeleteMemberGrou
return nil, status.Error(codes.Internal, fmt.Sprintf("transaction failed: %s", err.Error()))
}

newGroup, err := s.findByUserId(in.UserId)
newGroup, err := s.findByUserIdNoCache(in.UserId)
if err != nil {
s.log.Named("DeleteMember").Error("findByUserId newGroup: ", zap.Error(err))
s.log.Named("DeleteMember").Error("findByUserIdNoCache newGroup: ", zap.Error(err))
return nil, err
}
updatedGroup, err := s.findByUserId(in.LeaderId)
updatedGroup, err := s.findByUserIdNoCache(in.LeaderId)
if err != nil {
s.log.Named("DeleteMember").Error("findByUserId updatedGroup: ", zap.Error(err))
s.log.Named("DeleteMember").Error("findByUserIdNoCache updatedGroup: ", zap.Error(err))
return nil, err
}

if err := s.updateGroupCacheByUserId(newGroup); err != nil {
if err := s.updateGroupCache(newGroup); err != nil {
s.log.Named("DeleteMember").Error("updateGroupCacheByUserId: newGroup", zap.Error(err))
return nil, status.Error(codes.Internal, "failed to update newGroup cache")
}
if err := s.updateGroupCacheByUserId(updatedGroup); err != nil {
if err := s.updateGroupCache(updatedGroup); err != nil {
s.log.Named("DeleteMember").Error("updateGroupCacheByUserId: updatedGroup", zap.Error(err))
return nil, status.Error(codes.Internal, "failed to update updatedGroup cache")
}
Expand All @@ -267,6 +272,11 @@ func (s *serviceImpl) Leave(_ context.Context, in *proto.LeaveGroupRequest) (*pr
return nil, status.Error(codes.PermissionDenied, "You are the group leader, so you cannot leave")
}

if len(group.Members) == 1 {
s.log.Named("Leave").Error("Group has only one member", zap.String("user_id", in.UserId))
return nil, status.Error(codes.PermissionDenied, "You are the only member in the group, so you cannot leave")
}

err = s.repo.WithTransaction(func(tx *gorm.DB) error {
createGroup := &model.Group{
LeaderID: group.LeaderID,
Expand All @@ -277,9 +287,9 @@ func (s *serviceImpl) Leave(_ context.Context, in *proto.LeaveGroupRequest) (*pr
return fmt.Errorf("failed to create new group: %w", err)
}

if err := s.repo.MoveUserToNewGroupTX(tx, in.UserId, &createGroup.ID); err != nil {
s.log.Named("Leave").Error("MoveUserToNewGroupTX: ", zap.Error(err))
return fmt.Errorf("failed to delete member from group: %w", err)
if err := s.userRepo.AssignGroupTX(tx, in.UserId, &createGroup.ID); err != nil {
s.log.Named("Leave").Error("AssignGroupTX: ", zap.Error(err))
return fmt.Errorf("failed to assign user to new group: %w", err)
}

return nil
Expand All @@ -290,22 +300,22 @@ func (s *serviceImpl) Leave(_ context.Context, in *proto.LeaveGroupRequest) (*pr
return nil, status.Error(codes.Internal, fmt.Sprintf("transaction failed: %s", err.Error()))
}

newGroup, err := s.findByUserId(in.UserId)
newGroup, err := s.findByUserIdNoCache(in.UserId)
if err != nil {
s.log.Named("Leave").Error("findByUserId group: ", zap.Error(err))
s.log.Named("Leave").Error("findByUserIdNoCache group: ", zap.Error(err))
return nil, err
}
updatedGroup, err := s.findByUserId(group.LeaderID.String())
updatedGroup, err := s.findByUserIdNoCache(group.LeaderID.String())
if err != nil {
s.log.Named("Leave").Error("findByUserId group: ", zap.Error(err))
s.log.Named("Leave").Error("findByUserIdNoCache group: ", zap.Error(err))
return nil, err
}

if err := s.updateGroupCacheByUserId(newGroup); err != nil {
if err := s.updateGroupCache(newGroup); err != nil {
s.log.Named("Leave").Error("updateGroupCacheByUserId: newGroup", zap.Error(err))
return nil, status.Error(codes.Internal, "failed to update newGroup cache")
}
if err := s.updateGroupCacheByUserId(updatedGroup); err != nil {
if err := s.updateGroupCache(updatedGroup); err != nil {
s.log.Named("Leave").Error("updateGroupCacheByUserId: updatedGroup", zap.Error(err))
return nil, status.Error(codes.Internal, "failed to update updatedGroup cache")
}
Expand All @@ -316,17 +326,6 @@ func (s *serviceImpl) Leave(_ context.Context, in *proto.LeaveGroupRequest) (*pr
}

func (s *serviceImpl) Join(_ context.Context, in *proto.JoinGroupRequest) (*proto.JoinGroupResponse, error) {
prevGroup, err := s.findByUserId(in.UserId)
if err != nil {
s.log.Named("Join").Error("findByUserId prevGroup: ", zap.Error(err))
return nil, err
}

if in.UserId == prevGroup.LeaderID.String() && len(prevGroup.Members) > 1 {
s.log.Named("Join").Error("User is the leader of a group with >1 members", zap.String("user_id", in.UserId))
return nil, status.Error(codes.PermissionDenied, "You are the group leader, so you must kick all other members before joining another group")
}

joiningGroup := &model.Group{}
if err := s.repo.FindByToken(in.Token, joiningGroup); err != nil {
s.log.Named("Join").Error("FindByToken joiningGroup TX: ", zap.Error(err))
Expand All @@ -345,6 +344,12 @@ func (s *serviceImpl) Join(_ context.Context, in *proto.JoinGroupRequest) (*prot
return nil, status.Error(codes.PermissionDenied, "group is full")
}

prevGroup, err := s.findByUserId(in.UserId)
if err != nil {
s.log.Named("Join").Error("findByUserId prevGroup: ", zap.Error(err))
return nil, err
}

err = s.repo.WithTransaction(func(tx *gorm.DB) error {

if err := s.userRepo.AssignGroupTX(tx, in.UserId, &joiningGroup.ID); err != nil {
Expand All @@ -368,7 +373,9 @@ func (s *serviceImpl) Join(_ context.Context, in *proto.JoinGroupRequest) (*prot
return nil, status.Error(codes.Internal, fmt.Sprintf("transaction failed: %s", err.Error()))
}

if err := s.updateGroupCacheByUserId(joiningGroup); err != nil {
joiningGroup.Members = append(joiningGroup.Members, prevGroup.Members[0])

if err := s.updateGroupCache(joiningGroup); err != nil {
s.log.Named("Join").Error("updateGroupCacheByUserId: joiningGroup", zap.Error(err))
return nil, status.Error(codes.Internal, "failed to update joiningGroup cache")
}
Expand All @@ -378,13 +385,17 @@ func (s *serviceImpl) Join(_ context.Context, in *proto.JoinGroupRequest) (*prot
return &proto.JoinGroupResponse{Group: groupRPC}, nil
}

func (s *serviceImpl) updateGroupCacheByUserId(group *model.Group) error {
func (s *serviceImpl) updateGroupCache(group *model.Group) error {
for _, member := range group.Members {
if err := s.cache.SetValue(groupByUserIdKey(member.ID.String()), group, s.conf.CacheTTL); err != nil {
return fmt.Errorf("failed to update group cache: %w", err)
return fmt.Errorf("failed to update group cache by user id: %w", err)
}
}

if err := s.cache.SetValue(groupByTokenKey(group.Token), group, s.conf.CacheTTL); err != nil {
return fmt.Errorf("failed to update group cache by token: %w", err)
}

return nil
}

Expand Down
2 changes: 1 addition & 1 deletion internal/user/user.repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,5 @@ func (r *repositoryImpl) FindOne(id string, user *model.User) error {
}

func (r *repositoryImpl) AssignGroupTX(tx *gorm.DB, id string, groupID *uuid.UUID) error {
return r.Db.Model(&model.User{}).Where("id = ?", id).Update("group_id", groupID).Error
return tx.Model(&model.User{}).Where("id = ?", id).Update("group_id", groupID).Error
}

0 comments on commit 94af786

Please sign in to comment.