This is an automated email from the ASF dual-hosted git repository.

linkinstar pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/incubator-answer.git

commit 7d2fd40097efae5b98049a2ad3b9f15ded2c42fd
Author: hgaol <[email protected]>
AuthorDate: Wed May 8 00:24:51 2024 +0800

    add transaction when add or update reactions and fix other issues
---
 internal/controller/meta_controller.go |  6 +--
 internal/repo/meta/meta_repo.go        | 98 ++++++++++++++++++++++++++++++++++
 internal/schema/meta_schema.go         |  2 +-
 internal/service/meta/meta_service.go  | 80 +--------------------------
 4 files changed, 104 insertions(+), 82 deletions(-)

diff --git a/internal/controller/meta_controller.go 
b/internal/controller/meta_controller.go
index fe598b90..2a9ab866 100644
--- a/internal/controller/meta_controller.go
+++ b/internal/controller/meta_controller.go
@@ -67,9 +67,9 @@ func (mc *MetaController) AddOrUpdateReaction(ctx 
*gin.Context) {
 // @Accept json
 // @Produce json
 // @Security ApiKeyAuth
-// @Param data body schema.UpdateReactionReq true "reaction"
-// @Success 200 {object} handler.RespBody
-// @Router /answer/api/v1/meta/reaction [put]
+// @Param object_id query string true "object_id"
+// @Success 200 {object} handler.RespBody{data=schema.ReactionResp}
+// @Router /answer/api/v1/meta/reaction [get]
 func (mc *MetaController) GetReaction(ctx *gin.Context) {
        req := &schema.GetReactionReq{}
        if handler.BindAndCheck(ctx, req) {
diff --git a/internal/repo/meta/meta_repo.go b/internal/repo/meta/meta_repo.go
index bbf3e422..160201cf 100644
--- a/internal/repo/meta/meta_repo.go
+++ b/internal/repo/meta/meta_repo.go
@@ -21,13 +21,16 @@ package meta
 
 import (
        "context"
+       "encoding/json"
 
        "github.com/apache/incubator-answer/internal/base/data"
        "github.com/apache/incubator-answer/internal/base/reason"
        "github.com/apache/incubator-answer/internal/entity"
+       "github.com/apache/incubator-answer/internal/schema"
        "github.com/apache/incubator-answer/internal/service/meta"
        "github.com/segmentfault/pacman/errors"
        "xorm.io/builder"
+       "xorm.io/xorm"
 )
 
 // metaRepo meta repository
@@ -69,6 +72,101 @@ func (mr *metaRepo) UpdateMeta(ctx context.Context, meta 
*entity.Meta) (err erro
        return
 }
 
+// AddOrUpdateMetaByObjectIdAndKey if exist record with same objectID and key, 
update it. Or create a new one
+func (mr *metaRepo) AddOrUpdateMetaByObjectIdAndKey(ctx context.Context, req 
*schema.UpdateReactionReq) (schema.ReactSummaryMeta, error) {
+       result, err := mr.data.DB.Transaction(func(session *xorm.Session) 
(interface{}, error) {
+               session = session.Context(ctx)
+
+               // 1. acquire meta entity with target object id and key
+               metaEntity := &entity.Meta{}
+               exist, err := 
mr.data.DB.Context(ctx).Where(builder.Eq{"object_id": 
req.ObjectID}.And(builder.Eq{"`key`": 
entity.ObjectReactSummaryKey})).ForUpdate().Get(metaEntity)
+               if err != nil {
+                       return nil, 
errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
+               }
+
+               var reaction schema.ReactSummaryMeta
+               // if not exist, create new one
+               if !exist {
+                       reaction = schema.ReactSummaryMeta{}
+                       return nil, 
errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
+               } else {
+                       err = json.Unmarshal([]byte(metaEntity.Value), 
&reaction)
+                       if err != nil {
+                               return nil, err
+                       }
+               }
+
+               // update reaction
+               mr.updateReaction(req, reaction)
+
+               // write back to meta repo
+               reactSumBytes, err := json.Marshal(reaction)
+               if err != nil {
+                       return nil, err
+               }
+
+               metaObj := &entity.Meta{
+                       ObjectID: req.ObjectID,
+                       Key:      entity.ObjectReactSummaryKey,
+                       Value:    string(reactSumBytes),
+               }
+               if exist {
+                       _, err = session.Update(metaObj)
+               } else {
+                       _, err = session.Insert(metaObj)
+               }
+
+               return reaction, err
+       })
+
+       if err != nil {
+               return nil, 
errors.InternalServer(reason.DatabaseError).WithError(err)
+       }
+
+       if ret, ok := result.(schema.ReactSummaryMeta); ok {
+               return ret, nil
+       } else {
+               return nil, 
errors.InternalServer(reason.UnknownError).WithMsg("Unable to cast to 
schema.ReactSummaryMeta.")
+       }
+}
+
+// updateReaction update reaction
+func (mr *metaRepo) updateReaction(req *schema.UpdateReactionReq, reaction 
schema.ReactSummaryMeta) {
+       emojiUserIds, ok := reaction[req.Emoji]
+
+       if !ok {
+               emojiUserIds = make([]string, 0)
+       }
+
+       found := false
+       for _, item := range emojiUserIds {
+               if item == req.UserID {
+                       found = true
+                       break
+               }
+       }
+
+       removeItem := func(arr []string, target string) []string {
+               result := make([]string, 0, len(arr))
+
+               for _, item := range arr {
+                       if item != target {
+                               result = append(result, item)
+                       }
+               }
+
+               return result
+       }
+
+       if req.Reaction == "activate" && !found {
+               emojiUserIds = append(emojiUserIds, req.UserID)
+       } else if req.Reaction == "deactivate" && found {
+               emojiUserIds = removeItem(emojiUserIds, req.UserID)
+       }
+
+       reaction[req.Emoji] = emojiUserIds
+}
+
 // GetMetaByObjectIdAndKey get meta one
 func (mr *metaRepo) GetMetaByObjectIdAndKey(ctx context.Context, objectID, key 
string) (
        meta *entity.Meta, exist bool, err error) {
diff --git a/internal/schema/meta_schema.go b/internal/schema/meta_schema.go
index cf213813..bf458bfc 100644
--- a/internal/schema/meta_schema.go
+++ b/internal/schema/meta_schema.go
@@ -22,7 +22,7 @@ package schema
 type UpdateReactionReq struct {
        ObjectID string `validate:"required" form:"object_id" json:"object_id"` 
// object id
        Emoji    string `validate:"required" form:"emoji" json:"emoji"`         
// emoji
-       Type     string `validate:"required" form:"type" json:"type"`           
// type
+       Reaction string `validate:"required" form:"reaction" json:"reaction"`   
// reaction
        UserID   string `json:"-"`
 }
 
diff --git a/internal/service/meta/meta_service.go 
b/internal/service/meta/meta_service.go
index cd7ca4f7..b06fa736 100644
--- a/internal/service/meta/meta_service.go
+++ b/internal/service/meta/meta_service.go
@@ -36,6 +36,7 @@ type MetaRepo interface {
        AddMeta(ctx context.Context, meta *entity.Meta) (err error)
        RemoveMeta(ctx context.Context, id int) (err error)
        UpdateMeta(ctx context.Context, meta *entity.Meta) (err error)
+       AddOrUpdateMetaByObjectIdAndKey(ctx context.Context, req 
*schema.UpdateReactionReq) (schema.ReactSummaryMeta, error)
        GetMetaByObjectIdAndKey(ctx context.Context, objectId, key string) 
(meta *entity.Meta, exist bool, err error)
        GetMetaList(ctx context.Context, meta *entity.Meta) (metas 
[]*entity.Meta, err error)
 }
@@ -123,41 +124,7 @@ func (ms *MetaService) GetReactionByObjectId(ctx 
context.Context, objectID strin
 
 // AddOrUpdateReaction add or update reaction
 func (ms *MetaService) AddOrUpdateReaction(ctx context.Context, req 
*schema.UpdateReactionReq) (resp schema.ReactionResp, err error) {
-       // get reaction for this object
-       reactionMeta, err := ms.GetMetaByObjectIdAndKey(ctx, req.ObjectID, 
entity.ObjectReactSummaryKey)
-
-       var reaction schema.ReactSummaryMeta
-       if err != nil {
-               var pacmanErr *myErrors.Error
-               if errors.As(err, &pacmanErr) && pacmanErr.Reason == 
reason.MetaObjectNotFound {
-                       // create new reaction summary
-                       reaction = schema.ReactSummaryMeta{}
-               } else {
-                       return nil, err
-               }
-       } else {
-               // json unmarshal reactionMeta.Value to reaction
-               err = json.Unmarshal([]byte(reactionMeta.Value), &reaction)
-               if err != nil {
-                       return nil, err
-               }
-       }
-
-       // update reaction
-       ms.updateReaction(req, reaction)
-
-       // write back to meta repo
-       reactSumBytes, err := json.Marshal(reaction)
-       if err != nil {
-               return nil, err
-       }
-
-       if reactionMeta == nil {
-               err = ms.AddMeta(ctx, req.ObjectID, 
entity.ObjectReactSummaryKey, string(reactSumBytes))
-       } else {
-               err = ms.UpdateMeta(ctx, reactionMeta.ID, 
entity.ObjectReactSummaryKey, string(reactSumBytes))
-       }
-
+       reaction, err := ms.metaRepo.AddOrUpdateMetaByObjectIdAndKey(ctx, req)
        if err != nil {
                return nil, err
        }
@@ -170,49 +137,6 @@ func (ms *MetaService) AddOrUpdateReaction(ctx 
context.Context, req *schema.Upda
        return resp, nil
 }
 
-// updateReaction update reaction
-func (ms *MetaService) updateReaction(req *schema.UpdateReactionReq, reaction 
schema.ReactSummaryMeta) {
-       emojiUserIds, ok := reaction[req.Emoji]
-
-       if !ok {
-               emojiUserIds = make([]string, 0)
-       }
-
-       found := false
-       for _, item := range emojiUserIds {
-               if item == req.UserID {
-                       found = true
-                       break
-               }
-       }
-
-       removeItem := func(arr []string, target string) []string {
-               result := make([]string, 0, len(arr))
-
-               for _, item := range arr {
-                       if item != target {
-                               result = append(result, item)
-                       }
-               }
-
-               return result
-       }
-
-       if req.Type == "activate" && !found {
-               emojiUserIds = append(emojiUserIds, req.UserID)
-       } else if req.Type == "deactivate" && found {
-               emojiUserIds = removeItem(emojiUserIds, req.UserID)
-       } else if req.Type == "toggle" {
-               if found {
-                       emojiUserIds = removeItem(emojiUserIds, req.UserID)
-               } else {
-                       emojiUserIds = append(emojiUserIds, req.UserID)
-               }
-       }
-
-       reaction[req.Emoji] = emojiUserIds
-}
-
 func (ms *MetaService) convertToReactionResp(ctx context.Context, reaction 
schema.ReactSummaryMeta) (schema.ReactionResp, error) {
        resp := schema.ReactionResp{}
        // traverse map and convert to username

Reply via email to