/artists: drop deprecated search syntax, add regex search for names.

Drop support for the following pseudo-metatags in the Name field in the
artists search form:

* name:<name>
* other:<other name>
* group:<group name>
* status:banned
* status:active
* http://www.example.com

Instead, make the Name field do a wildcard search against the artist
name, group name, or other names. If the query looks like `/regex/`,
then do a regex search against any of these names.

/artists?search[name] now does a literal exact match and
/artists?search{any_name_matches] does the above wildcard/regex search.
This commit is contained in:
evazion
2018-09-21 18:34:39 -05:00
parent 237ab9b782
commit f917b83d6f
4 changed files with 10 additions and 39 deletions

View File

@@ -182,7 +182,7 @@ Autocomplete.initialize_artist_autocomplete = function($fields) {
$.ajax({
url: "/artists.json",
data: {
"search[name]": req.term + "*",
"search[name_like]": req.term.trim().replace(/\s+/g, "_") + "*",
"search[is_active]": true,
"search[order]": "post_count",
"limit": 10,

View File

@@ -477,42 +477,20 @@ class Artist < ApplicationRecord
where(name: normalize_name(name))
end
def any_name_matches(name)
stripped_name = normalize_name(name).to_escaped_for_sql_like
if name =~ /\*/ && CurrentUser.is_builder?
where("(artists.name LIKE ? ESCAPE E'\\\\' OR artists.other_names LIKE ? ESCAPE E'\\\\')", stripped_name, stripped_name)
def any_name_matches(query)
if query =~ %r!\A/(.*)/\z!
where_regex(:name, $1).or(where_regex(:other_names, $1)).or(where_regex(:group_name, $1))
else
name_for_tsquery = normalize_name(name).to_escaped_for_tsquery
where("(artists.name LIKE ? ESCAPE E'\\\\' OR artists.other_names_index @@ to_tsquery('danbooru', E?))", stripped_name, name_for_tsquery)
normalized_name = normalize_name(query)
normalized_name = "*#{normalized_name}*" unless normalized_name.include?("*")
where_like(:name, normalized_name).or(where_like(:other_names, normalized_name)).or(where_like(:group_name, normalized_name))
end
end
def search(params)
q = super
case params[:name]
when /^http/
q = q.url_matches(params[:name])
when /name:(.+)/
q = q.name_matches($1)
when /other:(.+)/
q = q.other_names_match($1)
when /group:(.+)/
q = q.group_name_matches($1)
when /status:banned/
q = q.banned
when /status:active/
q = q.unbanned.active
when /./
q = q.any_name_matches(params[:name])
end
if params[:name_matches].present?
q = q.name_matches(params[:name_matches])
end
@@ -544,11 +522,6 @@ class Artist < ApplicationRecord
q = q.where("artists.creator_id = ?", params[:creator_id].to_i)
end
# XXX deprecated, remove at some point.
if params[:empty_only].to_s.truthy?
params[:has_tag] = "false"
end
if params[:has_tag].to_s.truthy?
q = q.joins(:tag).where("tags.post_count > 0")
elsif params[:has_tag].to_s.falsy?

View File

@@ -1,5 +1,5 @@
<%= simple_form_for(:search, url: artists_path, method: :get, defaults: { required: false }, html: { class: "inline-form" }) do |f| %>
<%= f.input :name, label: "Name", hint: "Use * for wildcard", input_html: { value: params[:search][:name], data: { autocomplete: "artist" }} %>
<%= f.input :any_name_matches, label: "Name", hint: "Use * for wildcard", input_html: { value: params[:search][:any_name_matches], data: { autocomplete: "artist" }} %>
<%= f.input :url_matches, label: "URL", as: "string", input_html: { value: params[:search][:url_matches] } %>
<%= f.input :creator_name, label: "Creator", input_html: { value: params[:search][:creator_name] } %>
<%= f.input :is_active, label: "Active?", collection: [["Yes", true], ["No", false]], include_blank: true, selected: params[:search][:is_active] %>

View File

@@ -409,8 +409,7 @@ class ArtistTest < ActiveSupport::TestCase
assert_nil(Artist.other_names_match("artist").first)
assert_not_nil(Artist.other_names_match("aaa").first)
assert_not_nil(Artist.other_names_match("ccc_ddd").first)
assert_not_nil(Artist.search(:name => "other:aaa").first)
assert_not_nil(Artist.search(:name => "aaa").first)
assert_not_nil(Artist.search(:name => "artist").first)
assert_not_nil(Artist.search(:other_names_match => "aaa").first)
assert_not_nil(Artist.search(:any_name_matches => "aaa").first)
@@ -421,7 +420,6 @@ class ArtistTest < ActiveSupport::TestCase
yuu = FactoryBot.create(:artist, :name => "yuu", :group_name => "cat_or_fish")
cat_or_fish.reload
assert_equal("yuu", cat_or_fish.member_names)
assert_not_nil(Artist.search(:name => "group:cat_or_fish").first)
assert_not_nil(Artist.search(:group_name_matches => "cat_or_fish").first)
assert_not_nil(Artist.search(:any_name_matches => "cat_or_fish").first)