diff options
-rw-r--r-- | CHANGELOG.md | 26 | ||||
-rw-r--r-- | frontend/assets.go | 2 | ||||
-rw-r--r-- | internal/components/data.go | 10 | ||||
-rw-r--r-- | internal/components/results.templ | 7 | ||||
-rw-r--r-- | internal/config/config.go | 2 | ||||
-rw-r--r-- | internal/index/search.go | 9 | ||||
-rw-r--r-- | internal/pagination/pagination.go | 31 | ||||
-rw-r--r-- | internal/server/mux.go | 51 | ||||
-rw-r--r-- | nix/package.nix | 2 |
9 files changed, 104 insertions, 36 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 59f2241..759050a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,33 @@ # Changelog -## [v0.1.13](https://git.alanpearce.eu/searchix/diff/?id=v0.1.12&id2=e1787bf0b6dbac3a1601559d2f00ebc4b2df0f29) (2024-12-30) +## [v0.1.15](https://git.alanpearce.eu/searchix/diff/?id=v0.1.14&id2=920764211064521930441b96ed914034302a7470) (2025-01-05) ### Features +- offer to show all results on one page (if < 10000) + ([9207642](https://git.alanpearce.eu/searchix/commit/?id=920764211064521930441b96ed914034302a7470)) + +### Fixes + +- **dev:** overwrite previous asset hash on change + ([d289e54](https://git.alanpearce.eu/searchix/commit/?id=d289e54af28de6b21cbe49cebc262c4e3ca9f6d2)) + +### [v0.1.14](https://git.alanpearce.eu/searchix/diff/?id=v0.1.13&id2=v0.1.14) (2025-01-02) + +#### Features + +- show scores in results table in dev mode + ([58643f3](https://git.alanpearce.eu/searchix/commit/?id=58643f38bdd62dc538a03865b1f81eb77d957779)) + +#### Fixes + +- boost non-stemmed matches over stemmed matches + ([797c6e2](https://git.alanpearce.eu/searchix/commit/?id=797c6e27e18f6c47ceb4266d747a05064365c32d)) + +### [v0.1.13](https://git.alanpearce.eu/searchix/diff/?id=v0.1.12&id2=v0.1.13) (2024-12-30) + +#### Features + - increase results per page ([e1787bf](https://git.alanpearce.eu/searchix/commit/?id=e1787bf0b6dbac3a1601559d2f00ebc4b2df0f29)) - de-rank packages on 'all' search diff --git a/frontend/assets.go b/frontend/assets.go index 7a90d80..b1c2efa 100644 --- a/frontend/assets.go +++ b/frontend/assets.go @@ -86,10 +86,12 @@ func hashStyles() error { } func Rehash() (err error) { + Assets.Scripts = []*Asset{} err = hashScripts() if err != nil { return err } + Assets.Stylesheets = []*Asset{} err = hashStyles() if err != nil { return err diff --git a/internal/components/data.go b/internal/components/data.go index 3625017..862429e 100644 --- a/internal/components/data.go +++ b/internal/components/data.go @@ -21,9 +21,9 @@ type TemplateData struct { type ResultData struct { TemplateData - Query string - ResultsPerPage int - Results *search.Result - Prev string - Next string + Query string + Results *search.Result + Prev string + Next string + All string } diff --git a/internal/components/results.templ b/internal/components/results.templ index 226b71e..fee211c 100644 --- a/internal/components/results.templ +++ b/internal/components/results.templ @@ -1,9 +1,9 @@ package components import ( - "strconv" - "go.alanpearce.eu/searchix/internal/nix" "go.alanpearce.eu/searchix/internal/config" + "go.alanpearce.eu/searchix/internal/nix" + "strconv" ) func convertMatch[I nix.Importable](m nix.Importable) *I { @@ -37,6 +37,9 @@ templ Results(r ResultData) { } </nav> <span role="status">{ strconv.FormatUint(r.Results.Total, 10) } results</span> + if r.Next != r.Prev && r.Results.Total < config.MaxResultsShowAll { + <a href={ templ.SafeURL(r.All) }>Show All</a> + } </footer> } else { <span role="status">Nothing found</span> diff --git a/internal/config/config.go b/internal/config/config.go index 33ce1da..b2af53c 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -14,6 +14,8 @@ import ( var Version string var DevMode bool +const MaxResultsShowAll = 10_000 + type URL struct { *url.URL } diff --git a/internal/index/search.go b/internal/index/search.go index d576d5a..9d77488 100644 --- a/internal/index/search.go +++ b/internal/index/search.go @@ -15,7 +15,7 @@ import ( "github.com/pkg/errors" ) -const ResultsPerPage = 100 +const DefaultPageSize = 100 type DocumentMatch struct { *search.DocumentMatch @@ -134,7 +134,8 @@ func (index *ReadIndex) Search( ctx context.Context, source *config.Source, keyword string, - from uint64, + from int, + pageSize int, ) (*Result, error) { query := bleve.NewBooleanQuery() @@ -175,10 +176,10 @@ func (index *ReadIndex) Search( search := bleve.NewSearchRequest(query) search.Explain = config.DevMode - search.Size = ResultsPerPage + search.Size = pageSize if from != 0 { - search.From = int(from) + search.From = from } return index.search(ctx, search) diff --git a/internal/pagination/pagination.go b/internal/pagination/pagination.go new file mode 100644 index 0000000..4d41587 --- /dev/null +++ b/internal/pagination/pagination.go @@ -0,0 +1,31 @@ +package pagination + +type Pagination struct { + total uint64 + + From int + + Size, + Current, + Prev, + Next int + + Needed bool +} + +func New(page int, pageSize int) *Pagination { + return &Pagination{ + Current: page, + From: (page - 1) * pageSize, + Size: pageSize, + } +} + +func (p *Pagination) SetResults(total uint64) { + p.total = total + p.Needed = p.total > uint64(p.Size) + if uint64(p.Current*p.Size) <= p.total { + p.Next = p.Current + 1 + p.Prev = p.Current - 1 + } +} diff --git a/internal/server/mux.go b/internal/server/mux.go index 66da7b5..83fde10 100644 --- a/internal/server/mux.go +++ b/internal/server/mux.go @@ -16,6 +16,7 @@ import ( "go.alanpearce.eu/searchix/internal/config" search "go.alanpearce.eu/searchix/internal/index" "go.alanpearce.eu/searchix/internal/opensearch" + "go.alanpearce.eu/searchix/internal/pagination" "go.alanpearce.eu/x/log" sentryhttp "github.com/getsentry/sentry-go/http" @@ -104,17 +105,23 @@ func NewMux( if r.URL.Query().Has("query") { qs := r.URL.Query().Get("query") - pg := r.URL.Query().Get("page") - var page uint64 = 1 - if pg != "" { - page, err = strconv.ParseUint(pg, 10, 64) - if err != nil || page == 0 { + + var pageSize int = search.DefaultPageSize + var pageNumber = 1 + if pg := r.URL.Query().Get("page"); pg != "" { + pageNumber, err = strconv.Atoi(pg) + if err != nil || pageNumber > math.MaxInt { errorHandler(w, r, "Bad query string", http.StatusBadRequest) return } + if pageNumber == 0 { + pageNumber = 1 + pageSize = math.MaxInt + } } - results, err := index.Search(ctx, source, qs, (page-1)*search.ResultsPerPage) + page := pagination.New(pageNumber, pageSize) + results, err := index.Search(ctx, source, qs, page.From, page.Size) if err != nil { if err == context.DeadlineExceeded { errorHandler(w, r, "Search timed out", http.StatusInternalServerError) @@ -126,6 +133,9 @@ func NewMux( return } + if pageSize == math.MaxInt && results.Total > config.MaxResultsShowAll { + errorHandler(w, r, "Too many results, use pagination", http.StatusBadRequest) + } tdata := components.ResultData{ TemplateData: components.TemplateData{ @@ -135,13 +145,12 @@ func NewMux( Assets: frontend.Assets, Query: qs, }, - ResultsPerPage: search.ResultsPerPage, - Query: qs, - Results: results, + Query: qs, + Results: results, } - hits := uint64(len(results.Hits)) - if results.Total > hits { + page.SetResults(results.Total) + if page.Needed { q, err := url.ParseQuery(r.URL.RawQuery) if err != nil { errorHandler(w, r, "Query string error", http.StatusBadRequest) @@ -149,26 +158,22 @@ func NewMux( return } - if page > uint64(math.Ceil(float64(results.Total)/search.ResultsPerPage)) { - errorHandler(w, r, "Not found", http.StatusNotFound) - - return - } - - if page*search.ResultsPerPage < results.Total { - q.Set("page", strconv.FormatUint(page+1, 10)) + if page.Next != 0 { + q.Set("page", strconv.Itoa(page.Next)) tdata.Next = "search?" + q.Encode() } - if page > 1 { - p := page - 1 - if p == 1 { + if page.Prev != 0 { + if page.Prev == 1 { q.Del("page") } else { - q.Set("page", strconv.FormatUint(p, 10)) + q.Set("page", strconv.Itoa(page.Prev)) } tdata.Prev = "search?" + q.Encode() } + + q.Set("page", "0") + tdata.All = "search?" + q.Encode() } w.Header().Add("Cache-Control", "max-age=300") diff --git a/nix/package.nix b/nix/package.nix index 9a9e2a6..61e3a84 100644 --- a/nix/package.nix +++ b/nix/package.nix @@ -13,7 +13,7 @@ , css }: let - version = "0.1.13"; + version = "0.1.15"; in buildGoApplication { pname = "searchix"; |