MM-33746 Add TotalMsgCountRoot and MsgCountRoot columns (#17150)
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
ee3f986da0
Коммит
ab5925c4de
@@ -50,6 +50,7 @@ type channelMember struct {
|
||||
SchemeUser sql.NullBool
|
||||
SchemeAdmin sql.NullBool
|
||||
SchemeGuest sql.NullBool
|
||||
MsgCountRoot int64
|
||||
}
|
||||
|
||||
func NewChannelMemberFromModel(cm *model.ChannelMember) *channelMember {
|
||||
@@ -59,6 +60,7 @@ func NewChannelMemberFromModel(cm *model.ChannelMember) *channelMember {
|
||||
Roles: cm.ExplicitRoles,
|
||||
LastViewedAt: cm.LastViewedAt,
|
||||
MsgCount: cm.MsgCount,
|
||||
MsgCountRoot: cm.MsgCountRoot,
|
||||
MentionCount: cm.MentionCount,
|
||||
NotifyProps: cm.NotifyProps,
|
||||
LastUpdateAt: cm.LastUpdateAt,
|
||||
@@ -86,10 +88,11 @@ type channelMemberWithSchemeRoles struct {
|
||||
ChannelSchemeDefaultGuestRole sql.NullString
|
||||
ChannelSchemeDefaultUserRole sql.NullString
|
||||
ChannelSchemeDefaultAdminRole sql.NullString
|
||||
MsgCountRoot int64
|
||||
}
|
||||
|
||||
func channelMemberSliceColumns() []string {
|
||||
return []string{"ChannelId", "UserId", "Roles", "LastViewedAt", "MsgCount", "MentionCount", "NotifyProps", "LastUpdateAt", "SchemeUser", "SchemeAdmin", "SchemeGuest"}
|
||||
return []string{"ChannelId", "UserId", "Roles", "LastViewedAt", "MsgCount", "MsgCountRoot", "MentionCount", "NotifyProps", "LastUpdateAt", "SchemeUser", "SchemeAdmin", "SchemeGuest"}
|
||||
}
|
||||
|
||||
func channelMemberToSlice(member *model.ChannelMember) []interface{} {
|
||||
@@ -99,6 +102,7 @@ func channelMemberToSlice(member *model.ChannelMember) []interface{} {
|
||||
resultSlice = append(resultSlice, member.ExplicitRoles)
|
||||
resultSlice = append(resultSlice, member.LastViewedAt)
|
||||
resultSlice = append(resultSlice, member.MsgCount)
|
||||
resultSlice = append(resultSlice, member.MsgCountRoot)
|
||||
resultSlice = append(resultSlice, member.MentionCount)
|
||||
resultSlice = append(resultSlice, model.MapToJson(member.NotifyProps))
|
||||
resultSlice = append(resultSlice, member.LastUpdateAt)
|
||||
@@ -230,6 +234,7 @@ func (db channelMemberWithSchemeRoles) ToModel() *model.ChannelMember {
|
||||
Roles: strings.Join(rolesResult.roles, " "),
|
||||
LastViewedAt: db.LastViewedAt,
|
||||
MsgCount: db.MsgCount,
|
||||
MsgCountRoot: db.MsgCountRoot,
|
||||
MentionCount: db.MentionCount,
|
||||
NotifyProps: db.NotifyProps,
|
||||
LastUpdateAt: db.LastUpdateAt,
|
||||
@@ -712,7 +717,10 @@ func (s SqlChannelStore) GetChannelUnread(channelId, userId string) (*model.Chan
|
||||
var unreadChannel model.ChannelUnread
|
||||
err := s.GetReplica().SelectOne(&unreadChannel,
|
||||
`SELECT
|
||||
Channels.TeamId TeamId, Channels.Id ChannelId, (Channels.TotalMsgCount - ChannelMembers.MsgCount) MsgCount, ChannelMembers.MentionCount MentionCount, ChannelMembers.NotifyProps NotifyProps
|
||||
Channels.TeamId TeamId, Channels.Id ChannelId,
|
||||
(Channels.TotalMsgCount - ChannelMembers.MsgCount) MsgCount,
|
||||
(Channels.TotalMsgCountRoot - ChannelMembers.MsgCountRoot) MsgCountRoot,
|
||||
ChannelMembers.MentionCount MentionCount, ChannelMembers.NotifyProps NotifyProps
|
||||
FROM
|
||||
Channels, ChannelMembers
|
||||
WHERE
|
||||
@@ -1181,23 +1189,25 @@ func (s SqlChannelStore) GetPublicChannelsByIdsForTeam(teamId string, channelIds
|
||||
}
|
||||
|
||||
type channelIdWithCountAndUpdateAt struct {
|
||||
Id string
|
||||
TotalMsgCount int64
|
||||
UpdateAt int64
|
||||
Id string
|
||||
TotalMsgCount int64
|
||||
TotalMsgCountRoot int64
|
||||
UpdateAt int64
|
||||
}
|
||||
|
||||
func (s SqlChannelStore) GetChannelCounts(teamId string, userId string) (*model.ChannelCounts, error) {
|
||||
var data []channelIdWithCountAndUpdateAt
|
||||
_, err := s.GetReplica().Select(&data, "SELECT Id, TotalMsgCount, UpdateAt FROM Channels WHERE Id IN (SELECT ChannelId FROM ChannelMembers WHERE UserId = :UserId) AND (TeamId = :TeamId OR TeamId = '') AND DeleteAt = 0 ORDER BY DisplayName", map[string]interface{}{"TeamId": teamId, "UserId": userId})
|
||||
_, err := s.GetReplica().Select(&data, "SELECT Id, TotalMsgCount, TotalMsgCountRoot, UpdateAt FROM Channels WHERE Id IN (SELECT ChannelId FROM ChannelMembers WHERE UserId = :UserId) AND (TeamId = :TeamId OR TeamId = '') AND DeleteAt = 0 ORDER BY DisplayName", map[string]interface{}{"TeamId": teamId, "UserId": userId})
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to get channels count with teamId=%s and userId=%s", teamId, userId)
|
||||
}
|
||||
|
||||
counts := &model.ChannelCounts{Counts: make(map[string]int64), UpdateTimes: make(map[string]int64)}
|
||||
counts := &model.ChannelCounts{Counts: make(map[string]int64), CountsRoot: make(map[string]int64), UpdateTimes: make(map[string]int64)}
|
||||
for i := range data {
|
||||
v := data[i]
|
||||
counts.Counts[v.Id] = v.TotalMsgCount
|
||||
counts.CountsRoot[v.Id] = v.TotalMsgCountRoot
|
||||
counts.UpdateTimes[v.Id] = v.UpdateAt
|
||||
}
|
||||
|
||||
@@ -2061,12 +2071,13 @@ func (s SqlChannelStore) UpdateLastViewedAt(channelIds []string, userId string,
|
||||
props["UserId"] = userId
|
||||
|
||||
var lastPostAtTimes []struct {
|
||||
Id string
|
||||
LastPostAt int64
|
||||
TotalMsgCount int64
|
||||
Id string
|
||||
LastPostAt int64
|
||||
TotalMsgCount int64
|
||||
TotalMsgCountRoot int64
|
||||
}
|
||||
|
||||
query := `SELECT Id, LastPostAt, TotalMsgCount FROM Channels WHERE Id IN ` + keys
|
||||
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.DATABASE_DRIVER_POSTGRES {
|
||||
query = `WITH c AS ( ` + query + `),
|
||||
@@ -2076,6 +2087,7 @@ func (s SqlChannelStore) UpdateLastViewedAt(channelIds []string, userId string,
|
||||
SET
|
||||
MentionCount = 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
|
||||
@@ -2106,6 +2118,7 @@ func (s SqlChannelStore) UpdateLastViewedAt(channelIds []string, userId string,
|
||||
}
|
||||
|
||||
msgCountQuery := ""
|
||||
msgCountQueryRoot := ""
|
||||
lastViewedQuery := ""
|
||||
|
||||
for index, t := range lastPostAtTimes {
|
||||
@@ -2114,6 +2127,9 @@ func (s SqlChannelStore) UpdateLastViewedAt(channelIds []string, userId string,
|
||||
props["msgCount"+strconv.Itoa(index)] = t.TotalMsgCount
|
||||
msgCountQuery += fmt.Sprintf("WHEN :channelId%d THEN GREATEST(MsgCount, :msgCount%d) ", index, index)
|
||||
|
||||
props["msgCountRoot"+strconv.Itoa(index)] = t.TotalMsgCountRoot
|
||||
msgCountQueryRoot += fmt.Sprintf("WHEN :channelId%d THEN GREATEST(MsgCountRoot, :msgCountRoot%d) ", index, index)
|
||||
|
||||
props["lastViewed"+strconv.Itoa(index)] = t.LastPostAt
|
||||
lastViewedQuery += fmt.Sprintf("WHEN :channelId%d THEN GREATEST(LastViewedAt, :lastViewed%d) ", index, index)
|
||||
|
||||
@@ -2125,6 +2141,7 @@ func (s SqlChannelStore) UpdateLastViewedAt(channelIds []string, userId string,
|
||||
SET
|
||||
MentionCount = 0,
|
||||
MsgCount = CASE ChannelId ` + msgCountQuery + ` END,
|
||||
MsgCountRoot = CASE ChannelId ` + msgCountQueryRoot + ` END,
|
||||
LastViewedAt = CASE ChannelId ` + lastViewedQuery + ` END,
|
||||
LastUpdateAt = LastViewedAt
|
||||
WHERE
|
||||
@@ -2142,8 +2159,8 @@ func (s SqlChannelStore) UpdateLastViewedAt(channelIds []string, userId string,
|
||||
}
|
||||
|
||||
// CountPostsAfter returns the number of posts in the given channel created after but not including the given timestamp. If given a non-empty user ID, only counts posts made by that user.
|
||||
func (s SqlChannelStore) CountPostsAfter(channelId string, timestamp int64, userId string) (int, error) {
|
||||
joinLeavePostTypes, params := MapStringsToQueryParams([]string{
|
||||
func (s SqlChannelStore) CountPostsAfter(channelId string, timestamp int64, userId string) (int, int, error) {
|
||||
joinLeavePostTypes := []string{
|
||||
// These types correspond to the ones checked by Post.IsJoinLeaveMessage
|
||||
model.POST_JOIN_LEAVE,
|
||||
model.POST_ADD_REMOVE,
|
||||
@@ -2155,31 +2172,25 @@ func (s SqlChannelStore) CountPostsAfter(channelId string, timestamp int64, user
|
||||
model.POST_REMOVE_FROM_CHANNEL,
|
||||
model.POST_ADD_TO_TEAM,
|
||||
model.POST_REMOVE_FROM_TEAM,
|
||||
}, "PostType")
|
||||
|
||||
query := `
|
||||
SELECT count(*)
|
||||
FROM Posts
|
||||
WHERE
|
||||
ChannelId = :ChannelId
|
||||
AND CreateAt > :CreateAt
|
||||
AND Type NOT IN ` + joinLeavePostTypes + `
|
||||
AND DeleteAt = 0
|
||||
`
|
||||
|
||||
params["ChannelId"] = channelId
|
||||
params["CreateAt"] = timestamp
|
||||
}
|
||||
query := s.getQueryBuilder().Select("count(*)").From("Posts").Where(sq.Eq{"ChannelId": channelId}).Where(sq.Gt{"CreateAt": timestamp}).Where(sq.NotEq{"Type": joinLeavePostTypes}).Where(sq.Eq{"DeleteAt": 0})
|
||||
|
||||
if userId != "" {
|
||||
query += " AND UserId = :UserId"
|
||||
params["UserId"] = userId
|
||||
query = query.Where(sq.Eq{"UserId": userId})
|
||||
}
|
||||
sql, args, _ := query.ToSql()
|
||||
|
||||
unread, err := s.GetReplica().SelectInt(query, params)
|
||||
unread, err := s.GetReplica().SelectInt(sql, args...)
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "failed to count Posts")
|
||||
return 0, 0, errors.Wrap(err, "failed to count Posts")
|
||||
}
|
||||
return int(unread), nil
|
||||
sql2, args2, _ := query.Where(sq.Eq{"RootId": ""}).ToSql()
|
||||
|
||||
unreadRoot, err := s.GetReplica().SelectInt(sql2, args2...)
|
||||
if err != nil {
|
||||
return 0, 0, errors.Wrap(err, "failed to count root Posts")
|
||||
}
|
||||
return int(unread), int(unreadRoot), nil
|
||||
}
|
||||
|
||||
// UpdateLastViewedAtPost updates a ChannelMember as if the user last read the channel at the time of the given post.
|
||||
@@ -2196,18 +2207,19 @@ func (s SqlChannelStore) UpdateLastViewedAtPost(unreadPost *model.Post, userID s
|
||||
}
|
||||
}
|
||||
|
||||
unread, err := s.CountPostsAfter(unreadPost.ChannelId, unreadDate, "")
|
||||
unread, unreadRoot, err := s.CountPostsAfter(unreadPost.ChannelId, unreadDate, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
params := map[string]interface{}{
|
||||
"mentions": mentionCount,
|
||||
"unreadCount": unread,
|
||||
"lastViewedAt": unreadDate,
|
||||
"userId": userID,
|
||||
"channelId": unreadPost.ChannelId,
|
||||
"updatedAt": model.GetMillis(),
|
||||
"mentions": mentionCount,
|
||||
"unreadCount": unread,
|
||||
"unreadCountRoot": unreadRoot,
|
||||
"lastViewedAt": unreadDate,
|
||||
"userId": userID,
|
||||
"channelId": unreadPost.ChannelId,
|
||||
"updatedAt": model.GetMillis(),
|
||||
}
|
||||
|
||||
// msg count uses the value from channels to prevent counting on older channels where no. of messages can be high.
|
||||
@@ -2218,6 +2230,7 @@ func (s SqlChannelStore) UpdateLastViewedAtPost(unreadPost *model.Post, userID s
|
||||
SET
|
||||
MentionCount = :mentions,
|
||||
MsgCount = (SELECT TotalMsgCount FROM Channels WHERE ID = :channelId) - :unreadCount,
|
||||
MsgCountRoot = (SELECT TotalMsgCountRoot FROM Channels WHERE ID = :channelId) - :unreadCountRoot,
|
||||
LastViewedAt = :lastViewedAt,
|
||||
LastUpdateAt = :updatedAt
|
||||
WHERE
|
||||
@@ -2235,6 +2248,7 @@ func (s SqlChannelStore) UpdateLastViewedAtPost(unreadPost *model.Post, userID s
|
||||
cm.UserId UserId,
|
||||
cm.ChannelId ChannelId,
|
||||
cm.MsgCount MsgCount,
|
||||
cm.MsgCountRoot MsgCountRoot,
|
||||
cm.MentionCount MentionCount,
|
||||
cm.LastViewedAt LastViewedAt,
|
||||
cm.NotifyProps NotifyProps
|
||||
|
||||
@@ -917,6 +917,7 @@ func (s *SqlGroupStore) ChannelMembersToRemove(channelID *string) ([]*model.Chan
|
||||
"ChannelMembers.UserId",
|
||||
"ChannelMembers.LastViewedAt",
|
||||
"ChannelMembers.MsgCount",
|
||||
"ChannelMembers.MsgCountRoot",
|
||||
"ChannelMembers.MentionCount",
|
||||
"ChannelMembers.NotifyProps",
|
||||
"ChannelMembers.LastUpdateAt",
|
||||
|
||||
@@ -112,6 +112,7 @@ func (s *SqlPostStore) createIndexesIfNotExists() {
|
||||
|
||||
func (s *SqlPostStore) SaveMultiple(posts []*model.Post) ([]*model.Post, int, error) {
|
||||
channelNewPosts := make(map[string]int)
|
||||
channelNewRootPosts := make(map[string]int)
|
||||
maxDateNewPosts := make(map[string]int64)
|
||||
rootIds := make(map[string]int)
|
||||
maxDateRootIds := make(map[string]int64)
|
||||
@@ -125,8 +126,7 @@ func (s *SqlPostStore) SaveMultiple(posts []*model.Post) ([]*model.Post, int, er
|
||||
return nil, idx, err
|
||||
}
|
||||
|
||||
currentChannelCount, ok := channelNewPosts[post.ChannelId]
|
||||
if !ok {
|
||||
if currentChannelCount, ok := channelNewPosts[post.ChannelId]; !ok {
|
||||
if post.IsJoinLeaveMessage() {
|
||||
channelNewPosts[post.ChannelId] = 0
|
||||
} else {
|
||||
@@ -143,11 +143,21 @@ func (s *SqlPostStore) SaveMultiple(posts []*model.Post) ([]*model.Post, int, er
|
||||
}
|
||||
|
||||
if post.RootId == "" {
|
||||
if currentChannelCount, ok := channelNewRootPosts[post.ChannelId]; !ok {
|
||||
if post.IsJoinLeaveMessage() {
|
||||
channelNewRootPosts[post.ChannelId] = 0
|
||||
} else {
|
||||
channelNewRootPosts[post.ChannelId] = 1
|
||||
}
|
||||
} else {
|
||||
if !post.IsJoinLeaveMessage() {
|
||||
channelNewRootPosts[post.ChannelId] = currentChannelCount + 1
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
currentRootCount, ok := rootIds[post.RootId]
|
||||
if !ok {
|
||||
if currentRootCount, ok := rootIds[post.RootId]; !ok {
|
||||
rootIds[post.RootId] = 1
|
||||
maxDateRootIds[post.RootId] = post.CreateAt
|
||||
} else {
|
||||
@@ -188,7 +198,9 @@ func (s *SqlPostStore) SaveMultiple(posts []*model.Post) ([]*model.Post, int, er
|
||||
}
|
||||
|
||||
for channelId, count := range channelNewPosts {
|
||||
if _, err = s.GetMaster().Exec("UPDATE Channels SET LastPostAt = GREATEST(:LastPostAt, LastPostAt), TotalMsgCount = TotalMsgCount + :Count WHERE Id = :ChannelId", map[string]interface{}{"LastPostAt": maxDateNewPosts[channelId], "ChannelId": channelId, "Count": count}); err != nil {
|
||||
countRoot := channelNewRootPosts[channelId]
|
||||
|
||||
if _, err = s.GetMaster().Exec("UPDATE Channels SET LastPostAt = GREATEST(:LastPostAt, LastPostAt), TotalMsgCount = TotalMsgCount + :Count, TotalMsgCountRoot = TotalMsgCountRoot + :CountRoot WHERE Id = :ChannelId", map[string]interface{}{"LastPostAt": maxDateNewPosts[channelId], "ChannelId": channelId, "Count": count, "CountRoot": countRoot}); err != nil {
|
||||
mlog.Warn("Error updating Channel LastPostAt.", mlog.Err(err))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1177,7 +1177,7 @@ func (s SqlTeamStore) GetTeamsForUserWithPagination(userId string, page, perPage
|
||||
// for all the channels in all the teams except the excluded ones.
|
||||
func (s SqlTeamStore) GetChannelUnreadsForAllTeams(excludeTeamId, userId string) ([]*model.ChannelUnread, error) {
|
||||
query, args, err := s.getQueryBuilder().
|
||||
Select("Channels.TeamId TeamId", "Channels.Id ChannelId", "(Channels.TotalMsgCount - ChannelMembers.MsgCount) MsgCount", "ChannelMembers.MentionCount MentionCount", "ChannelMembers.NotifyProps NotifyProps").
|
||||
Select("Channels.TeamId TeamId", "Channels.Id ChannelId", "(Channels.TotalMsgCount - ChannelMembers.MsgCount) MsgCount", "(Channels.TotalMsgCountRoot - ChannelMembers.MsgCountRoot) MsgCountRoot", "ChannelMembers.MentionCount MentionCount", "ChannelMembers.NotifyProps NotifyProps").
|
||||
From("Channels").
|
||||
Join("ChannelMembers ON Id = ChannelId").
|
||||
Where(sq.Eq{"UserId": userId, "DeleteAt": 0}).
|
||||
@@ -1199,7 +1199,7 @@ func (s SqlTeamStore) GetChannelUnreadsForAllTeams(excludeTeamId, userId string)
|
||||
// GetChannelUnreadsForTeam returns unreads msg count, mention counts and notifyProps for all the channels in a single team.
|
||||
func (s SqlTeamStore) GetChannelUnreadsForTeam(teamId, userId string) ([]*model.ChannelUnread, error) {
|
||||
query, args, err := s.getQueryBuilder().
|
||||
Select("Channels.TeamId TeamId", "Channels.Id ChannelId", "(Channels.TotalMsgCount - ChannelMembers.MsgCount) MsgCount", "ChannelMembers.MentionCount MentionCount", "ChannelMembers.NotifyProps NotifyProps").
|
||||
Select("Channels.TeamId TeamId", "Channels.Id ChannelId", "(Channels.TotalMsgCount - ChannelMembers.MsgCount) MsgCount", "(Channels.TotalMsgCountRoot - ChannelMembers.MsgCountRoot) MsgCountRoot", "ChannelMembers.MentionCount MentionCount", "ChannelMembers.NotifyProps NotifyProps").
|
||||
From("Channels").
|
||||
Join("ChannelMembers ON Id = ChannelId").
|
||||
Where(sq.Eq{"UserId": userId, "TeamId": teamId, "DeleteAt": 0}).ToSql()
|
||||
|
||||
@@ -1011,6 +1011,57 @@ func upgradeDatabaseToVersion535(sqlStore *SqlStore) {
|
||||
|
||||
sqlStore.CreateColumnIfNotExists("SidebarCategories", "Collapsed", "tinyint(1)", "boolean", "0")
|
||||
|
||||
sqlStore.CreateColumnIfNotExistsNoDefault("Channels", "TotalMsgCountRoot", "bigint", "bigint")
|
||||
sqlStore.CreateColumnIfNotExistsNoDefault("Channels", "LastRootPostAt", "bigint", "bigint")
|
||||
defer sqlStore.RemoveColumnIfExists("Channels", "LastRootPostAt")
|
||||
|
||||
// note: setting default 0 on pre-5.0 tables causes test-db-migration script to fail, so this column will be added to ignore list
|
||||
sqlStore.CreateColumnIfNotExists("ChannelMembers", "MsgCountRoot", "bigint", "bigint", "0")
|
||||
sqlStore.AlterColumnDefaultIfExists("ChannelMembers", "MsgCountRoot", model.NewString("0"), model.NewString("0"))
|
||||
|
||||
forceIndex := ""
|
||||
if sqlStore.DriverName() == model.DATABASE_DRIVER_MYSQL {
|
||||
forceIndex = "FORCE INDEX(idx_posts_channel_id)"
|
||||
}
|
||||
totalMsgCountRootCTE := `
|
||||
SELECT Channels.Id channelid, COALESCE(COUNT(*),0) newcount, COALESCE(MAX(Posts.CreateAt), 0) as lastpost
|
||||
FROM Channels
|
||||
LEFT JOIN Posts ` + forceIndex + ` ON Channels.Id = Posts.ChannelId
|
||||
WHERE Posts.RootId = ''
|
||||
GROUP BY Channels.Id
|
||||
`
|
||||
channelsCTE := "SELECT TotalMsgCountRoot, Id, LastRootPostAt from Channels"
|
||||
updateChannels := `
|
||||
WITH q AS (` + totalMsgCountRootCTE + `)
|
||||
UPDATE Channels SET TotalMsgCountRoot = q.newcount, LastRootPostAt=q.lastpost
|
||||
FROM q where q.channelid=Channels.Id;
|
||||
`
|
||||
updateChannelMembers := `
|
||||
WITH q as (` + channelsCTE + `)
|
||||
UPDATE ChannelMembers CM SET MsgCountRoot=TotalMsgCountRoot
|
||||
FROM q WHERE q.id=CM.ChannelId AND LastViewedAt >= q.lastrootpostat;
|
||||
`
|
||||
if sqlStore.DriverName() == model.DATABASE_DRIVER_MYSQL {
|
||||
updateChannels = `
|
||||
UPDATE Channels
|
||||
INNER Join (` + totalMsgCountRootCTE + `) as q
|
||||
ON q.channelid=Channels.Id
|
||||
SET TotalMsgCountRoot = q.newcount, LastRootPostAt=q.lastpost;
|
||||
`
|
||||
updateChannelMembers = `
|
||||
UPDATE ChannelMembers CM
|
||||
INNER JOIN (` + channelsCTE + `) as q
|
||||
ON q.id=CM.ChannelId and LastViewedAt >= q.lastrootpostat
|
||||
SET MsgCountRoot=TotalMsgCountRoot
|
||||
`
|
||||
}
|
||||
if _, err := sqlStore.GetMaster().Exec(updateChannels); err != nil {
|
||||
mlog.Error("Error updating Channels table", mlog.Err(err))
|
||||
}
|
||||
if _, err := sqlStore.GetMaster().Exec(updateChannelMembers); err != nil {
|
||||
mlog.Error("Error updating ChannelMembers table", mlog.Err(err))
|
||||
}
|
||||
|
||||
// saveSchemaVersion(sqlStore, Version5350)
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -6,8 +6,10 @@ package sqlstore
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v5/model"
|
||||
"github.com/mattermost/mattermost-server/v5/store"
|
||||
)
|
||||
|
||||
@@ -103,3 +105,139 @@ func TestSaveSchemaVersion(t *testing.T) {
|
||||
})
|
||||
})
|
||||
}
|
||||
func createChannelMemberWithLastViewAt(ss store.Store, channelId, userId string, lastViewAt int64) *model.ChannelMember {
|
||||
m := model.ChannelMember{}
|
||||
m.ChannelId = channelId
|
||||
m.UserId = userId
|
||||
m.LastViewedAt = lastViewAt
|
||||
m.NotifyProps = model.GetDefaultChannelNotifyProps()
|
||||
cm, _ := ss.Channel().SaveMember(&m)
|
||||
return cm
|
||||
}
|
||||
func createPostWithTimestamp(ss store.Store, channelId, userId, rootId, parentId string, timestamp int64) *model.Post {
|
||||
m := model.Post{}
|
||||
m.CreateAt = timestamp
|
||||
m.ChannelId = channelId
|
||||
m.UserId = userId
|
||||
m.RootId = rootId
|
||||
m.ParentId = parentId
|
||||
m.Message = "zz" + model.NewId() + "b"
|
||||
p, _ := ss.Post().Save(&m)
|
||||
return p
|
||||
}
|
||||
|
||||
func createChannelWithLastPostAt(ss store.Store, teamId, creatorId string, lastPostAt, msgCount, rootCount int64) (*model.Channel, error) {
|
||||
m := model.Channel{}
|
||||
m.TeamId = teamId
|
||||
m.TotalMsgCount = msgCount
|
||||
m.TotalMsgCountRoot = rootCount
|
||||
m.LastPostAt = lastPostAt
|
||||
m.CreatorId = creatorId
|
||||
m.DisplayName = "Name"
|
||||
m.Name = "zz" + model.NewId() + "b"
|
||||
m.Type = model.CHANNEL_OPEN
|
||||
return ss.Channel().Save(&m, -1)
|
||||
}
|
||||
func TestMsgCountRootMigration(t *testing.T) {
|
||||
type TestCaseChannel struct {
|
||||
Name string
|
||||
PostTimes []int64
|
||||
ReplyTimes []int64
|
||||
MembershipsLastViewAt []int64
|
||||
ExpectedMembershipMsgCountRoot []int64
|
||||
}
|
||||
type TestTableEntry struct {
|
||||
name string
|
||||
data []TestCaseChannel
|
||||
}
|
||||
testTable := []TestTableEntry{
|
||||
{
|
||||
name: "test1",
|
||||
data: []TestCaseChannel{
|
||||
{
|
||||
Name: "channel with one post",
|
||||
PostTimes: []int64{1000},
|
||||
ReplyTimes: []int64{0},
|
||||
MembershipsLastViewAt: []int64{1},
|
||||
ExpectedMembershipMsgCountRoot: []int64{0},
|
||||
},
|
||||
{
|
||||
Name: "channel with one post, read",
|
||||
PostTimes: []int64{1000},
|
||||
ReplyTimes: []int64{0},
|
||||
MembershipsLastViewAt: []int64{1000},
|
||||
ExpectedMembershipMsgCountRoot: []int64{1},
|
||||
},
|
||||
{
|
||||
Name: "with one reply, viewed after 2nd root",
|
||||
PostTimes: []int64{1000, 2000, 3000, 4000},
|
||||
ReplyTimes: []int64{1001, 0, 0, 0},
|
||||
MembershipsLastViewAt: []int64{2001},
|
||||
ExpectedMembershipMsgCountRoot: []int64{0},
|
||||
},
|
||||
{
|
||||
Name: "two replies, 3 memberships",
|
||||
PostTimes: []int64{1000, 2000, 3000},
|
||||
ReplyTimes: []int64{1001, 2001, 0},
|
||||
MembershipsLastViewAt: []int64{2000, 5000, 0},
|
||||
ExpectedMembershipMsgCountRoot: []int64{0, 3, 0},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, testCase := range testTable {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
StoreTest(t, func(t *testing.T, ss store.Store) {
|
||||
sqlStore := ss.(*SqlStore)
|
||||
team := createTeam(ss)
|
||||
for _, testChannel := range testCase.data {
|
||||
t.Run(testChannel.Name, func(t *testing.T) {
|
||||
lastPostAt := int64(0)
|
||||
for i := range testChannel.PostTimes {
|
||||
if testChannel.PostTimes[i] > lastPostAt {
|
||||
lastPostAt = testChannel.PostTimes[i]
|
||||
}
|
||||
if testChannel.ReplyTimes[i] > lastPostAt {
|
||||
lastPostAt = testChannel.ReplyTimes[i]
|
||||
}
|
||||
}
|
||||
channel, err := createChannelWithLastPostAt(ss, team.Id, model.NewId(), lastPostAt, int64(len(testChannel.PostTimes)+len(testChannel.ReplyTimes)), int64(len(testChannel.PostTimes)))
|
||||
require.NoError(t, err)
|
||||
var userIds []string
|
||||
for _, md := range testChannel.MembershipsLastViewAt {
|
||||
user := createUser(ss)
|
||||
userIds = append(userIds, user.Id)
|
||||
require.NotNil(t, user)
|
||||
cm := createChannelMemberWithLastViewAt(ss, channel.Id, user.Id, md)
|
||||
require.NotNil(t, cm)
|
||||
}
|
||||
for i, pt := range testChannel.PostTimes {
|
||||
rt := testChannel.ReplyTimes[i]
|
||||
post := createPostWithTimestamp(ss, channel.Id, model.NewId(), "", "", pt)
|
||||
require.NotNil(t, post)
|
||||
if rt > 0 {
|
||||
reply := createPostWithTimestamp(ss, channel.Id, model.NewId(), post.Id, post.Id, rt)
|
||||
require.NotNil(t, reply)
|
||||
}
|
||||
}
|
||||
|
||||
upgradeDatabaseToVersion535(sqlStore)
|
||||
|
||||
members, err := ss.Channel().GetMembersByIds(channel.Id, userIds)
|
||||
require.NoError(t, err)
|
||||
|
||||
for _, m := range *members {
|
||||
for i, uid := range userIds {
|
||||
if m.UserId == uid {
|
||||
assert.Equal(t, testChannel.ExpectedMembershipMsgCountRoot[i], m.MsgCountRoot)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user