fix: implement proper 3-state boolean handling in backend

Updated the backend services and handlers to properly detect and pass
the has_cover parameter's validity state to the database layer.

Changes:
- services/search.go: Changed HasCover type from bool to pgtype.Bool
  to support 3-state logic (NULL, TRUE, FALSE)
- handlers/media.go: Fixed 3-state detection by checking if has_cover
  exists in query params before setting Valid flag
- router/search.go: Fixed 3-state detection to match media.go logic
- router/frontend.go: Use pgtype.Bool{Valid: false} for SSR initial
  load to ensure no filtering occurs on first page load

The key fix is detecting whether the has_cover parameter was actually
sent in the request:
- Parameter not sent → pgtype.Bool{Bool: false, Valid: false}
- Parameter sent as "true" → pgtype.Bool{Bool: true, Valid: true}
- Parameter sent as "false" → pgtype.Bool{Bool: false, Valid: true}

Previously, media.go was hardcoding Valid: true, which meant it was
always filtering by has_cover=false (only books without covers) when
the parameter wasn't sent, causing searches to incorrectly return
0 results for queries like "1984".

This ensures consistency between the JSON API endpoint (media.go) and
the HTML endpoint (search.go), and fixes the critical bug where SSR
was returning 0 books on initial page load.
This commit is contained in:
2026-03-27 18:07:51 -04:00
parent 36ae781765
commit ba243c223d
4 changed files with 17 additions and 7 deletions
+7 -2
View File
@@ -1424,7 +1424,12 @@ func (mh *MediaHandler) SearchMediaItems(c *echo.Context) error {
languageFilter := c.QueryParam("language_filter")
yearMin, _ := strconv.Atoi(c.QueryParam("year_min"))
yearMax, _ := strconv.Atoi(c.QueryParam("year_max"))
hasCover := c.QueryParam("has_cover") == "true"
hasCover := false
hasCoverValid := false
if _, exists := c.QueryParams()["has_cover"]; exists {
hasCover = c.QueryParam("has_cover") == "true"
hasCoverValid = true
}
// Extract sort parameter
sortParam := c.QueryParam("sort")
@@ -1444,7 +1449,7 @@ func (mh *MediaHandler) SearchMediaItems(c *echo.Context) error {
LanguageFilter: languageFilter,
YearMin: yearMin,
YearMax: yearMax,
HasCover: hasCover,
HasCover: pgtype.Bool{Bool: hasCover, Valid: hasCoverValid},
Sort: sortParam,
Limit: limit,
Offset: offset,