Migrates Channel.AutocompleteInTeam, Channel.SearchInTeam and Channel.SearchMore to sync by default (#11229)

Этот коммит содержится в:
Rodrigo Villablanca Vásquez
2019-06-17 14:32:37 -04:00
коммит произвёл jfrerich
родитель 651c3196a0
Коммит f97e6368c8
5 изменённых файлов: 169 добавлений и 166 удалений

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

@@ -1774,11 +1774,7 @@ func (a *App) AutocompleteChannels(teamId string, term string) (*model.ChannelLi
return &channelList, nil
}
result := <-a.Srv.Store.Channel().AutocompleteInTeam(teamId, term, includeDeleted)
if result.Err != nil {
return nil, result.Err
}
return result.Data.(*model.ChannelList), nil
return a.Srv.Store.Channel().AutocompleteInTeam(teamId, term, includeDeleted)
}
func (a *App) AutocompleteChannelsForSearch(teamId string, userId string, term string) (*model.ChannelList, *model.AppError) {
@@ -1818,20 +1814,12 @@ func (a *App) SearchChannels(teamId string, term string) (*model.ChannelList, *m
term = strings.TrimSpace(term)
result := <-a.Srv.Store.Channel().SearchInTeam(teamId, term, includeDeleted)
if result.Err != nil {
return nil, result.Err
}
return result.Data.(*model.ChannelList), nil
return a.Srv.Store.Channel().SearchInTeam(teamId, term, includeDeleted)
}
func (a *App) SearchChannelsUserNotIn(teamId string, userId string, term string) (*model.ChannelList, *model.AppError) {
term = strings.TrimSpace(term)
result := <-a.Srv.Store.Channel().SearchMore(userId, teamId, term)
if result.Err != nil {
return nil, result.Err
}
return result.Data.(*model.ChannelList), nil
return a.Srv.Store.Channel().SearchMore(userId, teamId, term)
}
func (a *App) MarkChannelsAsViewed(channelIds []string, userId string, currentSessionId string) (map[string]int64, *model.AppError) {

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

@@ -1957,50 +1957,48 @@ func (s SqlChannelStore) GetMembersForUserWithPagination(teamId, userId string,
})
}
func (s SqlChannelStore) AutocompleteInTeam(teamId string, term string, includeDeleted bool) store.StoreChannel {
return store.Do(func(result *store.StoreResult) {
deleteFilter := "AND c.DeleteAt = 0"
if includeDeleted {
deleteFilter = ""
func (s SqlChannelStore) AutocompleteInTeam(teamId string, term string, includeDeleted bool) (*model.ChannelList, *model.AppError) {
deleteFilter := "AND c.DeleteAt = 0"
if includeDeleted {
deleteFilter = ""
}
queryFormat := `
SELECT
Channels.*
FROM
Channels
JOIN
PublicChannels c ON (c.Id = Channels.Id)
WHERE
c.TeamId = :TeamId
` + deleteFilter + `
%v
LIMIT ` + strconv.Itoa(model.CHANNEL_SEARCH_DEFAULT_LIMIT)
var channels model.ChannelList
if likeClause, likeTerm := s.buildLIKEClause(term, "c.Name, c.DisplayName, c.Purpose"); likeClause == "" {
if _, err := s.GetReplica().Select(&channels, fmt.Sprintf(queryFormat, ""), map[string]interface{}{"TeamId": teamId}); err != nil {
return nil, model.NewAppError("SqlChannelStore.AutocompleteInTeam", "store.sql_channel.search.app_error", nil, "term="+term+", "+", "+err.Error(), http.StatusInternalServerError)
}
} else {
// Using a UNION results in index_merge and fulltext queries and is much faster than the ref
// query you would get using an OR of the LIKE and full-text clauses.
fulltextClause, fulltextTerm := s.buildFulltextClause(term, "c.Name, c.DisplayName, c.Purpose")
likeQuery := fmt.Sprintf(queryFormat, "AND "+likeClause)
fulltextQuery := fmt.Sprintf(queryFormat, "AND "+fulltextClause)
query := fmt.Sprintf("(%v) UNION (%v) LIMIT 50", likeQuery, fulltextQuery)
queryFormat := `
SELECT
Channels.*
FROM
Channels
JOIN
PublicChannels c ON (c.Id = Channels.Id)
WHERE
c.TeamId = :TeamId
` + deleteFilter + `
%v
LIMIT ` + strconv.Itoa(model.CHANNEL_SEARCH_DEFAULT_LIMIT)
var channels model.ChannelList
if likeClause, likeTerm := s.buildLIKEClause(term, "c.Name, c.DisplayName, c.Purpose"); likeClause == "" {
if _, err := s.GetReplica().Select(&channels, fmt.Sprintf(queryFormat, ""), map[string]interface{}{"TeamId": teamId}); err != nil {
result.Err = model.NewAppError("SqlChannelStore.AutocompleteInTeam", "store.sql_channel.search.app_error", nil, "term="+term+", "+", "+err.Error(), http.StatusInternalServerError)
}
} else {
// Using a UNION results in index_merge and fulltext queries and is much faster than the ref
// query you would get using an OR of the LIKE and full-text clauses.
fulltextClause, fulltextTerm := s.buildFulltextClause(term, "c.Name, c.DisplayName, c.Purpose")
likeQuery := fmt.Sprintf(queryFormat, "AND "+likeClause)
fulltextQuery := fmt.Sprintf(queryFormat, "AND "+fulltextClause)
query := fmt.Sprintf("(%v) UNION (%v) LIMIT 50", likeQuery, fulltextQuery)
if _, err := s.GetReplica().Select(&channels, query, map[string]interface{}{"TeamId": teamId, "LikeTerm": likeTerm, "FulltextTerm": fulltextTerm}); err != nil {
result.Err = model.NewAppError("SqlChannelStore.AutocompleteInTeam", "store.sql_channel.search.app_error", nil, "term="+term+", "+", "+err.Error(), http.StatusInternalServerError)
}
if _, err := s.GetReplica().Select(&channels, query, map[string]interface{}{"TeamId": teamId, "LikeTerm": likeTerm, "FulltextTerm": fulltextTerm}); err != nil {
return nil, model.NewAppError("SqlChannelStore.AutocompleteInTeam", "store.sql_channel.search.app_error", nil, "term="+term+", "+", "+err.Error(), http.StatusInternalServerError)
}
}
sort.Slice(channels, func(a, b int) bool {
return strings.ToLower(channels[a].DisplayName) < strings.ToLower(channels[b].DisplayName)
})
result.Data = &channels
sort.Slice(channels, func(a, b int) bool {
return strings.ToLower(channels[a].DisplayName) < strings.ToLower(channels[b].DisplayName)
})
return &channels, nil
}
func (s SqlChannelStore) AutocompleteInTeamForSearch(teamId string, userId string, term string, includeDeleted bool) store.StoreChannel {
@@ -2100,29 +2098,27 @@ func (s SqlChannelStore) autocompleteInTeamForSearchDirectMessages(userId string
return channels, nil
}
func (s SqlChannelStore) SearchInTeam(teamId string, term string, includeDeleted bool) store.StoreChannel {
return store.Do(func(result *store.StoreResult) {
deleteFilter := "AND c.DeleteAt = 0"
if includeDeleted {
deleteFilter = ""
}
func (s SqlChannelStore) SearchInTeam(teamId string, term string, includeDeleted bool) (*model.ChannelList, *model.AppError) {
deleteFilter := "AND c.DeleteAt = 0"
if includeDeleted {
deleteFilter = ""
}
*result = s.performSearch(`
SELECT
Channels.*
FROM
Channels
JOIN
PublicChannels c ON (c.Id = Channels.Id)
WHERE
c.TeamId = :TeamId
`+deleteFilter+`
SEARCH_CLAUSE
ORDER BY c.DisplayName
LIMIT 100
return s.performSearch(`
SELECT
Channels.*
FROM
Channels
JOIN
PublicChannels c ON (c.Id = Channels.Id)
WHERE
c.TeamId = :TeamId
`+deleteFilter+`
SEARCH_CLAUSE
ORDER BY c.DisplayName
LIMIT 100
`, term, map[string]interface{}{
"TeamId": teamId,
})
"TeamId": teamId,
})
}
@@ -2172,37 +2168,35 @@ func (s SqlChannelStore) SearchAllChannels(term string, opts store.ChannelSearch
})
}
func (s SqlChannelStore) SearchMore(userId string, teamId string, term string) store.StoreChannel {
return store.Do(func(result *store.StoreResult) {
*result = s.performSearch(`
func (s SqlChannelStore) SearchMore(userId string, teamId string, term string) (*model.ChannelList, *model.AppError) {
return s.performSearch(`
SELECT
Channels.*
FROM
Channels
JOIN
PublicChannels c ON (c.Id = Channels.Id)
WHERE
c.TeamId = :TeamId
AND c.DeleteAt = 0
AND c.Id NOT IN (
SELECT
Channels.*
c.Id
FROM
Channels
PublicChannels c
JOIN
PublicChannels c ON (c.Id = Channels.Id)
ChannelMembers cm ON (cm.ChannelId = c.Id)
WHERE
c.TeamId = :TeamId
c.TeamId = :TeamId
AND cm.UserId = :UserId
AND c.DeleteAt = 0
AND c.Id NOT IN (
SELECT
c.Id
FROM
PublicChannels c
JOIN
ChannelMembers cm ON (cm.ChannelId = c.Id)
WHERE
c.TeamId = :TeamId
AND cm.UserId = :UserId
AND c.DeleteAt = 0
)
SEARCH_CLAUSE
ORDER BY c.DisplayName
LIMIT 100
)
SEARCH_CLAUSE
ORDER BY c.DisplayName
LIMIT 100
`, term, map[string]interface{}{
"TeamId": teamId,
"UserId": userId,
})
"TeamId": teamId,
"UserId": userId,
})
}
@@ -2277,9 +2271,7 @@ func (s SqlChannelStore) buildFulltextClause(term string, searchColumns string)
return
}
func (s SqlChannelStore) performSearch(searchQuery string, term string, parameters map[string]interface{}) store.StoreResult {
result := store.StoreResult{}
func (s SqlChannelStore) performSearch(searchQuery string, term string, parameters map[string]interface{}) (*model.ChannelList, *model.AppError) {
likeClause, likeTerm := s.buildLIKEClause(term, "c.Name, c.DisplayName, c.Purpose")
if likeTerm == "" {
// If the likeTerm is empty after preparing, then don't bother searching.
@@ -2294,12 +2286,10 @@ func (s SqlChannelStore) performSearch(searchQuery string, term string, paramete
var channels model.ChannelList
if _, err := s.GetReplica().Select(&channels, searchQuery, parameters); err != nil {
result.Err = model.NewAppError("SqlChannelStore.Search", "store.sql_channel.search.app_error", nil, "term="+term+", "+", "+err.Error(), http.StatusInternalServerError)
return result
return nil, model.NewAppError("SqlChannelStore.Search", "store.sql_channel.search.app_error", nil, "term="+term+", "+", "+err.Error(), http.StatusInternalServerError)
}
result.Data = &channels
return result
return &channels, nil
}
func (s SqlChannelStore) GetMembersByIds(channelId string, userIds []string) store.StoreChannel {

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

@@ -180,11 +180,11 @@ type ChannelStore interface {
AnalyticsTypeCount(teamId string, channelType string) (int64, *model.AppError)
GetMembersForUser(teamId string, userId string) StoreChannel
GetMembersForUserWithPagination(teamId, userId string, page, perPage int) StoreChannel
AutocompleteInTeam(teamId string, term string, includeDeleted bool) StoreChannel
AutocompleteInTeam(teamId string, term string, includeDeleted bool) (*model.ChannelList, *model.AppError)
AutocompleteInTeamForSearch(teamId string, userId string, term string, includeDeleted bool) StoreChannel
SearchAllChannels(term string, opts ChannelSearchOpts) StoreChannel
SearchInTeam(teamId string, term string, includeDeleted bool) StoreChannel
SearchMore(userId string, teamId string, term string) StoreChannel
SearchInTeam(teamId string, term string, includeDeleted bool) (*model.ChannelList, *model.AppError)
SearchMore(userId string, teamId string, term string) (*model.ChannelList, *model.AppError)
GetMembersByIds(channelId string, userIds []string) StoreChannel
AnalyticsDeletedTypeCount(teamId string, channelType string) StoreChannel
GetChannelUnread(channelId, userId string) (*model.ChannelUnread, *model.AppError)

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

@@ -2108,33 +2108,33 @@ func testChannelStoreSearchMore(t *testing.T, ss store.Store) {
require.Nil(t, err, "channel should have been deleted")
t.Run("three public channels matching 'ChannelA', but already a member of one and one deleted", func(t *testing.T) {
result := <-ss.Channel().SearchMore(m1.UserId, teamId, "ChannelA")
require.Nil(t, result.Err)
require.Equal(t, &model.ChannelList{&o3}, result.Data.(*model.ChannelList))
channels, err := ss.Channel().SearchMore(m1.UserId, teamId, "ChannelA")
require.Nil(t, err)
require.Equal(t, &model.ChannelList{&o3}, channels)
})
t.Run("one public channels, but already a member", func(t *testing.T) {
result := <-ss.Channel().SearchMore(m1.UserId, teamId, o4.Name)
require.Nil(t, result.Err)
require.Equal(t, &model.ChannelList{}, result.Data.(*model.ChannelList))
channels, err := ss.Channel().SearchMore(m1.UserId, teamId, o4.Name)
require.Nil(t, err)
require.Equal(t, &model.ChannelList{}, channels)
})
t.Run("three matching channels, but only two public", func(t *testing.T) {
result := <-ss.Channel().SearchMore(m1.UserId, teamId, "off-")
require.Nil(t, result.Err)
require.Equal(t, &model.ChannelList{&o7, &o6}, result.Data.(*model.ChannelList))
channels, err := ss.Channel().SearchMore(m1.UserId, teamId, "off-")
require.Nil(t, err)
require.Equal(t, &model.ChannelList{&o7, &o6}, channels)
})
t.Run("one channel matching 'off-topic'", func(t *testing.T) {
result := <-ss.Channel().SearchMore(m1.UserId, teamId, "off-topic")
require.Nil(t, result.Err)
require.Equal(t, &model.ChannelList{&o6}, result.Data.(*model.ChannelList))
channels, err := ss.Channel().SearchMore(m1.UserId, teamId, "off-topic")
require.Nil(t, err)
require.Equal(t, &model.ChannelList{&o6}, channels)
})
t.Run("search purpose", func(t *testing.T) {
result := <-ss.Channel().SearchMore(m1.UserId, teamId, "now searchable")
require.Nil(t, result.Err)
require.Equal(t, &model.ChannelList{&o9}, result.Data.(*model.ChannelList))
channels, err := ss.Channel().SearchMore(m1.UserId, teamId, "now searchable")
require.Nil(t, err)
require.Equal(t, &model.ChannelList{&o9}, channels)
})
}
@@ -2320,16 +2320,14 @@ func testChannelStoreSearchInTeam(t *testing.T, ss store.Store) {
{"pipe ignored", teamId, "town square |", false, &model.ChannelList{&o9}},
}
for name, search := range map[string]func(teamId string, term string, includeDeleted bool) store.StoreChannel{
for name, search := range map[string]func(teamId string, term string, includeDeleted bool) (*model.ChannelList, *model.AppError){
"AutocompleteInTeam": ss.Channel().AutocompleteInTeam,
"SearchInTeam": ss.Channel().SearchInTeam,
} {
for _, testCase := range testCases {
t.Run(testCase.Description, func(t *testing.T) {
result := <-search(testCase.TeamId, testCase.Term, testCase.IncludeDeleted)
require.Nil(t, result.Err)
channels := result.Data.(*model.ChannelList)
channels, err := search(testCase.TeamId, testCase.Term, testCase.IncludeDeleted)
require.Nil(t, err)
// AutoCompleteInTeam doesn't currently sort its output results.
if name == "AutocompleteInTeam" {
@@ -3150,9 +3148,9 @@ func testMaterializedPublicChannels(t *testing.T, ss store.Store, s SqlSupplier)
require.Nil(t, err)
t.Run("o1 and o2 initially listed in public channels", func(t *testing.T) {
result := <-ss.Channel().SearchInTeam(teamId, "", true)
require.Nil(t, result.Err)
require.Equal(t, &model.ChannelList{&o1, &o2}, result.Data.(*model.ChannelList))
channels, channelErr := ss.Channel().SearchInTeam(teamId, "", true)
require.Nil(t, channelErr)
require.Equal(t, &model.ChannelList{&o1, &o2}, channels)
})
o1.DeleteAt = model.GetMillis()
@@ -3162,17 +3160,17 @@ func testMaterializedPublicChannels(t *testing.T, ss store.Store, s SqlSupplier)
require.Nil(t, e, "channel should have been deleted")
t.Run("o1 still listed in public channels when marked as deleted", func(t *testing.T) {
result := <-ss.Channel().SearchInTeam(teamId, "", true)
require.Nil(t, result.Err)
require.Equal(t, &model.ChannelList{&o1, &o2}, result.Data.(*model.ChannelList))
channels, channelErr := ss.Channel().SearchInTeam(teamId, "", true)
require.Nil(t, channelErr)
require.Equal(t, &model.ChannelList{&o1, &o2}, channels)
})
<-ss.Channel().PermanentDelete(o1.Id)
t.Run("o1 no longer listed in public channels when permanently deleted", func(t *testing.T) {
result := <-ss.Channel().SearchInTeam(teamId, "", true)
require.Nil(t, result.Err)
require.Equal(t, &model.ChannelList{&o2}, result.Data.(*model.ChannelList))
channels, channelErr := ss.Channel().SearchInTeam(teamId, "", true)
require.Nil(t, channelErr)
require.Equal(t, &model.ChannelList{&o2}, channels)
})
o2.Type = model.CHANNEL_PRIVATE
@@ -3180,9 +3178,9 @@ func testMaterializedPublicChannels(t *testing.T, ss store.Store, s SqlSupplier)
require.Nil(t, appErr)
t.Run("o2 no longer listed since now private", func(t *testing.T) {
result := <-ss.Channel().SearchInTeam(teamId, "", true)
require.Nil(t, result.Err)
require.Equal(t, &model.ChannelList{}, result.Data.(*model.ChannelList))
channels, channelErr := ss.Channel().SearchInTeam(teamId, "", true)
require.Nil(t, channelErr)
require.Equal(t, &model.ChannelList{}, channels)
})
o2.Type = model.CHANNEL_OPEN
@@ -3190,9 +3188,9 @@ func testMaterializedPublicChannels(t *testing.T, ss store.Store, s SqlSupplier)
require.Nil(t, appErr)
t.Run("o2 listed once again since now public", func(t *testing.T) {
result := <-ss.Channel().SearchInTeam(teamId, "", true)
require.Nil(t, result.Err)
require.Equal(t, &model.ChannelList{&o2}, result.Data.(*model.ChannelList))
channels, channelErr := ss.Channel().SearchInTeam(teamId, "", true)
require.Nil(t, channelErr)
require.Equal(t, &model.ChannelList{&o2}, channels)
})
// o3 is a public channel on the team that already existed in the PublicChannels table.
@@ -3246,9 +3244,9 @@ func testMaterializedPublicChannels(t *testing.T, ss store.Store, s SqlSupplier)
require.Nil(t, execerr)
t.Run("verify o3 INSERT converted to UPDATE", func(t *testing.T) {
result := <-ss.Channel().SearchInTeam(teamId, "", true)
require.Nil(t, result.Err)
require.Equal(t, &model.ChannelList{&o2, &o3}, result.Data.(*model.ChannelList))
channels, channelErr := ss.Channel().SearchInTeam(teamId, "", true)
require.Nil(t, channelErr)
require.Equal(t, &model.ChannelList{&o2, &o3}, channels)
})
// o4 is a public channel on the team that existed in the Channels table but was omitted from the PublicChannels table.
@@ -3277,9 +3275,9 @@ func testMaterializedPublicChannels(t *testing.T, ss store.Store, s SqlSupplier)
require.Nil(t, appErr)
t.Run("verify o4 UPDATE converted to INSERT", func(t *testing.T) {
result := <-ss.Channel().SearchInTeam(teamId, "", true)
require.Nil(t, result.Err)
require.Equal(t, &model.ChannelList{&o2, &o3, &o4}, result.Data.(*model.ChannelList))
channels, err := ss.Channel().SearchInTeam(teamId, "", true)
require.Nil(t, err)
require.Equal(t, &model.ChannelList{&o2, &o3, &o4}, channels)
})
}

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

@@ -53,19 +53,28 @@ func (_m *ChannelStore) AnalyticsTypeCount(teamId string, channelType string) (i
}
// AutocompleteInTeam provides a mock function with given fields: teamId, term, includeDeleted
func (_m *ChannelStore) AutocompleteInTeam(teamId string, term string, includeDeleted bool) store.StoreChannel {
func (_m *ChannelStore) AutocompleteInTeam(teamId string, term string, includeDeleted bool) (*model.ChannelList, *model.AppError) {
ret := _m.Called(teamId, term, includeDeleted)
var r0 store.StoreChannel
if rf, ok := ret.Get(0).(func(string, string, bool) store.StoreChannel); ok {
var r0 *model.ChannelList
if rf, ok := ret.Get(0).(func(string, string, bool) *model.ChannelList); ok {
r0 = rf(teamId, term, includeDeleted)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.StoreChannel)
r0 = ret.Get(0).(*model.ChannelList)
}
}
return r0
var r1 *model.AppError
if rf, ok := ret.Get(1).(func(string, string, bool) *model.AppError); ok {
r1 = rf(teamId, term, includeDeleted)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// AutocompleteInTeamForSearch provides a mock function with given fields: teamId, userId, term, includeDeleted
@@ -1072,35 +1081,53 @@ func (_m *ChannelStore) SearchAllChannels(term string, opts store.ChannelSearchO
}
// SearchInTeam provides a mock function with given fields: teamId, term, includeDeleted
func (_m *ChannelStore) SearchInTeam(teamId string, term string, includeDeleted bool) store.StoreChannel {
func (_m *ChannelStore) SearchInTeam(teamId string, term string, includeDeleted bool) (*model.ChannelList, *model.AppError) {
ret := _m.Called(teamId, term, includeDeleted)
var r0 store.StoreChannel
if rf, ok := ret.Get(0).(func(string, string, bool) store.StoreChannel); ok {
var r0 *model.ChannelList
if rf, ok := ret.Get(0).(func(string, string, bool) *model.ChannelList); ok {
r0 = rf(teamId, term, includeDeleted)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.StoreChannel)
r0 = ret.Get(0).(*model.ChannelList)
}
}
return r0
var r1 *model.AppError
if rf, ok := ret.Get(1).(func(string, string, bool) *model.AppError); ok {
r1 = rf(teamId, term, includeDeleted)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// SearchMore provides a mock function with given fields: userId, teamId, term
func (_m *ChannelStore) SearchMore(userId string, teamId string, term string) store.StoreChannel {
func (_m *ChannelStore) SearchMore(userId string, teamId string, term string) (*model.ChannelList, *model.AppError) {
ret := _m.Called(userId, teamId, term)
var r0 store.StoreChannel
if rf, ok := ret.Get(0).(func(string, string, string) store.StoreChannel); ok {
var r0 *model.ChannelList
if rf, ok := ret.Get(0).(func(string, string, string) *model.ChannelList); ok {
r0 = rf(userId, teamId, term)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.StoreChannel)
r0 = ret.Get(0).(*model.ChannelList)
}
}
return r0
var r1 *model.AppError
if rf, ok := ret.Get(1).(func(string, string, string) *model.AppError); ok {
r1 = rf(userId, teamId, term)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// SetDeleteAt provides a mock function with given fields: channelId, deleteAt, updateAt