Added from:, in:, and channel: search modifiers
Этот коммит содержится в:
10
api/post.go
10
api/post.go
@@ -680,16 +680,16 @@ func searchPosts(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
hashtagTerms, plainTerms := model.ParseHashtags(terms)
|
||||
plainSearchParams, hashtagSearchParams := model.ParseSearchParams(terms)
|
||||
|
||||
var hchan store.StoreChannel
|
||||
if len(hashtagTerms) != 0 {
|
||||
hchan = Srv.Store.Post().Search(c.Session.TeamId, c.Session.UserId, hashtagTerms, true)
|
||||
if hashtagSearchParams != nil {
|
||||
hchan = Srv.Store.Post().Search(c.Session.TeamId, c.Session.UserId, hashtagSearchParams)
|
||||
}
|
||||
|
||||
var pchan store.StoreChannel
|
||||
if len(plainTerms) != 0 {
|
||||
pchan = Srv.Store.Post().Search(c.Session.TeamId, c.Session.UserId, terms, false)
|
||||
if plainSearchParams != nil {
|
||||
pchan = Srv.Store.Post().Search(c.Session.TeamId, c.Session.UserId, plainSearchParams)
|
||||
}
|
||||
|
||||
mainList := &model.PostList{}
|
||||
|
||||
122
api/post_test.go
122
api/post_test.go
@@ -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) {
|
||||
Setup()
|
||||
|
||||
|
||||
130
model/search_params.go
Обычный файл
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
Обычный файл
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 puncStart = regexp.MustCompile(`^[.,()&$!\[\]{}"':;\\]+`)
|
||||
var puncEnd = regexp.MustCompile(`[.,()&$#!\[\]{}"':;\\]+$`)
|
||||
var puncEnd = regexp.MustCompile(`[.,()&$#!\[\]{}"';\\]+$`)
|
||||
|
||||
func ParseHashtags(text string) (string, string) {
|
||||
words := strings.Split(strings.Replace(text, "\n", " ", -1), " ")
|
||||
words := strings.Fields(text)
|
||||
|
||||
hashtagString := ""
|
||||
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)
|
||||
|
||||
go func() {
|
||||
result := StoreResult{}
|
||||
|
||||
termMap := map[string]bool{}
|
||||
terms := params.Terms
|
||||
|
||||
if terms == "" && params.InChannel == "" && params.FromUser == "" {
|
||||
result.Data = []*model.Post{}
|
||||
storeChannel <- result
|
||||
return
|
||||
}
|
||||
|
||||
searchType := "Message"
|
||||
if isHashtagSearch {
|
||||
if params.IsHashtag {
|
||||
searchType = "Hashtags"
|
||||
for _, term := range strings.Split(terms, " ") {
|
||||
termMap[term] = true
|
||||
@@ -430,63 +438,85 @@ func (s SqlPostStore) Search(teamId string, userId string, terms string, isHasht
|
||||
var posts []*model.Post
|
||||
|
||||
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
|
||||
if wildcard, err := regexp.Compile("\\*($| )"); err == nil {
|
||||
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), " | ")
|
||||
|
||||
_, err := s.GetReplica().Select(&posts, searchQuery, teamId, userId, terms)
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlPostStore.Search", "We encounted an error while searching for posts", "teamId="+teamId+", err="+err.Error())
|
||||
|
||||
}
|
||||
searchClause := fmt.Sprintf("AND %s @@ to_tsquery(:Terms)", searchType)
|
||||
searchQuery = strings.Replace(searchQuery, "SEARCH_CLAUSE", searchClause, 1)
|
||||
} else if utils.Cfg.SqlSettings.DriverName == model.DATABASE_DRIVER_MYSQL {
|
||||
searchQuery := fmt.Sprintf(`SELECT
|
||||
*
|
||||
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)
|
||||
searchClause := fmt.Sprintf("AND MATCH (%s) AGAINST (:Terms IN BOOLEAN MODE)", searchType)
|
||||
searchQuery = strings.Replace(searchQuery, "SEARCH_CLAUSE", searchClause, 1)
|
||||
}
|
||||
|
||||
_, err := s.GetReplica().Select(&posts, searchQuery, teamId, userId, terms)
|
||||
if err != nil {
|
||||
result.Err = model.NewAppError("SqlPostStore.Search", "We encounted an error while searching for posts", "teamId="+teamId+", err="+err.Error())
|
||||
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 {
|
||||
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))}
|
||||
|
||||
@@ -525,57 +525,57 @@ func TestPostStoreSearch(t *testing.T) {
|
||||
o5.Hashtags = "#secret #howdy"
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
t.Fatal("returned wrong search result")
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ type PostStore interface {
|
||||
GetPosts(channelId string, offset int, limit int) StoreChannel
|
||||
GetPostsSince(channelId string, time int64) 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
|
||||
}
|
||||
|
||||
|
||||
Ссылка в новой задаче
Block a user