diff --git a/lib/topics_filter.rb b/lib/topics_filter.rb index 9cad48ea254..f7e29ce64f9 100644 --- a/lib/topics_filter.rb +++ b/lib/topics_filter.rb @@ -309,6 +309,7 @@ class TopicsFilter .filter_visible(Tag, @guardian) .where_name(tag_names) .pluck(:id, :target_tag_id) + .transpose tag_ids ||= [] alias_tag_ids ||= [] @@ -417,7 +418,7 @@ class TopicsFilter def include_topics_with_all_tags(tag_ids) tag_ids.each do |tag_id| - sql_alias = "tt#{topic_tags_alias}" + sql_alias = topic_tags_alias @scope = @scope.joins( @@ -427,7 +428,13 @@ class TopicsFilter end def include_topics_with_any_tags(tag_ids) - @scope = @scope.joins(:topic_tags).where("topic_tags.tag_id IN (?)", tag_ids).distinct(:id) + sql_alias = topic_tags_alias + + @scope = + @scope + .joins("INNER JOIN topic_tags #{sql_alias} ON #{sql_alias}.topic_id = topics.id") + .where("#{sql_alias}.tag_id IN (?)", tag_ids) + .distinct(:id) end ORDER_BY_MAPPINGS = { diff --git a/spec/lib/topics_filter_spec.rb b/spec/lib/topics_filter_spec.rb index 9d16c7df132..66ddba7c4b9 100644 --- a/spec/lib/topics_filter_spec.rb +++ b/spec/lib/topics_filter_spec.rb @@ -694,6 +694,37 @@ RSpec.describe TopicsFilter do ).to contain_exactly(topic_with_tag_and_tag2.id, topic_with_tag_and_tag2_and_tag3.id) end + describe "when query string is `tags:tag1,tag2,tag3`" do + it "should only return topics that are tagged with either tag1, tag2 or tag3" do + topic_with_tag3 = Fabricate(:topic, tags: [tag3]) + + expect( + TopicsFilter + .new(guardian: Guardian.new) + .filter_from_query_string("tags:#{tag.name},#{tag2.name},#{tag3.name}") + .pluck(:id), + ).to contain_exactly( + topic_with_tag.id, + topic_with_tag_and_tag2.id, + topic_with_tag2.id, + topic_with_tag3.id, + ) + end + end + + describe "when query string is `tags:tag1+tag2+tag3`" do + it "should only return topics that are tagged with tag1, tag2 and tag3" do + topic_with_tag_tag2_tag3 = Fabricate(:topic, tags: [tag, tag2, tag3]) + + expect( + TopicsFilter + .new(guardian: Guardian.new) + .filter_from_query_string("tags:#{tag.name}+#{tag2.name}+#{tag3.name}") + .pluck(:id), + ).to contain_exactly(topic_with_tag_tag2_tag3.id) + end + end + it "should only return topics that are tagged with tag1 and tag2 but not tag3 when query string is `tags:tag1 tags:tag2 -tags:tag3`" do topic_with_tag_and_tag2_and_tag3 = Fabricate(:topic, tags: [tag, tag2, tag3])