From 7c6a8f1c74ea7ea3e81d9ffa80ca2227ee36a006 Mon Sep 17 00:00:00 2001 From: Alan Guo Xiang Tan Date: Fri, 24 Mar 2023 11:17:55 +0800 Subject: [PATCH] DEV: Refactor `TopicQuery#default_results` to improve readability (#20800) This commit breaks down the code in TopicQuery#default_results into smaller private methods to improve readability. --- lib/topic_query.rb | 112 +++++++++++++++++++++------------------------ 1 file changed, 53 insertions(+), 59 deletions(-) diff --git a/lib/topic_query.rb b/lib/topic_query.rb index ed1be76886a..2e8c0b35982 100644 --- a/lib/topic_query.rb +++ b/lib/topic_query.rb @@ -715,65 +715,7 @@ class TopicQuery end end - if SiteSetting.tagging_enabled - result = result.preload(:tags) - - tags_arg = @options[:tags] - - if tags_arg && tags_arg.size > 0 - tags_arg = tags_arg.split if String === tags_arg - - tags_arg = - tags_arg.map do |t| - if String === t - t.downcase - else - t - end - end - - tags_query = tags_arg[0].is_a?(String) ? Tag.where_name(tags_arg) : Tag.where(id: tags_arg) - tags = tags_query.select(:id, :target_tag_id).map { |t| t.target_tag_id || t.id }.uniq - - if ActiveModel::Type::Boolean.new.cast(@options[:match_all_tags]) - # ALL of the given tags: - if tags_arg.length == tags.length - tags.each_with_index do |tag, index| - sql_alias = ["t", index].join - result = - result.joins( - "INNER JOIN topic_tags #{sql_alias} ON #{sql_alias}.topic_id = topics.id AND #{sql_alias}.tag_id = #{tag}", - ) - end - else - result = result.none # don't return any results unless all tags exist in the database - end - else - # ANY of the given tags: - result = result.joins(:tags).where("tags.id in (?)", tags) - end - - # TODO: this is very side-effecty and should be changed - # It is done cause further up we expect normalized tags - @options[:tags] = tags - elsif @options[:no_tags] - # the following will do: ("topics"."id" NOT IN (SELECT DISTINCT "topic_tags"."topic_id" FROM "topic_tags")) - result = result.where.not(id: TopicTag.distinct.pluck(:topic_id)) - end - - if @options[:exclude_tag].present? && - !DiscourseTagging.hidden_tag_names(@guardian).include?(@options[:exclude_tag]) - result = result.where(<<~SQL, name: @options[:exclude_tag]) - topics.id NOT IN ( - SELECT topic_tags.topic_id - FROM topic_tags - INNER JOIN tags ON tags.id = topic_tags.tag_id - WHERE tags.name = :name - ) - SQL - end - end - + result = filter_by_tags(result) result = apply_ordering(result, options) all_listable_topics = @@ -1202,4 +1144,56 @@ class TopicQuery end results end + + def filter_by_tags(result) + return result if !SiteSetting.tagging_enabled + + tags_arg = @options[:tags] + + if tags_arg && tags_arg.size > 0 + tags_arg = tags_arg.split if String === tags_arg + tags_query = tags_arg[0].is_a?(String) ? Tag.where_name(tags_arg) : Tag.where(id: tags_arg) + tags = tags_query.select(:id, :target_tag_id).map { |t| t.target_tag_id || t.id }.uniq + + if ActiveModel::Type::Boolean.new.cast(@options[:match_all_tags]) + # ALL of the given tags: + if tags_arg.length == tags.length + tags.each_with_index do |tag, index| + sql_alias = ["t", index].join + + result = + result.joins( + "INNER JOIN topic_tags #{sql_alias} ON #{sql_alias}.topic_id = topics.id AND #{sql_alias}.tag_id = #{tag}", + ) + end + else + result = result.none # don't return any results unless all tags exist in the database + end + else + # ANY of the given tags: + result = result.joins(:tags).where("tags.id in (?)", tags) + end + + # TODO: this is very side-effecty and should be changed + # It is done cause further up we expect normalized tags + @options[:tags] = tags + elsif @options[:no_tags] + # the following will do: ("topics"."id" NOT IN (SELECT DISTINCT "topic_tags"."topic_id" FROM "topic_tags")) + result = result.where.not(id: TopicTag.distinct.select(:topic_id)) + end + + if @options[:exclude_tag].present? && + !DiscourseTagging.hidden_tag_names(@guardian).include?(@options[:exclude_tag]) + result = result.where(<<~SQL, name: @options[:exclude_tag]) + topics.id NOT IN ( + SELECT topic_tags.topic_id + FROM topic_tags + INNER JOIN tags ON tags.id = topic_tags.tag_id + WHERE tags.name = :name + ) + SQL + end + + result + end end