Current section

Files

Jump to
oban_web lib oban web search.ex
Raw

lib/oban/web/search.ex

defmodule Oban.Web.Search do
@moduledoc false
# Helpers for the search toolbar
@ignored_chars ~w(; / \ ` ' = * ! ? # $ & + ^ | ~ < > ( \) { } [ ])
# Suggestion tuning
@suggest_limit 10
@suggest_threshold 0.5
@doc """
Parse a string of qualifiers and values into structured search terms.
"""
def parse(terms, parser) when is_binary(terms) and is_function(parser, 1) do
terms
|> String.split(~r/\s+(?=([^\"]*\"[^\"]*\")*[^\"]*$)/, trim: true)
|> Map.new(fn term ->
term
|> String.replace(@ignored_chars, "")
|> parser.()
end)
end
@doc """
Append to the terms string without any duplication.
"""
def append(terms, choice, known)
when is_binary(terms) and is_binary(choice) and is_struct(known, MapSet) do
choice = if String.match?(choice, ~r/[\s,]/), do: ~s("#{choice}"), else: choice
cond do
MapSet.member?(known, choice) ->
choice
String.contains?(terms, ":") ->
[qualifier, _] = String.split(terms, ":", parts: 2)
"#{qualifier}:#{choice}"
true ->
terms
|> String.reverse()
|> String.split(["."], parts: 2)
|> List.last()
|> String.reverse()
|> Kernel.<>(".#{choice}")
end
end
@doc """
Restrict suggestions by similarity to a given fragment.
"""
def restrict_suggestions(suggestions, "") do
suggestions
|> Enum.sort()
|> Enum.take(@suggest_limit)
|> Enum.map(&{&1, "", ""})
end
def restrict_suggestions(suggestions, frag) do
suggestions
|> Enum.filter(&(similarity(&1, frag) >= @suggest_threshold))
|> Enum.sort_by(&{1.0 - similarity(&1, frag), &1}, :asc)
|> Enum.take(@suggest_limit)
|> Enum.map(&{&1, "", ""})
end
defp similarity(value, guess, boost \\ 0.5) do
value = String.downcase(value)
guess = String.downcase(guess)
distance = String.jaro_distance(value, guess)
if String.contains?(value, guess) do
min(distance + boost, 1.0)
else
distance
end
end
end