internal/domain/sticker_search.go
Rama main · réplica de lectura del repositorio original.
package domain
import (
"sort"
"strings"
)
// SearchStickerSets returns a stable public catalog projection. It never
// mutates the shared catalog or includes archived, deleted, or system sets.
func SearchStickerSets(sets []StickerSet, kind StickerSetKind, query string) []StickerSet {
tokens := strings.Fields(stickerSearchText(query))
result := make([]StickerSet, 0)
for _, set := range sets {
if set.ID == 0 || set.Deleted || set.Archived || set.Kind != kind {
continue
}
if stickerSearchMatches(stickerSearchText(set.Title+" "+set.ShortName), tokens) {
result = append(result, set)
}
}
sort.Slice(result, func(i, j int) bool {
if result[i].SortOrder != result[j].SortOrder {
return result[i].SortOrder < result[j].SortOrder
}
return result[i].ID < result[j].ID
})
return result
}
// SearchStickerDocuments searches metadata before materializing only the
// requested page of document payloads. Keywords remain specific to each item.
func SearchStickerDocuments(sets []StickerSet, kind StickerSetKind, query, emojis string, offset, limit int) []int64 {
result := make([]int64, 0, limit)
if limit == 0 {
return result
}
tokens := strings.Fields(stickerSearchText(query))
emojiTokens := strings.Fields(stickerSearchText(emojis))
seen := make(map[int64]bool)
matched := 0
for _, set := range SearchStickerSets(sets, kind, "") {
words := make(map[int64]string)
emojiByID := make(map[int64]string)
for _, pack := range set.Packs {
for _, id := range pack.DocumentIDs {
emojiByID[id] += " " + stickerSearchText(pack.Emoticon)
}
}
for _, entry := range set.Keywords {
words[entry.DocumentID] += " " + stickerSearchText(strings.Join(entry.Keywords, " "))
}
title := stickerSearchText(set.Title + " " + set.ShortName)
for _, id := range set.DocumentIDs {
if id == 0 || seen[id] {
continue
}
text := title + " " + words[id] + " " + emojiByID[id]
if !stickerSearchMatches(text, tokens) {
continue
}
emojiMatches := len(emojiTokens) == 0
for _, emoji := range emojiTokens {
for _, candidate := range strings.Fields(emojiByID[id]) {
if candidate == emoji {
emojiMatches = true
}
}
}
if !emojiMatches {
continue
}
seen[id] = true
if matched >= offset {
result = append(result, id)
}
matched++
if len(result) == limit {
return result
}
}
}
return result
}
func stickerSearchText(value string) string {
return strings.ToLower(strings.NewReplacer("\ufe0f", "", "\ufe0e", "").Replace(value))
}
func stickerSearchMatches(text string, tokens []string) bool {
for _, token := range tokens {
if !strings.Contains(text, token) {
return false
}
}
return true
}