feat: search all fields (#622)
* ✨ feat(search): search all feature - add Description field to Gist struct and index it - extend SearchGistMetadata with Description and Content - update Bleve and Meilisearch to index and search Description - modify ParseSearchQueryStr to parse description: and content: keywords - update templates and i18n for new search options * Fix test * Set content by default Signed-off-by: Thomas Miceli <tho.miceli@gmail.com> * Config to define default searchable fields Signed-off-by: Thomas Miceli <tho.miceli@gmail.com> --------- Signed-off-by: Thomas Miceli <tho.miceli@gmail.com> Co-authored-by: Thomas Miceli <tho.miceli@gmail.com>
This commit is contained in:
committed by
GitHub
parent
5ad01a3304
commit
279da52899
@@ -164,6 +164,18 @@ func AllGists(ctx *context.Context) error {
|
||||
return ctx.Html("all.html")
|
||||
}
|
||||
|
||||
// Search handles the search page for gists.
|
||||
//
|
||||
// It takes a query parameter "q" which is a search query in the format:
|
||||
// "user:username title:title description:description filename:filename language:language topic:topic"
|
||||
//
|
||||
// It also takes a page parameter "page" which is the page number to display.
|
||||
//
|
||||
// It returns an error if the search query is invalid or if the page number is invalid.
|
||||
//
|
||||
// It returns the search results as a list of rendered gists, along with the total number of results, the languages found, and the search query.
|
||||
//
|
||||
// The search results are paginated, with 10 results per page.
|
||||
func Search(ctx *context.Context) error {
|
||||
var err error
|
||||
|
||||
@@ -171,7 +183,7 @@ func Search(ctx *context.Context) error {
|
||||
Query: ctx.QueryParam("q"),
|
||||
}
|
||||
|
||||
content, meta := handlers.ParseSearchQueryStr(ctx.QueryParam("q"))
|
||||
metadata := handlers.ParseSearchQueryStr(ctx.QueryParam("q"))
|
||||
pageInt := handlers.GetPage(ctx)
|
||||
|
||||
var currentUserId uint
|
||||
@@ -182,14 +194,18 @@ func Search(ctx *context.Context) error {
|
||||
currentUserId = 0
|
||||
}
|
||||
|
||||
gistsIds, nbHits, langs, err := index.SearchGists(content, index.SearchGistMetadata{
|
||||
Username: meta["user"],
|
||||
Title: meta["title"],
|
||||
Filename: meta["filename"],
|
||||
Extension: meta["extension"],
|
||||
Language: meta["language"],
|
||||
Topic: meta["topic"],
|
||||
All: meta["all"],
|
||||
// Search gists in the index and fetch the gists IDs from the database
|
||||
gistsIds, nbHits, langs, err := index.SearchGists(index.SearchGistMetadata{
|
||||
Username: metadata["user"],
|
||||
Title: metadata["title"],
|
||||
Description: metadata["description"],
|
||||
Filename: metadata["filename"],
|
||||
Extension: metadata["extension"],
|
||||
Language: metadata["language"],
|
||||
Topic: metadata["topic"],
|
||||
Content: metadata["content"],
|
||||
All: metadata["all"],
|
||||
Default: metadata["default"],
|
||||
}, currentUserId, pageInt)
|
||||
if err != nil {
|
||||
return ctx.ErrorRes(500, "Error searching gists", err)
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/gorilla/schema"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/thomiceli/opengist/internal/web/context"
|
||||
)
|
||||
|
||||
@@ -119,10 +119,16 @@ func Paginate[T any](ctx *context.Context, data []*T, pageInt int, perPage int,
|
||||
return nil
|
||||
}
|
||||
|
||||
func ParseSearchQueryStr(query string) (string, map[string]string) {
|
||||
// ParseSearchQueryStr parses a search query string and returns a map of metadata.
|
||||
// The query string is split into words and each word is checked if it contains a colon (:).
|
||||
// If a word contains a colon, it is split into a key-value pair and added to the metadata map.
|
||||
// If a word does not contain a colon, it is added to an "all" key in the metadata map.
|
||||
// The "all" key is used to search all fields in the index.
|
||||
// The function returns the metadata map.
|
||||
func ParseSearchQueryStr(query string) map[string]string {
|
||||
words := strings.Fields(query)
|
||||
metadata := make(map[string]string)
|
||||
var contentBuilder strings.Builder
|
||||
var allFieldsBuilder strings.Builder
|
||||
|
||||
for _, word := range words {
|
||||
if strings.Contains(word, ":") {
|
||||
@@ -133,10 +139,18 @@ func ParseSearchQueryStr(query string) (string, map[string]string) {
|
||||
metadata[key] = value
|
||||
}
|
||||
} else {
|
||||
contentBuilder.WriteString(word + " ")
|
||||
// Add to content search by default
|
||||
allFieldsBuilder.WriteString(word + " ")
|
||||
}
|
||||
}
|
||||
|
||||
content := strings.TrimSpace(contentBuilder.String())
|
||||
return content, metadata
|
||||
// Set the default search field
|
||||
allContent := strings.TrimSpace(allFieldsBuilder.String())
|
||||
if allContent != "" {
|
||||
metadata["default"] = allContent
|
||||
}
|
||||
|
||||
log.Debug().Msgf("Metadata: %v", metadata)
|
||||
|
||||
return metadata
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user