Fix bug with special chars in search form
This commit is contained in:
parent
b167ada1c4
commit
2c17482924
4 changed files with 42 additions and 8 deletions
|
|
@ -128,9 +128,11 @@ defmodule Pinchflat.Media.MediaQuery do
|
|||
def matches_search_term(nil), do: dynamic([mi], true)
|
||||
|
||||
def matches_search_term(term) do
|
||||
case String.trim(term) do
|
||||
escaped_term = clean_search_term(term)
|
||||
|
||||
case String.trim(escaped_term) do
|
||||
"" -> dynamic([mi], true)
|
||||
term -> dynamic([mi], fragment("media_items_search_index MATCH ?", ^term))
|
||||
_ -> dynamic([mi], fragment("media_items_search_index MATCH ?", ^escaped_term))
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -161,9 +163,11 @@ defmodule Pinchflat.Media.MediaQuery do
|
|||
def matching_search_term(query, nil), do: query
|
||||
|
||||
def matching_search_term(query, term) do
|
||||
escaped_term = clean_search_term(term)
|
||||
|
||||
from(mi in query,
|
||||
join: mi_search_index in assoc(mi, :media_items_search_index),
|
||||
where: fragment("media_items_search_index MATCH ?", ^term),
|
||||
where: fragment("media_items_search_index MATCH ?", ^escaped_term),
|
||||
select_merge: %{
|
||||
matching_search_term:
|
||||
fragment("""
|
||||
|
|
@ -175,4 +179,23 @@ defmodule Pinchflat.Media.MediaQuery do
|
|||
order_by: [desc: fragment("rank")]
|
||||
)
|
||||
end
|
||||
|
||||
# SQLite's FTS5 is very picky about what it will accept as a search term.
|
||||
# To that end, we need to clean up the search term before passing it to the
|
||||
# MATCH clause.
|
||||
# This method:
|
||||
# - Trims leading and trailing whitespace
|
||||
# - Collapses multiple spaces into a single space
|
||||
# - Removes quote characters
|
||||
# - Wraps any word in quotes (must happen after the double quote replacement)
|
||||
#
|
||||
# This allows for works with apostrophes and quotes to be searched for correctly
|
||||
defp clean_search_term(term) do
|
||||
term
|
||||
|> String.trim()
|
||||
|> String.replace(~r/\s+/, " ")
|
||||
|> String.split(~r/\s+/)
|
||||
|> Enum.map(fn str -> String.replace(str, ~s("), "") end)
|
||||
|> Enum.map_join(" ", fn str -> ~s("#{str}") end)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ defmodule Pinchflat.Sources.MediaItemTableLive do
|
|||
media_state = session["media_state"]
|
||||
source = Sources.get_source!(session["source_id"])
|
||||
base_query = generate_base_query(source, media_state)
|
||||
pagination_attrs = fetch_pagination_attributes(base_query, page, "friendly")
|
||||
pagination_attrs = fetch_pagination_attributes(base_query, page, nil)
|
||||
|
||||
new_assigns =
|
||||
Map.merge(
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ defmodule Pinchflat.Repo.Migrations.ChangeMediaItemsSearchIndexTokenizer do
|
|||
|
||||
def up do
|
||||
# These all need to run as part of separate `execute` blocks. Do NOT ask me why.
|
||||
execute "DROP TRIGGER media_items_search_index_insert;"
|
||||
execute "DROP TRIGGER media_items_search_index_update;"
|
||||
execute "DROP TRIGGER media_items_search_index_delete;"
|
||||
execute "DROP TABLE media_items_search_index;"
|
||||
execute "DROP TRIGGER IF EXISTS media_items_search_index_insert;"
|
||||
execute "DROP TRIGGER IF EXISTS media_items_search_index_update;"
|
||||
execute "DROP TRIGGER IF EXISTS media_items_search_index_delete;"
|
||||
execute "DROP TABLE IF EXISTS media_items_search_index;"
|
||||
|
||||
execute """
|
||||
CREATE VIRTUAL TABLE media_items_search_index USING fts5(
|
||||
|
|
|
|||
|
|
@ -727,6 +727,17 @@ defmodule Pinchflat.MediaTest do
|
|||
test "returns an empty list when the search term is nil" do
|
||||
assert [] = Media.search(nil)
|
||||
end
|
||||
|
||||
test "doesn't blow up if there's an apostrophe or quotes in the search term" do
|
||||
assert [] = Media.search("don't expl'ode")
|
||||
assert [] = Media.search(~s(dont expl"o"de))
|
||||
assert [] = Media.search(~s(dont explo"de))
|
||||
end
|
||||
|
||||
test "doesn't blow up if there is a trailing operand" do
|
||||
assert [] = Media.search("foo OR")
|
||||
assert [] = Media.search("foo AND")
|
||||
end
|
||||
end
|
||||
|
||||
describe "get_media_item!/1" do
|
||||
|
|
|
|||
Loading…
Reference in a new issue