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
}
// 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) {
var threadsToUpdate []string
now := model.GetMillis()
@@ -2443,38 +2442,50 @@ func (s SqlChannelStore) UpdateLastViewedAt(channelIds []string, userId string,
}
}
keys, props := MapStringsToQueryParams(channelIds, "Channel")
props["UserId"] = userId
var lastPostAtTimes []struct {
lastPostAtTimes := []struct {
Id string
LastPostAt int64
TotalMsgCount 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.
if s.DriverName() == model.DatabaseDriverPostgres {
query = `WITH c AS ( ` + query + `),
updated AS (
UPDATE
ChannelMembers cm
SET
MentionCount = 0,
MentionCountRoot = 0,
MsgCount = greatest(cm.MsgCount, c.TotalMsgCount),
MsgCountRoot = greatest(cm.MsgCountRoot, c.TotalMsgCountRoot),
LastViewedAt = greatest(cm.LastViewedAt, c.LastPostAt),
LastUpdateAt = greatest(cm.LastViewedAt, c.LastPostAt)
FROM c
WHERE cm.UserId = :UserId
AND c.Id=cm.ChannelId
)
SELECT Id, LastPostAt FROM c`
with := query.Prefix("WITH c AS (").Suffix(") ,")
update := sq.StatementBuilder.PlaceholderFormat(sq.Question).
Update("ChannelMembers cm").
Set("MentionCount", 0).
Set("MentionCountRoot", 0).
Set("MsgCount", sq.Expr("greatest(cm.MsgCount, c.TotalMsgCount)")).
Set("MsgCountRoot", sq.Expr("greatest(cm.MsgCountRoot, c.TotalMsgCountRoot)")).
Set("LastViewedAt", sq.Expr("greatest(cm.LastViewedAt, c.LastPostAt)")).
Set("LastUpdateAt", sq.Expr("greatest(cm.LastViewedAt, c.LastPostAt)")).
SuffixExpr(sq.Expr("FROM c WHERE cm.UserId = ? AND c.Id = cm.ChannelId", userId))
updateWrap := update.Prefix("updated AS (").Suffix(")")
query = with.SuffixExpr(updateWrap).Suffix("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 {
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
}
msgCountQuery := ""
msgCountQueryRoot := ""
lastViewedQuery := ""
var msgCountQuery, msgCountQueryRoot, lastViewedQuery = sq.Case("ChannelId"), sq.Case("ChannelId"), sq.Case("ChannelId")
for index, t := range lastPostAtTimes {
for _, t := range lastPostAtTimes {
times[t.Id] = t.LastPostAt
props["msgCount"+strconv.Itoa(index)] = t.TotalMsgCount
msgCountQuery += fmt.Sprintf("WHEN :channelId%d THEN GREATEST(MsgCount, :msgCount%d) ", index, index)
msgCountQuery = msgCountQuery.When(
sq.Expr("?", t.Id),
sq.Expr("GREATEST(MsgCount, ?)", t.TotalMsgCount))
props["msgCountRoot"+strconv.Itoa(index)] = t.TotalMsgCountRoot
msgCountQueryRoot += fmt.Sprintf("WHEN :channelId%d THEN GREATEST(MsgCountRoot, :msgCountRoot%d) ", index, index)
msgCountQueryRoot = msgCountQueryRoot.When(
sq.Expr("?", t.Id),
sq.Expr("GREATEST(MsgCountRoot, ?)", t.TotalMsgCountRoot))
props["lastViewed"+strconv.Itoa(index)] = t.LastPostAt
lastViewedQuery += fmt.Sprintf("WHEN :channelId%d THEN GREATEST(LastViewedAt, :lastViewed%d) ", index, index)
props["channelId"+strconv.Itoa(index)] = t.Id
lastViewedQuery = lastViewedQuery.When(
sq.Expr("?", t.Id),
sq.Expr("GREATEST(LastViewedAt, ?)", t.LastPostAt))
}
updateQuery := `UPDATE
ChannelMembers
SET
MentionCount = 0,
MentionCountRoot = 0,
MsgCount = CASE ChannelId ` + msgCountQuery + ` END,
MsgCountRoot = CASE ChannelId ` + msgCountQueryRoot + ` END,
LastViewedAt = CASE ChannelId ` + lastViewedQuery + ` END,
LastUpdateAt = LastViewedAt
WHERE
UserId = :UserId
AND ChannelId IN ` + keys
updateQuery := s.getQueryBuilder().Update("ChannelMembers").
Set("MentionCount", 0).
Set("MentionCountRoot", 0).
Set("MsgCount", msgCountQuery).
Set("MsgCountRoot", msgCountQueryRoot).
Set("LastViewedAt", lastViewedQuery).
Set("LastUpdateAt", sq.Expr("LastViewedAt")).
Where(sq.Eq{
"UserId": userId,
"ChannelId": channelIds,
})
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)
}