in internal/repo/search_common/search_repo.go [102:242]
func (sr *searchRepo) SearchContents(ctx context.Context, words []string, tagIDs [][]string, userID string, votes int, page, pageSize int, order string) (resp []*schema.SearchResult, total int64, err error) {
words = filterWords(words)
var (
b *builder.Builder
ub *builder.Builder
qfs = qFields
afs = aFields
argsQ = []interface{}{}
argsA = []interface{}{}
)
if order == "relevance" {
if len(words) > 0 {
qfs, argsQ = addRelevanceField([]string{"title", "original_text"}, words, qfs)
afs, argsA = addRelevanceField([]string{"`answer`.`original_text`"}, words, afs)
} else {
order = "newest"
}
}
b = builder.MySQL().Select(qfs...).From("`question`")
ub = builder.MySQL().Select(afs...).From("`answer`").
LeftJoin("`question`", "`question`.id = `answer`.question_id")
b.Where(builder.Lt{"`question`.`status`": entity.QuestionStatusDeleted}).
And(builder.Eq{"`question`.`show`": entity.QuestionShow})
ub.Where(builder.Lt{"`question`.`status`": entity.QuestionStatusDeleted}).
And(builder.Lt{"`answer`.`status`": entity.AnswerStatusDeleted}).
And(builder.Eq{"`question`.`show`": entity.QuestionShow})
argsQ = append(argsQ, entity.QuestionStatusDeleted, entity.QuestionShow)
argsA = append(argsA, entity.QuestionStatusDeleted, entity.AnswerStatusDeleted, entity.QuestionShow)
likeConQ := builder.NewCond()
likeConA := builder.NewCond()
for _, word := range words {
likeConQ = likeConQ.Or(builder.Like{"title", word}).
Or(builder.Like{"original_text", word})
argsQ = append(argsQ, "%"+word+"%")
argsQ = append(argsQ, "%"+word+"%")
likeConA = likeConA.Or(builder.Like{"`answer`.original_text", word})
argsA = append(argsA, "%"+word+"%")
}
b.Where(likeConQ)
ub.Where(likeConA)
// check tag
for ti, tagID := range tagIDs {
ast := "tag_rel" + strconv.Itoa(ti)
b.Join("INNER", "tag_rel as "+ast, "question.id = "+ast+".object_id").
And(builder.Eq{
ast + ".status": entity.TagRelStatusAvailable,
}).
And(builder.In(ast+".tag_id", tagID))
ub.Join("INNER", "tag_rel as "+ast, "question_id = "+ast+".object_id").
And(builder.Eq{
ast + ".status": entity.TagRelStatusAvailable,
}).
And(builder.In(ast+".tag_id", tagID))
argsQ = append(argsQ, entity.TagRelStatusAvailable)
argsA = append(argsA, entity.TagRelStatusAvailable)
for _, t := range tagID {
argsQ = append(argsQ, t)
argsA = append(argsA, t)
}
}
// check user
if userID != "" {
b.Where(builder.Eq{"question.user_id": userID})
ub.Where(builder.Eq{"answer.user_id": userID})
argsQ = append(argsQ, userID)
argsA = append(argsA, userID)
}
// check vote
if votes == 0 {
b.Where(builder.Eq{"question.vote_count": votes})
ub.Where(builder.Eq{"answer.vote_count": votes})
argsQ = append(argsQ, votes)
argsA = append(argsA, votes)
} else if votes > 0 {
b.Where(builder.Gte{"question.vote_count": votes})
ub.Where(builder.Gte{"answer.vote_count": votes})
argsQ = append(argsQ, votes)
argsA = append(argsA, votes)
}
//b = b.Union("all", ub)
ubSQL, _, err := ub.ToSQL()
if err != nil {
return
}
bSQL, _, err := b.ToSQL()
if err != nil {
return
}
sql := fmt.Sprintf("(%s UNION ALL %s)", bSQL, ubSQL)
countSQL, _, err := builder.MySQL().Select("count(*) total").From(sql, "c").ToSQL()
if err != nil {
return
}
startNum := (page - 1) * pageSize
querySQL, _, err := builder.MySQL().Select("*").From(sql, "t").OrderBy(sr.parseOrder(ctx, order)).Limit(pageSize, startNum).ToSQL()
if err != nil {
return
}
queryArgs := []interface{}{}
countArgs := []interface{}{}
queryArgs = append(queryArgs, querySQL)
queryArgs = append(queryArgs, argsQ...)
queryArgs = append(queryArgs, argsA...)
countArgs = append(countArgs, countSQL)
countArgs = append(countArgs, argsQ...)
countArgs = append(countArgs, argsA...)
res, err := sr.data.DB.Context(ctx).Query(queryArgs...)
if err != nil {
return
}
tr, err := sr.data.DB.Context(ctx).Query(countArgs...)
if len(tr) != 0 {
total = converter.StringToInt64(string(tr[0]["total"]))
}
if err != nil {
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
return
} else {
resp, err = sr.parseResult(ctx, res, words)
return
}
}