diff --git a/backend/app/services/post_tag_search.rb b/backend/app/services/post_tag_search.rb index 461400d..1e4b9dd 100644 --- a/backend/app/services/post_tag_search.rb +++ b/backend/app/services/post_tag_search.rb @@ -3,8 +3,8 @@ class PostTagSearch def self.literals(locale, raw) tokens = raw.split.reject { _1.downcase == 'type:or' } names = tokens.map { _1.sub(/\Anot:/i, '') } - registered = TagName.where(language_code: locale.language_code, name: names) - .pluck(:name, :tag_id).to_h + registered = matching_names(TagName.where(language_code: locale.language_code), + names, 'tag_names.name', :tag_id).to_h primary = TagName.where(language_code: locale.language_code, tag_id: registered.values, primary_flg: true).pluck(:tag_id, :name).to_h tokens.zip(names).map do |token, name| @@ -19,12 +19,25 @@ class PostTagSearch def self.references_for(locale, literals) names = literals.map { _1[:name] }.uniq - internal = TagName.where(language_code: locale.language_code, name: names) - .pluck(:name, :tag_id).group_by(&:first) - external = names.empty? ? {} : ExternalTag.where( - "CONCAT(platform, ':', name) IN (?)", names) - .pluck(Arel.sql("CONCAT(platform, ':', name)"), :id).group_by(&:first) + internal = matching_names(TagName.where(language_code: locale.language_code), + names, 'tag_names.name', :tag_id).group_by(&:first) + external = matching_names(ExternalTag.all, names, + "CONCAT(external_tags.platform, ':', external_tags.name)", :id).group_by(&:first) names.to_h { |name| [name, [internal.fetch(name, []).map(&:last).uniq, external.fetch(name, []).map(&:last).uniq]] } end + + def self.matching_names(scope, names, expression, identifier) + return [] if names.empty? + + queries = names.uniq.map do |name| + scope.klass.sanitize_sql_array(['SELECT ? AS name', name]) + end + # Return the input spelling so Ruby does not recheck database equivalence. + scope.joins(<<~SQL).pluck(Arel.sql('search_names.name'), identifier) + INNER JOIN (#{ queries.join(' UNION ALL ') }) AS search_names + ON #{ expression } = search_names.name COLLATE utf8mb4_0900_ai_ci + SQL + end + private_class_method :matching_names end