Added from:, in:, and channel: search modifiers

Этот коммит содержится в:
hmhealey
2015-10-17 14:37:51 -04:00
родитель 754f1721fe
Коммит 06fd374c19
8 изменённых файлов: 419 добавлений и 67 удалений

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

@@ -680,16 +680,16 @@ func searchPosts(c *Context, w http.ResponseWriter, r *http.Request) {
return return
} }
hashtagTerms, plainTerms := model.ParseHashtags(terms) plainSearchParams, hashtagSearchParams := model.ParseSearchParams(terms)
var hchan store.StoreChannel var hchan store.StoreChannel
if len(hashtagTerms) != 0 { if hashtagSearchParams != nil {
hchan = Srv.Store.Post().Search(c.Session.TeamId, c.Session.UserId, hashtagTerms, true) hchan = Srv.Store.Post().Search(c.Session.TeamId, c.Session.UserId, hashtagSearchParams)
} }
var pchan store.StoreChannel var pchan store.StoreChannel
if len(plainTerms) != 0 { if plainSearchParams != nil {
pchan = Srv.Store.Post().Search(c.Session.TeamId, c.Session.UserId, terms, false) pchan = Srv.Store.Post().Search(c.Session.TeamId, c.Session.UserId, plainSearchParams)
} }
mainList := &model.PostList{} mainList := &model.PostList{}

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

@@ -406,6 +406,128 @@ func TestSearchHashtagPosts(t *testing.T) {
} }
} }
func TestSearchPostsInChannel(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
channel1 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
post1 := &model.Post{ChannelId: channel1.Id, Message: "sgtitlereview with space"}
post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
channel2 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
post2 := &model.Post{ChannelId: channel2.Id, Message: "sgtitlereview\n with return"}
post2 = Client.Must(Client.CreatePost(post2)).Data.(*model.Post)
post3 := &model.Post{ChannelId: channel2.Id, Message: "other message with no return"}
post3 = Client.Must(Client.CreatePost(post3)).Data.(*model.Post)
if result := Client.Must(Client.SearchPosts("channel:")).Data.(*model.PostList); len(result.Order) != 0 {
t.Fatalf("wrong number of posts returned %v", len(result.Order))
}
if result := Client.Must(Client.SearchPosts("in:")).Data.(*model.PostList); len(result.Order) != 0 {
t.Fatalf("wrong number of posts returned %v", len(result.Order))
}
if result := Client.Must(Client.SearchPosts("channel:" + channel1.Name)).Data.(*model.PostList); len(result.Order) != 1 {
t.Fatalf("wrong number of posts returned %v", len(result.Order))
}
if result := Client.Must(Client.SearchPosts("in: " + channel2.Name)).Data.(*model.PostList); len(result.Order) != 2 {
t.Fatalf("wrong number of posts returned %v", len(result.Order))
}
if result := Client.Must(Client.SearchPosts("channel: " + channel2.Name)).Data.(*model.PostList); len(result.Order) != 2 {
t.Fatalf("wrong number of posts returned %v", len(result.Order))
}
if result := Client.Must(Client.SearchPosts("ChAnNeL: " + channel2.Name)).Data.(*model.PostList); len(result.Order) != 2 {
t.Fatalf("wrong number of posts returned %v", len(result.Order))
}
if result := Client.Must(Client.SearchPosts("sgtitlereview")).Data.(*model.PostList); len(result.Order) != 2 {
t.Fatalf("wrong number of posts returned %v", len(result.Order))
}
if result := Client.Must(Client.SearchPosts("sgtitlereview in:")).Data.(*model.PostList); len(result.Order) != 2 {
t.Fatalf("wrong number of posts returned %v", len(result.Order))
}
if result := Client.Must(Client.SearchPosts("sgtitlereview channel:" + channel1.Name)).Data.(*model.PostList); len(result.Order) != 1 {
t.Fatalf("wrong number of posts returned %v", len(result.Order))
}
if result := Client.Must(Client.SearchPosts("sgtitlereview in: " + channel2.Name)).Data.(*model.PostList); len(result.Order) != 1 {
t.Fatalf("wrong number of posts returned %v", len(result.Order))
}
if result := Client.Must(Client.SearchPosts("sgtitlereview channel: " + channel2.Name)).Data.(*model.PostList); len(result.Order) != 1 {
t.Fatalf("wrong number of posts returned %v", len(result.Order))
}
}
func TestSearchPostsFromUser(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
channel1 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
channel2 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
post1 := &model.Post{ChannelId: channel1.Id, Message: "sgtitlereview with space"}
post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
Client.LoginByEmail(team.Name, user2.Email, "pwd")
Client.Must(Client.JoinChannel(channel1.Id))
Client.Must(Client.JoinChannel(channel2.Id))
post2 := &model.Post{ChannelId: channel2.Id, Message: "sgtitlereview\n with return"}
post2 = Client.Must(Client.CreatePost(post2)).Data.(*model.Post)
if result := Client.Must(Client.SearchPosts("from: " + user1.Username)).Data.(*model.PostList); len(result.Order) != 1 {
t.Fatalf("wrong number of posts returned %v", len(result.Order))
}
// note that this includes the "User2 has joined the channel" system messages
if result := Client.Must(Client.SearchPosts("from: " + user2.Username)).Data.(*model.PostList); len(result.Order) != 3 {
t.Fatalf("wrong number of posts returned %v", len(result.Order))
}
if result := Client.Must(Client.SearchPosts("from: " + user2.Username + " sgtitlereview")).Data.(*model.PostList); len(result.Order) != 1 {
t.Fatalf("wrong number of posts returned %v", len(result.Order))
}
if result := Client.Must(Client.SearchPosts("from: " + user2.Username + " in:" + channel1.Name)).Data.(*model.PostList); len(result.Order) != 1 {
t.Fatalf("wrong number of posts returned %v", len(result.Order))
}
}
func TestGetPostsCache(t *testing.T) { func TestGetPostsCache(t *testing.T) {
Setup() Setup()

130
model/search_params.go Обычный файл
Просмотреть файл

@@ -0,0 +1,130 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package model
import (
"strings"
)
type SearchParams struct {
Terms string
IsHashtag bool
InChannel string
FromUser string
}
var searchFlags = [...]string{"from", "channel", "in"}
func splitWords(text string) []string {
words := []string{}
for _, word := range strings.Fields(text) {
word = puncStart.ReplaceAllString(word, "")
word = puncEnd.ReplaceAllString(word, "")
if len(word) != 0 {
words = append(words, word)
}
}
return words
}
func parseSearchFlags(input []string) ([]string, map[string]string) {
words := []string{}
flags := make(map[string]string)
skipNextWord := false
for i, word := range input {
if skipNextWord {
skipNextWord = false
continue
}
isFlag := false
if colon := strings.Index(word, ":"); colon != -1 {
flag := word[:colon]
value := word[colon+1:]
for _, searchFlag := range searchFlags {
// check for case insensitive equality
if strings.EqualFold(flag, searchFlag) {
if value != "" {
flags[searchFlag] = value
isFlag = true
} else if i < len(input)-1 {
flags[searchFlag] = input[i+1]
skipNextWord = true
isFlag = true
}
if isFlag {
break
}
}
}
}
if !isFlag {
words = append(words, word)
}
}
return words, flags
}
func ParseSearchParams(text string) (*SearchParams, *SearchParams) {
words, flags := parseSearchFlags(splitWords(text))
hashtagTerms := []string{}
plainTerms := []string{}
for _, word := range words {
if validHashtag.MatchString(word) {
hashtagTerms = append(hashtagTerms, word)
} else {
plainTerms = append(plainTerms, word)
}
}
inChannel := flags["channel"]
if inChannel == "" {
inChannel = flags["in"]
}
fromUser := flags["from"]
var plainParams *SearchParams
if len(plainTerms) > 0 {
plainParams = &SearchParams{
Terms: strings.Join(plainTerms, " "),
IsHashtag: false,
InChannel: inChannel,
FromUser: fromUser,
}
}
var hashtagParams *SearchParams
if len(hashtagTerms) > 0 {
hashtagParams = &SearchParams{
Terms: strings.Join(hashtagTerms, " "),
IsHashtag: true,
InChannel: inChannel,
FromUser: fromUser,
}
}
// special case for when no terms are specified but we still have a filter
if plainParams == nil && hashtagParams == nil && (inChannel != "" || fromUser != "") {
plainParams = &SearchParams{
Terms: "",
IsHashtag: false,
InChannel: inChannel,
FromUser: fromUser,
}
}
return plainParams, hashtagParams
}

70
model/search_params_test.go Обычный файл
Просмотреть файл

@@ -0,0 +1,70 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package model
import (
"testing"
)
func TestParseSearchFlags(t *testing.T) {
if words, flags := parseSearchFlags(splitWords("")); len(words) != 0 {
t.Fatal("got words from empty input")
} else if len(flags) != 0 {
t.Fatal("got flags from empty input")
}
if words, flags := parseSearchFlags(splitWords("word")); len(words) != 1 || words[0] != "word" {
t.Fatalf("got incorrect words %v", words)
} else if len(flags) != 0 {
t.Fatalf("got incorrect flags %v", flags)
}
if words, flags := parseSearchFlags(splitWords("apple banana cherry")); len(words) != 3 || words[0] != "apple" || words[1] != "banana" || words[2] != "cherry" {
t.Fatalf("got incorrect words %v", words)
} else if len(flags) != 0 {
t.Fatalf("got incorrect flags %v", flags)
}
if words, flags := parseSearchFlags(splitWords("apple banana from:chan")); len(words) != 2 || words[0] != "apple" || words[1] != "banana" {
t.Fatalf("got incorrect words %v", words)
} else if len(flags) != 1 || flags["from"] != "chan" {
t.Fatalf("got incorrect flags %v", flags)
}
if words, flags := parseSearchFlags(splitWords("apple banana from: chan")); len(words) != 2 || words[0] != "apple" || words[1] != "banana" {
t.Fatalf("got incorrect words %v", words)
} else if len(flags) != 1 || flags["from"] != "chan" {
t.Fatalf("got incorrect flags %v", flags)
}
if words, flags := parseSearchFlags(splitWords("apple banana in: chan")); len(words) != 2 || words[0] != "apple" || words[1] != "banana" {
t.Fatalf("got incorrect words %v", words)
} else if len(flags) != 1 || flags["in"] != "chan" {
t.Fatalf("got incorrect flags %v", flags)
}
if words, flags := parseSearchFlags(splitWords("apple banana channel:chan")); len(words) != 2 || words[0] != "apple" || words[1] != "banana" {
t.Fatalf("got incorrect words %v", words)
} else if len(flags) != 1 || flags["channel"] != "chan" {
t.Fatalf("got incorrect flags %v", flags)
}
if words, flags := parseSearchFlags(splitWords("fruit: cherry")); len(words) != 2 || words[0] != "fruit:" || words[1] != "cherry" {
t.Fatalf("got incorrect words %v", words)
} else if len(flags) != 0 {
t.Fatalf("got incorrect flags %v", flags)
}
if words, flags := parseSearchFlags(splitWords("channel:")); len(words) != 1 || words[0] != "channel:" {
t.Fatalf("got incorrect words %v", words)
} else if len(flags) != 0 {
t.Fatalf("got incorrect flags %v", flags)
}
if words, flags := parseSearchFlags(splitWords("channel: first in: second from:")); len(words) != 1 || words[0] != "from:" {
t.Fatalf("got incorrect words %v", words)
} else if len(flags) != 2 || flags["channel"] != "first" || flags["in"] != "second" {
t.Fatalf("got incorrect flags %v", flags)
}
}

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

@@ -242,10 +242,10 @@ func Etag(parts ...interface{}) string {
var validHashtag = regexp.MustCompile(`^(#[A-Za-z]+[A-Za-z0-9_\-]*[A-Za-z0-9])$`) var validHashtag = regexp.MustCompile(`^(#[A-Za-z]+[A-Za-z0-9_\-]*[A-Za-z0-9])$`)
var puncStart = regexp.MustCompile(`^[.,()&$!\[\]{}"':;\\]+`) var puncStart = regexp.MustCompile(`^[.,()&$!\[\]{}"':;\\]+`)
var puncEnd = regexp.MustCompile(`[.,()&$#!\[\]{}"':;\\]+$`) var puncEnd = regexp.MustCompile(`[.,()&$#!\[\]{}"';\\]+$`)
func ParseHashtags(text string) (string, string) { func ParseHashtags(text string) (string, string) {
words := strings.Split(strings.Replace(text, "\n", " ", -1), " ") words := strings.Fields(text)
hashtagString := "" hashtagString := ""
plainString := "" plainString := ""

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

@@ -407,15 +407,23 @@ var specialSearchChar = []string{
"@", "@",
} }
func (s SqlPostStore) Search(teamId string, userId string, terms string, isHashtagSearch bool) StoreChannel { func (s SqlPostStore) Search(teamId string, userId string, params *model.SearchParams) StoreChannel {
storeChannel := make(StoreChannel) storeChannel := make(StoreChannel)
go func() { go func() {
result := StoreResult{} result := StoreResult{}
termMap := map[string]bool{} termMap := map[string]bool{}
terms := params.Terms
if terms == "" && params.InChannel == "" && params.FromUser == "" {
result.Data = []*model.Post{}
storeChannel <- result
return
}
searchType := "Message" searchType := "Message"
if isHashtagSearch { if params.IsHashtag {
searchType = "Hashtags" searchType = "Hashtags"
for _, term := range strings.Split(terms, " ") { for _, term := range strings.Split(terms, " ") {
termMap[term] = true termMap[term] = true
@@ -430,63 +438,85 @@ func (s SqlPostStore) Search(teamId string, userId string, terms string, isHasht
var posts []*model.Post var posts []*model.Post
if utils.Cfg.SqlSettings.DriverName == model.DATABASE_DRIVER_POSTGRES { if utils.Cfg.SqlSettings.DriverName == model.DATABASE_DRIVER_POSTGRES {
// Parse text for wildcards
if wildcard, err := regexp.Compile("\\*($| )"); err == nil {
terms = wildcard.ReplaceAllLiteralString(terms, ":* ")
}
}
searchQuery := `
SELECT
*
FROM
Posts
WHERE
DeleteAt = 0
POST_FILTER
AND ChannelId IN (
SELECT
Id
FROM
Channels,
ChannelMembers
WHERE
Id = ChannelId
AND TeamId = :TeamId
AND UserId = :UserId
AND DeleteAt = 0
CHANNEL_FILTER)
SEARCH_CLAUSE
ORDER BY CreateAt DESC
LIMIT 100`
if params.InChannel != "" {
searchQuery = strings.Replace(searchQuery, "CHANNEL_FILTER", "AND Name = :InChannel", 1)
} else {
searchQuery = strings.Replace(searchQuery, "CHANNEL_FILTER", "", 1)
}
if params.FromUser != "" {
searchQuery = strings.Replace(searchQuery, "POST_FILTER", `
AND UserId IN (
SELECT
Id
FROM
Users
WHERE
TeamId = :TeamId
AND Username = :FromUser)`, 1)
} else {
searchQuery = strings.Replace(searchQuery, "POST_FILTER", "", 1)
}
if terms == "" {
// we've already confirmed that we have a channel or user to search for
searchQuery = strings.Replace(searchQuery, "SEARCH_CLAUSE", "", 1)
} else if utils.Cfg.SqlSettings.DriverName == model.DATABASE_DRIVER_POSTGRES {
// Parse text for wildcards // Parse text for wildcards
if wildcard, err := regexp.Compile("\\*($| )"); err == nil { if wildcard, err := regexp.Compile("\\*($| )"); err == nil {
terms = wildcard.ReplaceAllLiteralString(terms, ":* ") terms = wildcard.ReplaceAllLiteralString(terms, ":* ")
} }
searchQuery := fmt.Sprintf(`SELECT
*
FROM
Posts
WHERE
DeleteAt = 0
AND ChannelId IN (SELECT
Id
FROM
Channels,
ChannelMembers
WHERE
Id = ChannelId AND TeamId = $1
AND UserId = $2
AND DeleteAt = 0)
AND %s @@ to_tsquery($3)
ORDER BY CreateAt DESC
LIMIT 100`, searchType)
terms = strings.Join(strings.Fields(terms), " | ") terms = strings.Join(strings.Fields(terms), " | ")
_, err := s.GetReplica().Select(&posts, searchQuery, teamId, userId, terms) searchClause := fmt.Sprintf("AND %s @@ to_tsquery(:Terms)", searchType)
if err != nil { searchQuery = strings.Replace(searchQuery, "SEARCH_CLAUSE", searchClause, 1)
result.Err = model.NewAppError("SqlPostStore.Search", "We encounted an error while searching for posts", "teamId="+teamId+", err="+err.Error())
}
} else if utils.Cfg.SqlSettings.DriverName == model.DATABASE_DRIVER_MYSQL { } else if utils.Cfg.SqlSettings.DriverName == model.DATABASE_DRIVER_MYSQL {
searchQuery := fmt.Sprintf(`SELECT searchClause := fmt.Sprintf("AND MATCH (%s) AGAINST (:Terms IN BOOLEAN MODE)", searchType)
* searchQuery = strings.Replace(searchQuery, "SEARCH_CLAUSE", searchClause, 1)
FROM }
Posts
WHERE
DeleteAt = 0
AND ChannelId IN (SELECT
Id
FROM
Channels,
ChannelMembers
WHERE
Id = ChannelId AND TeamId = ?
AND UserId = ?
AND DeleteAt = 0)
AND MATCH (%s) AGAINST (? IN BOOLEAN MODE)
ORDER BY CreateAt DESC
LIMIT 100`, searchType)
_, err := s.GetReplica().Select(&posts, searchQuery, teamId, userId, terms) queryParams := map[string]interface{}{
"TeamId": teamId,
"UserId": userId,
"Terms": terms,
"InChannel": params.InChannel,
"FromUser": params.FromUser,
}
_, err := s.GetReplica().Select(&posts, searchQuery, queryParams)
if err != nil { if err != nil {
result.Err = model.NewAppError("SqlPostStore.Search", "We encounted an error while searching for posts", "teamId="+teamId+", err="+err.Error()) result.Err = model.NewAppError("SqlPostStore.Search", "We encounted an error while searching for posts", "teamId="+teamId+", err="+err.Error())
}
} }
list := &model.PostList{Order: make([]string, 0, len(posts))} list := &model.PostList{Order: make([]string, 0, len(posts))}

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

@@ -525,57 +525,57 @@ func TestPostStoreSearch(t *testing.T) {
o5.Hashtags = "#secret #howdy" o5.Hashtags = "#secret #howdy"
o5 = (<-store.Post().Save(o5)).Data.(*model.Post) o5 = (<-store.Post().Save(o5)).Data.(*model.Post)
r1 := (<-store.Post().Search(teamId, userId, "corey", false)).Data.(*model.PostList) r1 := (<-store.Post().Search(teamId, userId, &model.SearchParams{Terms: "corey", IsHashtag: false})).Data.(*model.PostList)
if len(r1.Order) != 1 && r1.Order[0] != o1.Id { if len(r1.Order) != 1 && r1.Order[0] != o1.Id {
t.Fatal("returned wrong search result") t.Fatal("returned wrong search result")
} }
r3 := (<-store.Post().Search(teamId, userId, "new", false)).Data.(*model.PostList) r3 := (<-store.Post().Search(teamId, userId, &model.SearchParams{Terms: "new", IsHashtag: false})).Data.(*model.PostList)
if len(r3.Order) != 2 && r3.Order[0] != o1.Id { if len(r3.Order) != 2 && r3.Order[0] != o1.Id {
t.Fatal("returned wrong search result") t.Fatal("returned wrong search result")
} }
r4 := (<-store.Post().Search(teamId, userId, "john", false)).Data.(*model.PostList) r4 := (<-store.Post().Search(teamId, userId, &model.SearchParams{Terms: "john", IsHashtag: false})).Data.(*model.PostList)
if len(r4.Order) != 1 && r4.Order[0] != o2.Id { if len(r4.Order) != 1 && r4.Order[0] != o2.Id {
t.Fatal("returned wrong search result") t.Fatal("returned wrong search result")
} }
r5 := (<-store.Post().Search(teamId, userId, "matter*", false)).Data.(*model.PostList) r5 := (<-store.Post().Search(teamId, userId, &model.SearchParams{Terms: "matter*", IsHashtag: false})).Data.(*model.PostList)
if len(r5.Order) != 1 && r5.Order[0] != o1.Id { if len(r5.Order) != 1 && r5.Order[0] != o1.Id {
t.Fatal("returned wrong search result") t.Fatal("returned wrong search result")
} }
r6 := (<-store.Post().Search(teamId, userId, "#hashtag", true)).Data.(*model.PostList) r6 := (<-store.Post().Search(teamId, userId, &model.SearchParams{Terms: "#hashtag", IsHashtag: true})).Data.(*model.PostList)
if len(r6.Order) != 1 && r6.Order[0] != o4.Id { if len(r6.Order) != 1 && r6.Order[0] != o4.Id {
t.Fatal("returned wrong search result") t.Fatal("returned wrong search result")
} }
r7 := (<-store.Post().Search(teamId, userId, "#secret", true)).Data.(*model.PostList) r7 := (<-store.Post().Search(teamId, userId, &model.SearchParams{Terms: "#secret", IsHashtag: true})).Data.(*model.PostList)
if len(r7.Order) != 1 && r7.Order[0] != o5.Id { if len(r7.Order) != 1 && r7.Order[0] != o5.Id {
t.Fatal("returned wrong search result") t.Fatal("returned wrong search result")
} }
r8 := (<-store.Post().Search(teamId, userId, "@thisshouldmatchnothing", true)).Data.(*model.PostList) r8 := (<-store.Post().Search(teamId, userId, &model.SearchParams{Terms: "@thisshouldmatchnothing", IsHashtag: true})).Data.(*model.PostList)
if len(r8.Order) != 0 { if len(r8.Order) != 0 {
t.Fatal("returned wrong search result") t.Fatal("returned wrong search result")
} }
r9 := (<-store.Post().Search(teamId, userId, "mattermost jersey", false)).Data.(*model.PostList) r9 := (<-store.Post().Search(teamId, userId, &model.SearchParams{Terms: "mattermost jersey", IsHashtag: false})).Data.(*model.PostList)
if len(r9.Order) != 2 { if len(r9.Order) != 2 {
t.Fatal("returned wrong search result") t.Fatal("returned wrong search result")
} }
r10 := (<-store.Post().Search(teamId, userId, "matter* jer*", false)).Data.(*model.PostList) r10 := (<-store.Post().Search(teamId, userId, &model.SearchParams{Terms: "matter* jer*", IsHashtag: false})).Data.(*model.PostList)
if len(r10.Order) != 2 { if len(r10.Order) != 2 {
t.Fatal("returned wrong search result") t.Fatal("returned wrong search result")
} }
r11 := (<-store.Post().Search(teamId, userId, "message blargh", false)).Data.(*model.PostList) r11 := (<-store.Post().Search(teamId, userId, &model.SearchParams{Terms: "message blargh", IsHashtag: false})).Data.(*model.PostList)
if len(r11.Order) != 1 { if len(r11.Order) != 1 {
t.Fatal("returned wrong search result") t.Fatal("returned wrong search result")
} }
r12 := (<-store.Post().Search(teamId, userId, "blargh>", false)).Data.(*model.PostList) r12 := (<-store.Post().Search(teamId, userId, &model.SearchParams{Terms: "blargh>", IsHashtag: false})).Data.(*model.PostList)
if len(r12.Order) != 1 { if len(r12.Order) != 1 {
t.Fatal("returned wrong search result") t.Fatal("returned wrong search result")
} }

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

@@ -84,7 +84,7 @@ type PostStore interface {
GetPosts(channelId string, offset int, limit int) StoreChannel GetPosts(channelId string, offset int, limit int) StoreChannel
GetPostsSince(channelId string, time int64) StoreChannel GetPostsSince(channelId string, time int64) StoreChannel
GetEtag(channelId string) StoreChannel GetEtag(channelId string) StoreChannel
Search(teamId string, userId string, terms string, isHashtagSearch bool) StoreChannel Search(teamId string, userId string, params *model.SearchParams) StoreChannel
GetForExport(channelId string) StoreChannel GetForExport(channelId string) StoreChannel
} }