From c02c31b966336a5e91cc4f3d0951d12f26d0fd88 Mon Sep 17 00:00:00 2001 From: evazion Date: Mon, 14 Dec 2020 16:48:21 -0600 Subject: [PATCH] autocomplete: recognize Japanese tags in autocomplete. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allowing typing Japanese tags in autocomplete. For example, typing 東方 in autocomplete will be completed to the touhou tag. Typing ぶくぶ will complete to the bkub tag. This works using wiki page and artist other names. Effectively, any name listed as an other name in a wiki or artist page will be treated like an alias for autocomplete purposes. This is limited to non-ASCII other names, to prevent English other names from interfering with regular tag searches. --- app/logical/autocomplete_service.rb | 23 +++++++++++++++++++++- app/models/wiki_page.rb | 2 +- test/unit/autocomplete_service_test.rb | 27 ++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/app/logical/autocomplete_service.rb b/app/logical/autocomplete_service.rb index 833c016da..2d4f5d614 100644 --- a/app/logical/autocomplete_service.rb +++ b/app/logical/autocomplete_service.rb @@ -72,8 +72,11 @@ class AutocompleteService results = results.uniq.sort_by { |r| [r[:antecedent].length, -r[:post_count]] }.take(limit) elsif string.include?("*") results = tag_matches(string) + results = tag_other_name_matches(string) if results.blank? else - results = tag_matches(string + "*") + string += "*" + results = tag_matches(string) + results = tag_other_name_matches(string) if results.blank? results = tag_autocorrect_matches(string) if results.blank? end @@ -81,6 +84,8 @@ class AutocompleteService end def tag_matches(string) + return [] if string =~ /[^[:ascii:]]/ + name_matches = Tag.nonempty.name_matches(string).order(post_count: :desc).limit(limit) alias_matches = Tag.nonempty.alias_matches(string).order(post_count: :desc).limit(limit) union = "((#{name_matches.to_sql}) UNION (#{alias_matches.to_sql})) AS tags" @@ -100,6 +105,7 @@ class AutocompleteService end def tag_autocorrect_matches(string) + string = string.delete("*") tags = Tag.nonempty.autocorrect_matches(string).limit(limit) tags.map do |tag| @@ -107,6 +113,21 @@ class AutocompleteService end end + def tag_other_name_matches(string) + return [] unless string =~ /[^[:ascii:]]/ + + artists = Artist.undeleted.any_other_name_like(string) + wikis = WikiPage.undeleted.other_names_match(string) + tags = Tag.where(name: wikis.select(:title)).or(Tag.where(name: artists.select(:name))) + tags = tags.nonempty.order(post_count: :desc).limit(limit).includes(:wiki_page, :artist) + + tags.map do |tag| + other_names = tag.artist&.other_names.to_a + tag.wiki_page&.other_names.to_a + antecedent = other_names.find { |other_name| other_name.ilike?(string) } + { type: "tag", label: tag.pretty_name, value: tag.name, category: tag.category, post_count: tag.post_count, antecedent: antecedent } + end + end + def autocomplete_metatag(metatag, value) results = case metatag.to_sym when :user, :approver, :commenter, :comm, :noter, :noteupdater, :commentaryupdater, diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb index c9fd1a7c1..603ddcecd 100644 --- a/app/models/wiki_page.rb +++ b/app/models/wiki_page.rb @@ -45,7 +45,7 @@ class WikiPage < ApplicationRecord def other_names_match(name) if name =~ /\*/ - subquery = WikiPage.from("unnest(other_names) AS other_name").where_ilike("other_name", name) + subquery = WikiPage.from("unnest(other_names) AS other_name").where_ilike("other_name", normalize_other_name(name)) where(id: subquery) else other_names_include(name) diff --git a/test/unit/autocomplete_service_test.rb b/test/unit/autocomplete_service_test.rb index 29d8ea6ce..eaf65235b 100644 --- a/test/unit/autocomplete_service_test.rb +++ b/test/unit/autocomplete_service_test.rb @@ -97,6 +97,33 @@ class AutocompleteServiceTest < ActiveSupport::TestCase assert_autocomplete_includes("mole_under_eye", "~/mue", :tag_query) end + should "autocomplete tags from wiki and artist other names" do + create(:tag, name: "touhou") + create(:tag, name: "bkub", category: Tag.categories.artist) + create(:wiki_page, title: "touhou", other_names: %w[東方 东方 동방]) + create(:artist, name: "bkub", other_names: %w[大川ぶくぶ フミンバイン]) + + assert_autocomplete_equals(["touhou"], "東", :tag_query) + assert_autocomplete_equals(["touhou"], "东", :tag_query) + assert_autocomplete_equals(["touhou"], "동", :tag_query) + + assert_autocomplete_equals(["touhou"], "*東*", :tag_query) + assert_autocomplete_equals(["touhou"], "東*", :tag_query) + assert_autocomplete_equals([], "*東", :tag_query) + + assert_autocomplete_equals(["touhou"], "*方*", :tag_query) + assert_autocomplete_equals(["touhou"], "*方", :tag_query) + assert_autocomplete_equals([], "方", :tag_query) + + assert_autocomplete_equals(["bkub"], "*大*", :tag_query) + assert_autocomplete_equals(["bkub"], "大", :tag_query) + assert_autocomplete_equals([], "*大", :tag_query) + + assert_autocomplete_equals(["bkub"], "*川*", :tag_query) + assert_autocomplete_equals([], "*川", :tag_query) + assert_autocomplete_equals([], "川", :tag_query) + end + should "autocomplete wildcard searches" do create(:tag, name: "mole", post_count: 150) create(:tag, name: "mole_under_eye", post_count: 100)