Migrate ChannelStore.UpdateLastViewedAt to squirrel (#19439)

Fixes https://github.com/mattermost/mattermost-server/issues/19332

```release-note
NONE
```

Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Этот коммит содержится в:
Agniva De Sarker
2022-02-09 19:21:47 +05:30
коммит произвёл GitHub
родитель de0d95f72b
Коммит d5b24e383d

Просмотреть файл

@@ -2431,7 +2431,6 @@ func (s SqlChannelStore) PermanentDeleteMembersByUser(userId string) error {
return nil return nil
} }
// TODO: convert to squirrel (https://github.com/mattermost/mattermost-server/issues/19332)
func (s SqlChannelStore) UpdateLastViewedAt(channelIds []string, userId string, updateThreads bool) (map[string]int64, error) { func (s SqlChannelStore) UpdateLastViewedAt(channelIds []string, userId string, updateThreads bool) (map[string]int64, error) {
var threadsToUpdate []string var threadsToUpdate []string
now := model.GetMillis() now := model.GetMillis()
@@ -2443,38 +2442,50 @@ func (s SqlChannelStore) UpdateLastViewedAt(channelIds []string, userId string,
} }
} }
keys, props := MapStringsToQueryParams(channelIds, "Channel") lastPostAtTimes := []struct {
props["UserId"] = userId
var lastPostAtTimes []struct {
Id string Id string
LastPostAt int64 LastPostAt int64
TotalMsgCount int64 TotalMsgCount int64
TotalMsgCountRoot int64 TotalMsgCountRoot int64
} }{}
// We use the question placeholder format for both databases, because
// we replace that with the dollar format later on.
// It's needed to support the prefix CTE query. See: https://github.com/Masterminds/squirrel/issues/285.
query := sq.StatementBuilder.PlaceholderFormat(sq.Question).
Select("Id, LastPostAt, TotalMsgCount, TotalMsgCountRoot").
From("Channels").
Where(sq.Eq{"Id": channelIds})
query := `SELECT Id, LastPostAt, TotalMsgCount, TotalMsgCountRoot FROM Channels WHERE Id IN ` + keys
// TODO: use a CTE for mysql too when version 8 becomes the minimum supported version. // TODO: use a CTE for mysql too when version 8 becomes the minimum supported version.
if s.DriverName() == model.DatabaseDriverPostgres { if s.DriverName() == model.DatabaseDriverPostgres {
query = `WITH c AS ( ` + query + `), with := query.Prefix("WITH c AS (").Suffix(") ,")
updated AS ( update := sq.StatementBuilder.PlaceholderFormat(sq.Question).
UPDATE Update("ChannelMembers cm").
ChannelMembers cm Set("MentionCount", 0).
SET Set("MentionCountRoot", 0).
MentionCount = 0, Set("MsgCount", sq.Expr("greatest(cm.MsgCount, c.TotalMsgCount)")).
MentionCountRoot = 0, Set("MsgCountRoot", sq.Expr("greatest(cm.MsgCountRoot, c.TotalMsgCountRoot)")).
MsgCount = greatest(cm.MsgCount, c.TotalMsgCount), Set("LastViewedAt", sq.Expr("greatest(cm.LastViewedAt, c.LastPostAt)")).
MsgCountRoot = greatest(cm.MsgCountRoot, c.TotalMsgCountRoot), Set("LastUpdateAt", sq.Expr("greatest(cm.LastViewedAt, c.LastPostAt)")).
LastViewedAt = greatest(cm.LastViewedAt, c.LastPostAt), SuffixExpr(sq.Expr("FROM c WHERE cm.UserId = ? AND c.Id = cm.ChannelId", userId))
LastUpdateAt = greatest(cm.LastViewedAt, c.LastPostAt) updateWrap := update.Prefix("updated AS (").Suffix(")")
FROM c query = with.SuffixExpr(updateWrap).Suffix("SELECT Id, LastPostAt FROM c")
WHERE cm.UserId = :UserId
AND c.Id=cm.ChannelId
)
SELECT Id, LastPostAt FROM c`
} }
_, err := s.GetMaster().Select(&lastPostAtTimes, query, props) sql, args, err := query.ToSql()
if err != nil {
return nil, errors.Wrap(err, "UpdateLastViewedAt_CTE_Tosql")
}
if s.DriverName() == model.DatabaseDriverPostgres {
sql, err = sq.Dollar.ReplacePlaceholders(sql)
if err != nil {
return nil, errors.Wrap(err, "UpdateLastViewedAt_ReplacePlaceholders")
}
}
err = s.GetMasterX().Select(&lastPostAtTimes, sql, args...)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "failed to find ChannelMembers data with userId=%s and channelId in %v", userId, channelIds) return nil, errors.Wrapf(err, "failed to find ChannelMembers data with userId=%s and channelId in %v", userId, channelIds)
} }
@@ -2494,39 +2505,42 @@ func (s SqlChannelStore) UpdateLastViewedAt(channelIds []string, userId string,
return times, nil return times, nil
} }
msgCountQuery := "" var msgCountQuery, msgCountQueryRoot, lastViewedQuery = sq.Case("ChannelId"), sq.Case("ChannelId"), sq.Case("ChannelId")
msgCountQueryRoot := ""
lastViewedQuery := ""
for index, t := range lastPostAtTimes { for _, t := range lastPostAtTimes {
times[t.Id] = t.LastPostAt times[t.Id] = t.LastPostAt
props["msgCount"+strconv.Itoa(index)] = t.TotalMsgCount msgCountQuery = msgCountQuery.When(
msgCountQuery += fmt.Sprintf("WHEN :channelId%d THEN GREATEST(MsgCount, :msgCount%d) ", index, index) sq.Expr("?", t.Id),
sq.Expr("GREATEST(MsgCount, ?)", t.TotalMsgCount))
props["msgCountRoot"+strconv.Itoa(index)] = t.TotalMsgCountRoot msgCountQueryRoot = msgCountQueryRoot.When(
msgCountQueryRoot += fmt.Sprintf("WHEN :channelId%d THEN GREATEST(MsgCountRoot, :msgCountRoot%d) ", index, index) sq.Expr("?", t.Id),
sq.Expr("GREATEST(MsgCountRoot, ?)", t.TotalMsgCountRoot))
props["lastViewed"+strconv.Itoa(index)] = t.LastPostAt lastViewedQuery = lastViewedQuery.When(
lastViewedQuery += fmt.Sprintf("WHEN :channelId%d THEN GREATEST(LastViewedAt, :lastViewed%d) ", index, index) sq.Expr("?", t.Id),
sq.Expr("GREATEST(LastViewedAt, ?)", t.LastPostAt))
props["channelId"+strconv.Itoa(index)] = t.Id
} }
updateQuery := `UPDATE updateQuery := s.getQueryBuilder().Update("ChannelMembers").
ChannelMembers Set("MentionCount", 0).
SET Set("MentionCountRoot", 0).
MentionCount = 0, Set("MsgCount", msgCountQuery).
MentionCountRoot = 0, Set("MsgCountRoot", msgCountQueryRoot).
MsgCount = CASE ChannelId ` + msgCountQuery + ` END, Set("LastViewedAt", lastViewedQuery).
MsgCountRoot = CASE ChannelId ` + msgCountQueryRoot + ` END, Set("LastUpdateAt", sq.Expr("LastViewedAt")).
LastViewedAt = CASE ChannelId ` + lastViewedQuery + ` END, Where(sq.Eq{
LastUpdateAt = LastViewedAt "UserId": userId,
WHERE "ChannelId": channelIds,
UserId = :UserId })
AND ChannelId IN ` + keys
if _, err := s.GetMaster().Exec(updateQuery, props); err != nil { sql, args, err = updateQuery.ToSql()
if err != nil {
return nil, errors.Wrap(err, "UpdateLastViewedAt_Update_Tosql")
}
if _, err := s.GetMasterX().Exec(sql, args...); err != nil {
return nil, errors.Wrapf(err, "failed to update ChannelMembers with userId=%s and channelId in %v", userId, channelIds) return nil, errors.Wrapf(err, "failed to update ChannelMembers with userId=%s and channelId in %v", userId, channelIds)
} }