datastar/site/routes_examples_active_sear...

73 lines
1.8 KiB
Go

package site
import (
"math"
"net/http"
"slices"
"strings"
"github.com/delaneyj/toolbelt"
"github.com/go-chi/chi/v5"
"github.com/go-faker/faker/v4"
"github.com/lithammer/fuzzysearch/fuzzy"
datastar "github.com/starfederation/datastar/sdk/go"
)
func setupExamplesActiveSearch(examplesRouter chi.Router) error {
users := make([]*ActiveSearchUser, 256)
for i := range users {
u := &ActiveSearchUser{
ID: faker.UUIDHyphenated(),
FirstName: faker.FirstName(),
LastName: faker.LastName(),
Email: faker.Email(),
}
users[i] = u
}
examplesRouter.Get("/active_search/updates", func(w http.ResponseWriter, r *http.Request) {
signals := &ActiveSearchSignals{}
if err := datastar.ReadSignals(r, signals); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
scores := map[string]float64{}
s := strings.ToLower(signals.Search)
minScore, maxScore := math.MaxFloat64, -math.MaxFloat64
for _, u := range users {
fn := strings.ToLower(u.FirstName)
ln := strings.ToLower(u.LastName)
e := strings.ToLower(u.Email)
fnd := fuzzy.LevenshteinDistance(s, fn)
lnd := fuzzy.LevenshteinDistance(s, ln)
ed := fuzzy.LevenshteinDistance(s, e)
dist := float64(fnd + lnd + ed)
scores[u.ID] = dist
minScore = min(minScore, dist)
maxScore = max(maxScore, dist)
}
for id, score := range scores {
scores[id] = toolbelt.Fit(score, minScore, maxScore, 100, 0)
}
// copy users
filteredUsers := make([]*ActiveSearchUser, len(users))
copy(filteredUsers, users)
// sort users by score
slices.SortFunc(filteredUsers, func(a, b *ActiveSearchUser) int {
return int(10000 * (scores[b.ID] - scores[a.ID]))
})
datastar.NewSSE(w, r).MergeFragmentTempl(ActiveSearchComponent(filteredUsers, scores, signals))
})
return nil
}