bugfix - Search feature not finding special characters like '%'#75
Conversation
|
Here you go @sam1am; that's a simple bugfix PR. |
There was a problem hiding this comment.
Pull request overview
Fixes SQLite LIKE wildcard handling in library search and genre filters so user-supplied % and _ are treated as literals, and adds a query-length cap to reduce oversized-input risk.
Changes:
- Added
escape_like()helper to escape\,%, and_for SQLLIKEpatterns. - Updated
/library,/hidden, and/removedroutes to useESCAPE '\\'and apply escaping to both name search and genre filters. - Added tests for
escape_likeand integration tests for/librarysearch behavior and themax_length=200validation.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
web/utils/helpers.py |
Introduces escape_like() utility for safe literal matching in LIKE queries. |
web/routes/library.py |
Applies escape_like() and ESCAPE '\\' to name/genre LIKE filters and adds search max length. |
tests/test_search.py |
Adds unit + integration coverage for escaping behavior and request validation. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| def test_underscore_search_returns_only_matching_game(self, client_with_special_games): | ||
| """Searching for _ should not act as a wildcard; only exact matches are returned.""" | ||
| resp = client_with_special_games.get("/library?search=Pro_game") | ||
| assert resp.status_code == 200 | ||
| text = resp.text | ||
| assert "Pro_game" in text | ||
| # Normal Game has no underscore – should not match | ||
| assert "Normal Game" not in text | ||
|
|
There was a problem hiding this comment.
test_underscore_search_returns_only_matching_game doesn’t actually prove that _ is no longer treated as a LIKE wildcard: the pattern %Pro_game% wouldn’t match Normal Game even in the buggy (unescaped) implementation. Add a counterexample row (e.g. ProXgame) that would match if _ were a wildcard, or add a test that searches for _ alone and asserts only names containing a literal underscore are returned.
|
Looks good, thanks! Merging. |
Fixes issue #74: escape SQL LIKE special characters in search queries
Problem
Searching for
%or_in the library search box produced wrong results:%→ matched all games (SQLLIKEinterprets%as "any sequence of characters")_→ matched any single character instead of a literal underscoreAdditionally, the
genresfilter had the same issue, and thesearchparameter had no length limit, leaving a potential DoS vector.Changes
web/utils/helpers.pyescape_like(value: str) -> strutility function that escapes\,%, and_before injecting a value into aLIKEpattern.web/routes/library.pyescape_like()+ESCAPE '\\'on all threename LIKE ?queries:/library,/hidden,/removed.escape_like()+ESCAPE '\\'on thegenresLIKEfilter as well.max_length=200viaQuery(...)on thesearchparameter in all three routes to prevent oversized inputs.tests/test_search.py(new file)escape_likecovering%,_,\, and combinations./libraryverifying that%only matches games whose name contains a literal%, that_is not treated as a wildcard, and that searches longer than 200 characters return HTTP 422.Notes
?). The only values interpolated directly into SQL (sort,order,playtime_label) are validated against whitelists before use.