github.com/vnforks/kid/v5@v5.22.1-0.20200408055009-b89d99c65676/store/sqlstore/supplier_reactions.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package sqlstore
     5  
     6  import (
     7  	"net/http"
     8  
     9  	"github.com/mattermost/gorp"
    10  	"github.com/vnforks/kid/v5/mlog"
    11  	"github.com/vnforks/kid/v5/model"
    12  	"github.com/vnforks/kid/v5/store"
    13  )
    14  
    15  type SqlReactionStore struct {
    16  	SqlStore
    17  }
    18  
    19  func newSqlReactionStore(sqlStore SqlStore) store.ReactionStore {
    20  	s := &SqlReactionStore{sqlStore}
    21  
    22  	for _, db := range sqlStore.GetAllConns() {
    23  		table := db.AddTableWithName(model.Reaction{}, "Reactions").SetKeys(false, "PostId", "UserId", "EmojiName")
    24  		table.ColMap("UserId").SetMaxSize(26)
    25  		table.ColMap("PostId").SetMaxSize(26)
    26  		table.ColMap("EmojiName").SetMaxSize(64)
    27  	}
    28  
    29  	return s
    30  }
    31  
    32  func (s *SqlReactionStore) Save(reaction *model.Reaction) (*model.Reaction, *model.AppError) {
    33  	reaction.PreSave()
    34  	if err := reaction.IsValid(); err != nil {
    35  		return nil, err
    36  	}
    37  
    38  	transaction, err := s.GetMaster().Begin()
    39  	if err != nil {
    40  		return nil, model.NewAppError("SqlReactionStore.Save", "store.sql_reaction.save.begin.app_error", nil, err.Error(), http.StatusInternalServerError)
    41  	}
    42  	defer finalizeTransaction(transaction)
    43  	appErr := saveReactionAndUpdatePost(transaction, reaction)
    44  	if appErr != nil {
    45  		// We don't consider duplicated save calls as an error
    46  		if !IsUniqueConstraintError(appErr, []string{"reactions_pkey", "PRIMARY"}) {
    47  			return nil, model.NewAppError("SqlPreferenceStore.Save", "store.sql_reaction.save.save.app_error", nil, appErr.Error(), http.StatusBadRequest)
    48  		}
    49  	} else {
    50  		if err := transaction.Commit(); err != nil {
    51  			return nil, model.NewAppError("SqlPreferenceStore.Save", "store.sql_reaction.save.commit.app_error", nil, err.Error(), http.StatusInternalServerError)
    52  		}
    53  	}
    54  
    55  	return reaction, nil
    56  }
    57  
    58  func (s *SqlReactionStore) Delete(reaction *model.Reaction) (*model.Reaction, *model.AppError) {
    59  	transaction, err := s.GetMaster().Begin()
    60  	if err != nil {
    61  		return nil, model.NewAppError("SqlReactionStore.Delete", "store.sql_reaction.delete.begin.app_error", nil, err.Error(), http.StatusInternalServerError)
    62  	}
    63  	defer finalizeTransaction(transaction)
    64  
    65  	appErr := deleteReactionAndUpdatePost(transaction, reaction)
    66  	if appErr != nil {
    67  		return nil, model.NewAppError("SqlPreferenceStore.Delete", "store.sql_reaction.delete.app_error", nil, appErr.Error(), http.StatusInternalServerError)
    68  	}
    69  
    70  	if err := transaction.Commit(); err != nil {
    71  		return nil, model.NewAppError("SqlPreferenceStore.Delete", "store.sql_reaction.delete.commit.app_error", nil, err.Error(), http.StatusInternalServerError)
    72  	}
    73  
    74  	return reaction, nil
    75  }
    76  
    77  func (s *SqlReactionStore) GetForPost(postId string, allowFromCache bool) ([]*model.Reaction, *model.AppError) {
    78  	var reactions []*model.Reaction
    79  
    80  	if _, err := s.GetReplica().Select(&reactions,
    81  		`SELECT
    82  				*
    83  			FROM
    84  				Reactions
    85  			WHERE
    86  				PostId = :PostId
    87  			ORDER BY
    88  				CreateAt`, map[string]interface{}{"PostId": postId}); err != nil {
    89  		return nil, model.NewAppError("SqlReactionStore.GetForPost", "store.sql_reaction.get_for_post.app_error", nil, "", http.StatusInternalServerError)
    90  	}
    91  
    92  	return reactions, nil
    93  }
    94  
    95  func (s *SqlReactionStore) BulkGetForPosts(postIds []string) ([]*model.Reaction, *model.AppError) {
    96  	keys, params := MapStringsToQueryParams(postIds, "postId")
    97  	var reactions []*model.Reaction
    98  
    99  	if _, err := s.GetReplica().Select(&reactions, `SELECT
   100  				*
   101  			FROM
   102  				Reactions
   103  			WHERE
   104  				PostId IN `+keys+`
   105  			ORDER BY
   106  				CreateAt`, params); err != nil {
   107  		return nil, model.NewAppError("SqlReactionStore.GetForPost", "store.sql_reaction.bulk_get_for_post_ids.app_error", nil, "", http.StatusInternalServerError)
   108  	}
   109  	return reactions, nil
   110  }
   111  
   112  func (s *SqlReactionStore) DeleteAllWithEmojiName(emojiName string) *model.AppError {
   113  	var reactions []*model.Reaction
   114  
   115  	if _, err := s.GetReplica().Select(&reactions,
   116  		`SELECT
   117  				*
   118  			FROM
   119  				Reactions
   120  			WHERE
   121  				EmojiName = :EmojiName`, map[string]interface{}{"EmojiName": emojiName}); err != nil {
   122  		return model.NewAppError("SqlReactionStore.DeleteAllWithEmojiName",
   123  			"store.sql_reaction.delete_all_with_emoji_name.get_reactions.app_error", nil,
   124  			"emoji_name="+emojiName+", error="+err.Error(), http.StatusInternalServerError)
   125  	}
   126  
   127  	if _, err := s.GetMaster().Exec(
   128  		`DELETE FROM
   129  				Reactions
   130  			WHERE
   131  				EmojiName = :EmojiName`, map[string]interface{}{"EmojiName": emojiName}); err != nil {
   132  		return model.NewAppError("SqlReactionStore.DeleteAllWithEmojiName",
   133  			"store.sql_reaction.delete_all_with_emoji_name.delete_reactions.app_error", nil,
   134  			"emoji_name="+emojiName+", error="+err.Error(), http.StatusInternalServerError)
   135  	}
   136  
   137  	for _, reaction := range reactions {
   138  		if _, err := s.GetMaster().Exec(UPDATE_POST_HAS_REACTIONS_ON_DELETE_QUERY,
   139  			map[string]interface{}{"PostId": reaction.PostId, "UpdateAt": model.GetMillis()}); err != nil {
   140  			mlog.Warn("Unable to update Post.HasReactions while removing reactions", mlog.String("post_id", reaction.PostId), mlog.Err(err))
   141  		}
   142  	}
   143  
   144  	return nil
   145  }
   146  
   147  func (s *SqlReactionStore) PermanentDeleteBatch(endTime int64, limit int64) (int64, *model.AppError) {
   148  	var query string
   149  	if s.DriverName() == "postgres" {
   150  		query = "DELETE from Reactions WHERE CreateAt = any (array (SELECT CreateAt FROM Reactions WHERE CreateAt < :EndTime LIMIT :Limit))"
   151  	} else {
   152  		query = "DELETE from Reactions WHERE CreateAt < :EndTime LIMIT :Limit"
   153  	}
   154  
   155  	sqlResult, err := s.GetMaster().Exec(query, map[string]interface{}{"EndTime": endTime, "Limit": limit})
   156  	if err != nil {
   157  		return 0, model.NewAppError("SqlReactionStore.PermanentDeleteBatch", "store.sql_reaction.permanent_delete_batch.app_error", nil, ""+err.Error(), http.StatusInternalServerError)
   158  	}
   159  
   160  	rowsAffected, err := sqlResult.RowsAffected()
   161  	if err != nil {
   162  		return 0, model.NewAppError("SqlReactionStore.PermanentDeleteBatch", "store.sql_reaction.permanent_delete_batch.app_error", nil, ""+err.Error(), http.StatusInternalServerError)
   163  	}
   164  	return rowsAffected, nil
   165  }
   166  
   167  func saveReactionAndUpdatePost(transaction *gorp.Transaction, reaction *model.Reaction) error {
   168  	if err := transaction.Insert(reaction); err != nil {
   169  		return err
   170  	}
   171  
   172  	return updatePostForReactionsOnInsert(transaction, reaction.PostId)
   173  }
   174  
   175  func deleteReactionAndUpdatePost(transaction *gorp.Transaction, reaction *model.Reaction) error {
   176  	if _, err := transaction.Exec(
   177  		`DELETE FROM
   178  			Reactions
   179  		WHERE
   180  			PostId = :PostId AND
   181  			UserId = :UserId AND
   182  			EmojiName = :EmojiName`,
   183  		map[string]interface{}{"PostId": reaction.PostId, "UserId": reaction.UserId, "EmojiName": reaction.EmojiName}); err != nil {
   184  		return err
   185  	}
   186  
   187  	return updatePostForReactionsOnDelete(transaction, reaction.PostId)
   188  }
   189  
   190  const (
   191  	UPDATE_POST_HAS_REACTIONS_ON_DELETE_QUERY = `UPDATE
   192  			Posts
   193  		SET
   194  			UpdateAt = :UpdateAt,
   195  			HasReactions = (SELECT count(0) > 0 FROM Reactions WHERE PostId = :PostId)
   196  		WHERE
   197  			Id = :PostId`
   198  )
   199  
   200  func updatePostForReactionsOnDelete(transaction *gorp.Transaction, postId string) error {
   201  	updateAt := model.GetMillis()
   202  	_, err := transaction.Exec(UPDATE_POST_HAS_REACTIONS_ON_DELETE_QUERY, map[string]interface{}{"PostId": postId, "UpdateAt": updateAt})
   203  	return err
   204  }
   205  
   206  func updatePostForReactionsOnInsert(transaction *gorp.Transaction, postId string) error {
   207  	_, err := transaction.Exec(
   208  		`UPDATE
   209  			Posts
   210  		SET
   211  			HasReactions = True,
   212  			UpdateAt = :UpdateAt
   213  		WHERE
   214  			Id = :PostId`,
   215  		map[string]interface{}{"PostId": postId, "UpdateAt": model.GetMillis()})
   216  
   217  	return err
   218  }